1
0
Эх сурвалжийг харах

refactor: Migrate interfaces.js to new registration mechanism (#1239)

* refactor: migrate interfaces.js to new registration mechanism

- Created EntityStoreInterfaceService for crud-q interface\n- Created AnalyticsInterfaceService for puter-analytics interface\n- Added InterfacesModule to load these services\n- Removed interfaces.js\n\nCloses #1131

ai: true

* chore: remove interfaces.js file

ai: true

* fix: DRY CRUD interfaces

This comment is flagged as AI-generated, but Claude rate-limited before
it could actually make the commit so this commit was made by hand. Well,
while I'm writing this commit message I may as well mention that Claud's
rate limits are relentless and it has become impossible to use Claude
for some purposes as a result.

ai: true

* refactor: replace interfaces module with separate Module.js files for entitystore and analytics

- Removed interfaces module\n- Added EntityStoreModule.js to entitystore module\n- Added AnalyticsModule.js to analytics module\n- Updated main index.js to use the new modules directly\n\nai: true

ai: true

* fix: modules exported and registered incorrectly

* feat: add KVStoreModule for puter-kvstore interface

- Created KVStoreModule.js\n- Created KVStoreInterfaceService.js to register the puter-kvstore interface\n- Updated exports.js to include the new module\n\nai: true

* fix: remove index.js from kvstore module

- Removed unnecessary index.js file from kvstore module\n\nai: true

* fix: remove index.js files from analytics and entitystore modules

- Removed unnecessary index.js files from analytics and entitystore modules\n\nai: true

* fix: cleanup mycoder mistakes again

...because it actually threw out my previous commit where I already did
this.
Eric Dubé 1 сар өмнө
parent
commit
b7defab2d2

+ 7 - 0
src/backend/exports.js

@@ -40,6 +40,9 @@ const { PuterExecModule } = require("./src/modules/puterexec/PuterExecModule.js"
 const { MailModule } = require("./src/modules/mail/MailModule.js");
 const { ConvertModule } = require("./src/modules/convert/ConvertModule.js");
 const { CaptchaModule } = require("./src/modules/captcha/CaptchaModule.js");
+const { EntityStoreModule } = require("./src/modules/entitystore/EntityStoreModule.js");
+const { AnalyticsModule } = require("./src/modules/analytics/AnalyticsModule.js");
+const { KVStoreModule } = require("./src/modules/kvstore/KVStoreModule.js");
 
 module.exports = {
     helloworld: () => {
@@ -63,6 +66,9 @@ module.exports = {
         TemplateModule,
         AppsModule,
         CaptchaModule,
+        EntityStoreModule,
+        AnalyticsModule,
+        KVStoreModule,
     ],
 
     // Pre-built modules
@@ -79,6 +85,7 @@ module.exports = {
     MailModule,
     ConvertModule,
     CaptchaModule,
+    KVStoreModule,
     
     // Development modules
     PerfMonModule,

+ 64 - 0
src/backend/src/modules/analytics/AnalyticsInterfaceService.js

@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2025-present Puter Technologies Inc.
+ * 
+ * This file is part of Puter.
+ * 
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+const BaseService = require("../../services/BaseService");
+
+/**
+* Service class that manages Analytics interface registrations.
+* Handles registration of the puter-analytics interface.
+* @extends BaseService
+*/
+class AnalyticsInterfaceService extends BaseService {
+    /**
+    * Service class for managing Analytics interface registrations.
+    * Extends the base service to provide analytics interface management.
+    */
+    async ['__on_driver.register.interfaces'] () {
+        const svc_registry = this.services.get('registry');
+        const col_interfaces = svc_registry.get('interfaces');
+        
+        // Register the puter-analytics interface
+        col_interfaces.set('puter-analytics', {
+            no_sdk: true,
+            description: 'Analytics.',
+            methods: {
+                create_trace: {
+                    description: 'Get a trace UID.',
+                    parameters: {
+                        trace_id: { type: 'string', optional: true },
+                    },
+                    result: { type: 'string' }
+                },
+                record: {
+                    description: 'Record an event.',
+                    parameters: {
+                        trace_id: { type: 'string', optional: true },
+                        tags: { type: 'json' },
+                        fields: { type: 'json' },
+                    },
+                    result: { type: 'void' }
+                }
+            }
+        });
+    }
+}
+
+module.exports = {
+    AnalyticsInterfaceService
+};

+ 37 - 0
src/backend/src/modules/analytics/AnalyticsModule.js

@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2025-present Puter Technologies Inc.
+ * 
+ * This file is part of Puter.
+ * 
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+const { AdvancedBase } = require("@heyputer/putility");
+const { AnalyticsInterfaceService } = require("./AnalyticsInterfaceService");
+
+/**
+ * A module for registering analytics interfaces.
+ */
+class AnalyticsModule extends AdvancedBase {
+    async install(context) {
+        const services = context.get('services');
+        
+        // Register interface services
+        services.registerService('analytics-interface', AnalyticsInterfaceService);
+    }
+}
+
+module.exports = {
+    AnalyticsModule,
+};

+ 128 - 0
src/backend/src/modules/entitystore/EntityStoreInterfaceService.js

@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2025-present Puter Technologies Inc.
+ * 
+ * This file is part of Puter.
+ * 
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+// METADATA // {"ai-commented":{"service":"claude"}}
+const BaseService = require("../../services/BaseService");
+
+/**
+* Service class that manages Entity Store interface registrations.
+* Handles registration of the crud-q interface which is used by various
+* entity storage services.
+* @extends BaseService
+*/
+class EntityStoreInterfaceService extends BaseService {
+    /**
+    * Service class for managing Entity Store interface registrations.
+    * Extends the base service to provide entity storage interface management.
+    */
+    async ['__on_driver.register.interfaces'] () {
+        const svc_registry = this.services.get('registry');
+        const col_interfaces = svc_registry.get('interfaces');
+        
+        // Define the standard CRUD interface methods that will be reused
+        const crudMethods = {
+            create: {
+                parameters: {
+                    object: {
+                        type: 'json',
+                        subtype: 'object',
+                        required: true,
+                    },
+                    options: { type: 'json' },
+                }
+            },
+            read: {
+                parameters: {
+                    uid: { type: 'string' },
+                    id: { type: 'json' },
+                    params: { type: 'json' },
+                }
+            },
+            select: {
+                parameters: {
+                    predicate: { type: 'json' },
+                    offset: { type: 'number' },
+                    limit: { type: 'number' },
+                    params: { type: 'json' },
+                }
+            },
+            update: {
+                parameters: {
+                    id: { type: 'json' },
+                    object: {
+                        type: 'json',
+                        subtype: 'object',
+                        required: true,
+                    },
+                    options: { type: 'json' },
+                }
+            },
+            upsert: {
+                parameters: {
+                    id: { type: 'json' },
+                    object: {
+                        type: 'json',
+                        subtype: 'object',
+                        required: true,
+                    },
+                    options: { type: 'json' },
+                }
+            },
+            delete: {
+                parameters: {
+                    uid: { type: 'string' },
+                    id: { type: 'json' },
+                }
+            },
+        };
+        
+        // Register the crud-q interface
+        col_interfaces.set('crud-q', {
+            methods: { ...crudMethods }
+        });
+
+        // Register entity-specific interfaces that use crud-q
+        const entityInterfaces = [
+            {
+                name: 'puter-apps',
+                description: 'Manage a developer\'s apps on Puter.'
+            },
+            {
+                name: 'puter-subdomains',
+                description: 'Manage subdomains on Puter.'
+            },
+            {
+                name: 'puter-notifications',
+                description: 'Read notifications on Puter.'
+            }
+        ];
+
+        // Register each entity interface with the same CRUD methods
+        for (const entity of entityInterfaces) {
+            col_interfaces.set(entity.name, {
+                description: entity.description,
+                methods: { ...crudMethods }
+            });
+        }
+    }
+}
+
+module.exports = {
+    EntityStoreInterfaceService
+};

+ 37 - 0
src/backend/src/modules/entitystore/EntityStoreModule.js

@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2025-present Puter Technologies Inc.
+ * 
+ * This file is part of Puter.
+ * 
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+const { AdvancedBase } = require("@heyputer/putility");
+const { EntityStoreInterfaceService } = require("./EntityStoreInterfaceService");
+
+/**
+ * A module for registering entity store interfaces.
+ */
+class EntityStoreModule extends AdvancedBase {
+    async install(context) {
+        const services = context.get('services');
+        
+        // Register interface services
+        services.registerService('entitystore-interface', EntityStoreInterfaceService);
+    }
+}
+
+module.exports = {
+    EntityStoreModule,
+};

+ 105 - 0
src/backend/src/modules/kvstore/KVStoreInterfaceService.js

@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2025-present Puter Technologies Inc.
+ * 
+ * This file is part of Puter.
+ * 
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+const BaseService = require("../../services/BaseService");
+
+/**
+* Service class that manages KVStore interface registrations.
+* Handles registration of the puter-kvstore interface.
+* @extends BaseService
+*/
+class KVStoreInterfaceService extends BaseService {
+    /**
+    * Service class for managing KVStore interface registrations.
+    * Extends the base service to provide key-value store interface management.
+    */
+    async ['__on_driver.register.interfaces'] () {
+        const svc_registry = this.services.get('registry');
+        const col_interfaces = svc_registry.get('interfaces');
+        
+        // Register the puter-kvstore interface
+        col_interfaces.set('puter-kvstore', {
+            description: 'A simple key-value store.',
+            methods: {
+                get: {
+                    description: 'Get a value by key.',
+                    parameters: {
+                        key: { type: 'json', required: true },
+                        app_uid: { type: 'string', optional: true },
+                    },
+                    result: { type: 'json' },
+                },
+                set: {
+                    description: 'Set a value by key.',
+                    parameters: {
+                        key: { type: 'string', required: true, },
+                        value: { type: 'json' },
+                        app_uid: { type: 'string', optional: true },
+                    },
+                    result: { type: 'void' },
+                },
+                del: {
+                    description: 'Delete a value by key.',
+                    parameters: {
+                        key: { type: 'string' },
+                        app_uid: { type: 'string', optional: true },
+                    },
+                    result: { type: 'void' },
+                },
+                list: {
+                    description: 'List all key-value pairs.',
+                    parameters: {
+                        as: {
+                            type: 'string',
+                        },
+                        app_uid: { type: 'string', optional: true },
+                    },
+                    result: { type: 'array' },
+                },
+                flush: {
+                    description: 'Delete all key-value pairs.',
+                    parameters: {},
+                    result: { type: 'void' },
+                },
+                incr: {
+                    description: 'Increment a value by key.',
+                    parameters: {
+                        key: { type: 'string', required: true, },
+                        amount: { type: 'number' },
+                        app_uid: { type: 'string', optional: true },
+                    },
+                    result: { type: 'number' },
+                },
+                decr: {
+                    description: 'Increment a value by key.',
+                    parameters: {
+                        key: { type: 'string', required: true, },
+                        amount: { type: 'number' },
+                        app_uid: { type: 'string', optional: true },
+                    },
+                    result: { type: 'number' },
+                },
+            }
+        });
+    }
+}
+
+module.exports = {
+    KVStoreInterfaceService
+};

+ 37 - 0
src/backend/src/modules/kvstore/KVStoreModule.js

@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2025-present Puter Technologies Inc.
+ * 
+ * This file is part of Puter.
+ * 
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+const { AdvancedBase } = require("@heyputer/putility");
+const { KVStoreInterfaceService } = require("./KVStoreInterfaceService");
+
+/**
+ * A module for registering key-value store interfaces.
+ */
+class KVStoreModule extends AdvancedBase {
+    async install(context) {
+        const services = context.get('services');
+        
+        // Register interface services
+        services.registerService('kvstore-interface', KVStoreInterfaceService);
+    }
+}
+
+module.exports = {
+    KVStoreModule,
+};

+ 0 - 6
src/backend/src/services/drivers/DriverService.js

@@ -111,12 +111,6 @@ class DriverService extends BaseService {
         const col_interfaces = svc_registry.get('interfaces');
         const col_drivers = svc_registry.get('drivers');
         const col_types = svc_registry.get('types');
-        {
-            const default_interfaces = require('./interfaces');
-            for ( const k in default_interfaces ) {
-                col_interfaces.set(k, default_interfaces[k]);
-            }
-        }
         {
             const types = this.modules.types;
             for ( const k in types ) {

+ 0 - 299
src/backend/src/services/drivers/interfaces.js

@@ -1,299 +0,0 @@
-// METADATA // {"ai-commented":{"service":"xai"}}
-/*
- * Copyright (C) 2024-present Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-const ENTITY_STORAGE_INTERFACE = {
-    methods: {
-        create: {
-            parameters: {
-                object: {
-                    type: 'json',
-                    subtype: 'object',
-                    required: true,
-                },
-                options: { type: 'json' },
-            }
-        },
-        read: {
-            parameters: {
-                uid: { type: 'string' },
-                id: { type: 'json' },
-                params: { type: 'json' },
-            }
-        },
-        select: {
-            parameters: {
-                predicate: { type: 'json' },
-                offset: { type: 'number' },
-                limit: { type: 'number' },
-                params: { type: 'json' },
-            }
-        },
-        update: {
-            parameters: {
-                id: { type: 'json' },
-                object: {
-                    type: 'json',
-                    subtype: 'object',
-                    required: true,
-                },
-                options: { type: 'json' },
-            }
-        },
-        upsert: {
-            parameters: {
-                id: { type: 'json' },
-                object: {
-                    type: 'json',
-                    subtype: 'object',
-                    required: true,
-                },
-                options: { type: 'json' },
-            }
-        },
-        delete: {
-            parameters: {
-                uid: { type: 'string' },
-                id: { type: 'json' },
-            }
-        },
-    },
-}
-
-module.exports = {
-    'hello-world': {
-        description: 'A simple driver that returns a greeting.',
-        methods: {
-            greet: {
-                description: 'Returns a greeting.',
-                parameters: {
-                    subject: {
-                        type: 'string',
-                        optional: true,
-                    },
-                },
-                result: { type: 'string' },
-            }
-        }
-    },
-    // Note: these are all prefixed with 'puter-' to avoid name collisions
-    // with possible future support for user-contributed driver interfaces.
-    'puter-ocr': {
-        description: 'Optical character recognition.',
-        methods: {
-            recognize: {
-                description: 'Recognize text in an image or document.',
-                parameters:  {
-                    source: {
-                        type: 'file',
-                    },
-                },
-                result: { type: 'image' },
-            },
-        },
-    },
-    'puter-kvstore': {
-        description: 'A simple key-value store.',
-        methods: {
-            get: {
-                description: 'Get a value by key.',
-                parameters: {
-                    key: { type: 'json', required: true },
-                    app_uid: { type: 'string', optional: true },
-                },
-                result: { type: 'json' },
-            },
-            set: {
-                description: 'Set a value by key.',
-                parameters: {
-                    key: { type: 'string', required: true, },
-                    value: { type: 'json' },
-                    app_uid: { type: 'string', optional: true },
-                },
-                result: { type: 'void' },
-            },
-            del: {
-                description: 'Delete a value by key.',
-                parameters: {
-                    key: { type: 'string' },
-                    app_uid: { type: 'string', optional: true },
-                },
-                result: { type: 'void' },
-            },
-            list: {
-                description: 'List all key-value pairs.',
-                parameters: {
-                    as: {
-                        type: 'string',
-                    },
-                    app_uid: { type: 'string', optional: true },
-                },
-                result: { type: 'array' },
-            },
-            flush: {
-                description: 'Delete all key-value pairs.',
-                parameters: {},
-                result: { type: 'void' },
-            },
-            incr: {
-                description: 'Increment a value by key.',
-                parameters: {
-                    key: { type: 'string', required: true, },
-                    amount: { type: 'number' },
-                    app_uid: { type: 'string', optional: true },
-                },
-                result: { type: 'number' },
-            },
-            decr: {
-                description: 'Increment a value by key.',
-                parameters: {
-                    key: { type: 'string', required: true, },
-                    amount: { type: 'number' },
-                    app_uid: { type: 'string', optional: true },
-                },
-                result: { type: 'number' },
-            },
-            /*
-            expireat: {
-                description: 'Set a key\'s time-to-live.',
-                parameters: {
-                    key: { type: 'string', required: true, },
-                    timestamp: { type: 'number', required: true, },
-                    app_uid: { type: 'string', optional: true },
-                },
-            },
-            expire: {
-                description: 'Set a key\'s time-to-live.',
-                parameters: {
-                    key: { type: 'string', required: true, },
-                    ttl: { type: 'number', required: true, },
-                    app_uid: { type: 'string', optional: true },
-                },
-            }
-            */
-        }
-    },
-    'puter-chat-completion': {
-        description: 'Chatbot.',
-        methods: {
-            complete: {
-                description: 'Get completions for a chat log.',
-                parameters: {
-                    messages: { type: 'json' },
-                    vision: { type: 'flag' },
-                },
-                result: { type: 'json' }
-            }
-        }
-    },
-    'puter-image-generation': {
-        description: 'AI Image Generation.',
-        methods: {
-            generate: {
-                description: 'Generate an image from a prompt.',
-                parameters: {
-                    prompt: { type: 'string' },
-                },
-                result_choices: [
-                    {
-                        names: ['image'],
-                        type: {
-                            $: 'stream',
-                            content_type: 'image',
-                        }
-                    },
-                    {
-                        names: ['url'],
-                        type: {
-                            $: 'string:url:web',
-                            content_type: 'image',
-                        }
-                    },
-                ],
-                result: {
-                    description: 'URL of the generated image.',
-                    type: 'string'
-                }
-            }
-        }
-    },
-    'puter-tts': {
-        description: 'Text-to-speech.',
-        methods: {
-            list_voices: {
-                description: 'List available voices.',
-                parameters: {},
-            },
-            synthesize: {
-                description: 'Synthesize speech from text.',
-                parameters: {
-                    text: { type: 'string' },
-                    voice: { type: 'string' },
-                    language: { type: 'string' },
-                    ssml: { type: 'flag' },
-                },
-                result_choices: [
-                    {
-                        names: ['audio'],
-                        type: {
-                            $: 'stream',
-                            content_type: 'audio',
-                        }
-                    },
-                ]
-            },
-        }
-    },
-    'puter-analytics': {
-        no_sdk: true,
-        description: 'Analytics.',
-        methods: {
-            create_trace: {
-                description: 'Get a trace UID.',
-                parameters: {
-                    trace_id: { type: 'string', optional: true },
-                },
-                result: { type: 'string' }
-            },
-            record: {
-                description: 'Record an event.',
-                parameters: {
-                    trace_id: { type: 'string', optional: true },
-                    tags: { type: 'json' },
-                    fields: { type: 'json' },
-                },
-                result: { type: 'void' }
-            }
-        }
-    },
-    'puter-apps': {
-        ...ENTITY_STORAGE_INTERFACE,
-        description: 'Manage a developer\'s apps on Puter.',
-    },
-    'puter-subdomains': {
-        ...ENTITY_STORAGE_INTERFACE,
-        description: 'Manage subdomains on Puter.',
-    },
-    'puter-notifications': {
-        ...ENTITY_STORAGE_INTERFACE,
-        description: 'Read notifications on Puter.',
-    },
-    'crud-q': {
-        ...ENTITY_STORAGE_INTERFACE,
-    },
-};