mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-03 16:10:31 +00:00
refactor: begin migrating utility code
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test (18.x) (push) Has been cancelled
test / test (20.x) (push) Has been cancelled
test / test (22.x) (push) Has been cancelled
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test (18.x) (push) Has been cancelled
test / test (20.x) (push) Has been cancelled
test / test (22.x) (push) Has been cancelled
I'm calling this approach a "re-core"; see src/backend-core-0/README.md for more information about this.
This commit is contained in:
Generated
+9
@@ -2049,6 +2049,10 @@
|
||||
"resolved": "src/backend",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@heyputer/backend-core-0": {
|
||||
"resolved": "src/backend-core-0",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@heyputer/gui": {
|
||||
"resolved": "src/gui",
|
||||
"link": true
|
||||
@@ -15133,6 +15137,11 @@
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
},
|
||||
"src/backend-core-0": {
|
||||
"name": "@heyputer/backend-core-0",
|
||||
"version": "1.0.0",
|
||||
"license": "AGPL-3.0-only"
|
||||
},
|
||||
"src/backend/node_modules/lru-cache": {
|
||||
"version": "11.0.2",
|
||||
"license": "ISC",
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# What is `backend-core-0`?
|
||||
|
||||
The ugly name is intentional. We prefer to refactor incrementally which
|
||||
means we need a way to "re-core" the backend, and we may do this more
|
||||
than once simultaneously (hence it's `0` right now).
|
||||
|
||||
"re-core" is a term I just made up, and it means this:
|
||||
> To find the utility code that is not dependent on other utility code,
|
||||
> move that into a new package, and then continue this process in multiple
|
||||
> iterations until the problem being solved is solved.
|
||||
|
||||
The purpose of `backend-core-0` is to move common dependencies for driver
|
||||
implementations into a new core so that existing driver implementations
|
||||
can be moved from backend modules (part of the `backend` package) to
|
||||
extensions (packages added to Puter at runtime).
|
||||
|
||||
What will follow is a log of what was moved here and why.
|
||||
|
||||
## 2025-03-31
|
||||
|
||||
The AI/LLM driver module depends on constructs related to driver
|
||||
interfaces. The actual mechanism that facilitates these interfaces,
|
||||
as well as the interface format, both don't really have a name yet;
|
||||
I'll call it the "PDIM" (Puter Driver Interface Mechanism) in this log.
|
||||
|
||||
The PDIM depends on some class definitions currently in
|
||||
`src/backend/src/services/drivers/meta` which are split into the categories
|
||||
of "Constructs" and "Runtime Entities". A construct is the class
|
||||
representation of something defined in an interface, including
|
||||
**Interface** itself, and a RuntimeEntity - well there's only one;
|
||||
it's a wrapper for runtime-typed values such as "jpeg stream".
|
||||
|
||||
A construct called **Parameter**, which is the class represerntation
|
||||
of a parameter of an interface that a driver may implement, depends on
|
||||
a file called `types.js`. This file defines high-level types like String,
|
||||
URL, File, etc that can be used in Puter drivers.
|
||||
|
||||
Some types depend on utilities in Puter's backend:
|
||||
- **File**
|
||||
- filesystem/validation
|
||||
- `is_valid_uuidv4` from helpers.js
|
||||
- **URL**
|
||||
- `is_valid_url` from helpers.js
|
||||
|
||||
These utilities do not have dependencies so they are good candidates
|
||||
to be moved into this package. Afterwards, it currently apperas that
|
||||
everything in `drivers/meta` can be moved here, allowing DriverService
|
||||
to finally be moved to a backend module (right now it's part of backend
|
||||
core), and driver modules like `puterai` will be closer to being able
|
||||
to be moved to extensions.
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@heyputer/backend-core-0",
|
||||
"version": "1.0.0",
|
||||
"description": "The ugly name is intentional. We prefer to refactor incrementally which means we need a way to \"re-core\" the backend, and we may do this more than once simultaneously (hence it's `0` right now).",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"prepare": "npm run build",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"require": "./dist/cjs/exports.cjs",
|
||||
"import": "./dist/esm/exports.js"
|
||||
}
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "AGPL-3.0-only"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { defineConfig } from 'rollup';
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
|
||||
export default defineConfig([
|
||||
// ESM build
|
||||
{
|
||||
input: 'src/exports.js',
|
||||
output: {
|
||||
dir: 'dist/esm',
|
||||
format: 'es',
|
||||
preserveModules: true
|
||||
},
|
||||
plugins: [nodeResolve()]
|
||||
},
|
||||
// CJS build
|
||||
{
|
||||
input: 'src/exports.js',
|
||||
output: {
|
||||
dir: 'dist/cjs',
|
||||
format: 'cjs',
|
||||
preserveModules: true,
|
||||
entryFileNames: '[name].cjs',
|
||||
},
|
||||
plugins: [nodeResolve(), commonjs()]
|
||||
}
|
||||
]);
|
||||
@@ -0,0 +1 @@
|
||||
export * as validation from './pdim/validation';
|
||||
@@ -0,0 +1,73 @@
|
||||
export const is_valid_uuid = ( uuid ) => {
|
||||
let s = "" + uuid;
|
||||
s = s.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
||||
return !! s;
|
||||
}
|
||||
|
||||
export const is_valid_uuid4 = ( uuid ) => {
|
||||
return is_valid_uuid(uuid);
|
||||
}
|
||||
|
||||
export const is_specifically_uuidv4 = ( uuid ) => {
|
||||
let s = "" + uuid;
|
||||
|
||||
s = s.match(/^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i);
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export const is_valid_url = ( url ) => {
|
||||
let s = "" + url;
|
||||
|
||||
try {
|
||||
new URL(s);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const path_excludes = () => /[\x00-\x1F]/g;
|
||||
|
||||
// this characters are not allowed in path names because
|
||||
// they might be used to trick the user into thinking
|
||||
// a filename is different from what it actually is.
|
||||
const safety_excludes = [
|
||||
/[\u202A-\u202E]/, // RTL and LTR override
|
||||
/[\u200E-\u200F]/, // RTL and LTR mark
|
||||
/[\u2066-\u2069]/, // RTL and LTR isolate
|
||||
/[\u2028-\u2029]/, // line and paragraph separator
|
||||
/[\uFF01-\uFF5E]/, // fullwidth ASCII
|
||||
/[\u2060]/, // word joiner
|
||||
/[\uFEFF]/, // zero width no-break space
|
||||
/[\uFFFE-\uFFFF]/, // non-characters
|
||||
];
|
||||
|
||||
export const is_valid_path = (path, {
|
||||
no_relative_components,
|
||||
allow_path_fragment,
|
||||
} = {}) => {
|
||||
if ( typeof path !== 'string' ) return false;
|
||||
if ( path.length < 1 ) false;
|
||||
if ( path_excludes().test(path) ) return false;
|
||||
for ( const exclude of safety_excludes ) {
|
||||
if ( exclude.test(path) ) return false;
|
||||
}
|
||||
|
||||
if ( ! allow_path_fragment ) if ( path[0] !== '/' && path[0] !== '.' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( no_relative_components ) {
|
||||
const components = path.split('/');
|
||||
for ( const component of components ) {
|
||||
if ( component === '' ) continue;
|
||||
const name_without_dots = component.replace(/\./g, '');
|
||||
if ( name_without_dots.length < 1 ) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1194,37 +1194,6 @@ async function jwt_auth(req){
|
||||
return ancestors;
|
||||
}
|
||||
|
||||
function is_valid_uuid ( uuid ) {
|
||||
let s = "" + uuid;
|
||||
s = s.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
||||
return !! s;
|
||||
}
|
||||
|
||||
function is_valid_uuid4 ( uuid ) {
|
||||
return is_valid_uuid(uuid);
|
||||
}
|
||||
|
||||
function is_specifically_uuidv4 ( uuid ) {
|
||||
let s = "" + uuid;
|
||||
|
||||
s = s.match(/^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i);
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function is_valid_url ( url ) {
|
||||
let s = "" + url;
|
||||
|
||||
try {
|
||||
new URL(s);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function hyphenize_confirm_code(email_confirm_code){
|
||||
email_confirm_code = email_confirm_code.toString();
|
||||
email_confirm_code =
|
||||
@@ -1679,12 +1648,9 @@ module.exports = {
|
||||
is_empty,
|
||||
is_shared_with,
|
||||
is_shared_with_anyone,
|
||||
is_valid_uuid4,
|
||||
is_valid_uuid,
|
||||
is_specifically_uuidv4,
|
||||
...require('@heyputer/backend-core-0').validation,
|
||||
is_temp_users_disabled,
|
||||
is_user_signup_disabled,
|
||||
is_valid_url,
|
||||
jwt_auth,
|
||||
mv,
|
||||
number_format,
|
||||
|
||||
Reference in New Issue
Block a user