mirror of
https://github.com/HeyPuter/puter.git
synced 2025-12-30 17:50:00 -06:00
fix: types and tests? (#2193)
This commit is contained in:
33
extensions/api.d.ts
vendored
33
extensions/api.d.ts
vendored
@@ -1,4 +1,6 @@
|
||||
import APIError from '@heyputer/backend/src/api/APIError.js';
|
||||
import type { WebServerService } from '@heyputer/backend/src/modules/web/WebServerService.js';
|
||||
import query from '@heyputer/backend/src/om/query/query';
|
||||
import type { Actor } from '@heyputer/backend/src/services/auth/Actor.js';
|
||||
import type { BaseDatabaseAccessService } from '@heyputer/backend/src/services/database/BaseDatabaseAccessService.d.ts';
|
||||
import type { MeteringService } from '@heyputer/backend/src/services/MeteringService/MeteringService.ts';
|
||||
@@ -7,14 +9,11 @@ import type { DBKVStore } from '@heyputer/backend/src/services/repositories/DBKV
|
||||
import type { SUService } from '@heyputer/backend/src/services/SUService.js';
|
||||
import type { IUser } from '@heyputer/backend/src/services/User.js';
|
||||
import type { UserService } from '@heyputer/backend/src/services/UserService.d.ts';
|
||||
import { Context } from '@heyputer/backend/src/util/context.js';
|
||||
import type { RequestHandler } from 'express';
|
||||
import type FSNodeContext from '../src/backend/src/filesystem/FSNodeContext.js';
|
||||
import type helpers from '../src/backend/src/helpers.js';
|
||||
import type * as ExtensionControllerExports from './ExtensionController/src/ExtensionController.ts';
|
||||
import { Context } from '@heyputer/backend/src/util/context.js';
|
||||
import config from '../volatile/config/config.json'
|
||||
import APIError from '@heyputer/backend/src/api/APIError.js';
|
||||
import query from '@heyputer/backend/src/om/query/query';
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
@@ -40,22 +39,18 @@ interface EndpointOptions {
|
||||
}
|
||||
|
||||
// Driver interface types
|
||||
type ParameterDefinition = {
|
||||
interface ParameterDefinition {
|
||||
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
||||
optional: boolean;
|
||||
};
|
||||
type MethodDefinition = {
|
||||
}
|
||||
interface MethodDefinition {
|
||||
description: string;
|
||||
parameters: Record<string, ParameterDefinition>;
|
||||
};
|
||||
type DriverInterface = {
|
||||
}
|
||||
interface DriverInterface {
|
||||
description: string;
|
||||
methods: Record<string, MethodDefinition>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
|
||||
|
||||
@@ -97,12 +92,12 @@ interface Extension extends RouterMethods {
|
||||
run<T>(label: string, fn: () => T): T;
|
||||
run<T>(fn: () => T): T;
|
||||
},
|
||||
config: Record<string | number | symbol, any>,
|
||||
config: Record<string | number | symbol, any>,
|
||||
on<T extends unknown[]>(event: string, listener: (...args: T) => void): void, // TODO DS: type events better
|
||||
on(event: 'create.drivers', listener: (event: {createDriver: (interface: string, service: string, executors: any)=>any}) => void),
|
||||
on(event: 'create.permissions', listener: (event: {grant_to_everyone: (permission: string) => void, grant_to_users: (permission: string) => void})=>void)
|
||||
on(event: 'create.interfaces', listener: (event: {createInterface: (interface: string, interfaces: DriverInterface) => void}) => void)
|
||||
import(module: 'data'): { db: BaseDatabaseAccessService, kv: DBKVStore & {get: (string) => void, set: (string, string) => void}, cache: unknown }// TODO DS: type cache better
|
||||
on(event: 'create.drivers', listener: (event: { createDriver: (interface: string, service: string, executors: any) => any }) => void),
|
||||
on(event: 'create.permissions', listener: (event: { grant_to_everyone: (permission: string) => void, grant_to_users: (permission: string) => void }) => void)
|
||||
on(event: 'create.interfaces', listener: (event: { createInterface: (interface: string, interfaces: DriverInterface) => void }) => void)
|
||||
import(module: 'data'): { db: BaseDatabaseAccessService, kv: DBKVStore & { get: (string) => void, set: (string, string) => void }, cache: unknown }// TODO DS: type cache better
|
||||
import(module: 'core'): CoreRuntimeModule,
|
||||
import(module: 'fs'): FilesystemModule,
|
||||
import(module: 'query'): typeof query,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
const { Eq } = extension.import('query')
|
||||
const { kv } = extension.import('data');
|
||||
const span = extension.span;
|
||||
const { Eq } = extension.import('query');
|
||||
const { db } = extension.import('data');
|
||||
const { Context, APIError } = extension.import('core');
|
||||
const app_es: any = extension.import('service:es:app');
|
||||
const { APIError } = extension.import('core');
|
||||
const app_es = extension.import('service:es:app') as any;
|
||||
|
||||
extension.on('create.interfaces', (event) => {
|
||||
event.createInterface('app-telemetry', {
|
||||
@@ -22,8 +20,8 @@ extension.on('create.interfaces', (event) => {
|
||||
},
|
||||
offset: {
|
||||
type: 'number',
|
||||
optional: true
|
||||
}
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
user_count: {
|
||||
@@ -32,47 +30,45 @@ extension.on('create.interfaces', (event) => {
|
||||
app_uuid: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
extension.on('create.drivers', event => {
|
||||
event.createDriver('app-telemetry', 'app-telemetry', {
|
||||
async get_users({ app_uuid, limit = 100, offset = 0 }: {app_uuid: string, limit: number, offset: number}) {
|
||||
async get_users ({ app_uuid, limit = 100, offset = 0 }: { app_uuid: string, limit: number, offset: number }) {
|
||||
// first lets make sure executor owns this app
|
||||
const [result] = (await app_es.select({ predicate: new Eq({ key: 'uid', value: app_uuid }) }));
|
||||
if (!result) {
|
||||
if ( ! result ) {
|
||||
throw APIError.create('permission_denied');
|
||||
}
|
||||
|
||||
// Fetch and return users
|
||||
const users: Array<{username: string, uuid: string}> = await db.read(
|
||||
`SELECT user.username, user.uuid FROM user_to_app_permissions
|
||||
const users: Array<{ username: string, uuid: string }> = await db.read(`SELECT user.username, user.uuid FROM user_to_app_permissions
|
||||
INNER JOIN user ON user_to_app_permissions.user_id = user.id
|
||||
WHERE permission = 'flag:app-is-authenticated' AND app_id=? ORDER BY (dt IS NOT NULL), dt, user_id LIMIT ? OFFSET ?`,
|
||||
[result.private_meta.mysql_id, limit, offset],
|
||||
);
|
||||
return users.map(e=>{return {user: e.username, user_uuid: e.uuid}});
|
||||
[result.private_meta.mysql_id, limit, offset]);
|
||||
return users.map(e => {
|
||||
return { user: e.username, user_uuid: e.uuid };
|
||||
});
|
||||
},
|
||||
async user_count({ app_uuid }: {app_uuid: string}) {
|
||||
async user_count ({ app_uuid }: { app_uuid: string }) {
|
||||
// first lets make sure executor owns this app
|
||||
const [result] = (await app_es.select({ predicate: new Eq({ key: 'uid', value: app_uuid }) }));
|
||||
if (!result) {
|
||||
if ( ! result ) {
|
||||
throw APIError.create('permission_denied');
|
||||
}
|
||||
|
||||
// Fetch and return authenticated user count
|
||||
const [data] = await db.read(
|
||||
`SELECT count(*) FROM user_to_app_permissions
|
||||
const [data] = await db.read(`SELECT count(*) FROM user_to_app_permissions
|
||||
WHERE permission = 'flag:app-is-authenticated' AND app_id=?;`,
|
||||
[result.private_meta.mysql_id],
|
||||
);
|
||||
[result.private_meta.mysql_id]);
|
||||
const count = data['count(*)'];
|
||||
return count;
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
1
extensions/app-telemetry/index.d.ts
vendored
Normal file
1
extensions/app-telemetry/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import '../api.js';
|
||||
@@ -12,7 +12,8 @@
|
||||
"sourceMap": true,
|
||||
},
|
||||
"include": [
|
||||
"app-user-count.ts",
|
||||
"./**/*.ts",
|
||||
"./**/*.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"**/*.test.ts",
|
||||
|
||||
@@ -54,16 +54,19 @@ def run():
|
||||
# =========================================================================
|
||||
cxc_toolkit.exec.run_command("npm install")
|
||||
common.init_backend_config()
|
||||
admin_password = common.get_admin_password()
|
||||
update_server_config()
|
||||
|
||||
# =========================================================================
|
||||
# config client
|
||||
# =========================================================================
|
||||
cxc_toolkit.exec.run_background("npm start")
|
||||
# wait 10s for the server to start
|
||||
cxc_toolkit.exec.run_background(
|
||||
"npm start", work_dir=common.PUTER_ROOT, log_path="/tmp/backend.log"
|
||||
)
|
||||
admin_password = common.get_admin_password()
|
||||
# wait 10 more sec for the server to start
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
token = common.get_token(admin_password)
|
||||
common.init_client_config(token)
|
||||
|
||||
|
||||
@@ -30,25 +30,20 @@ def get_admin_password() -> str:
|
||||
"""
|
||||
Get the admin password from the backend server, throw an error if not found.
|
||||
"""
|
||||
LOG_PATH = "/tmp/backend.log"
|
||||
backend_process = cxc_toolkit.exec.run_background("npm start", log_path=LOG_PATH)
|
||||
|
||||
# NB: run_command + kill_on_output may wait indefinitely, use run_background + hard limit instead
|
||||
time.sleep(10)
|
||||
|
||||
backend_process.terminate()
|
||||
|
||||
# read the log file
|
||||
with open(LOG_PATH, "r") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if "password for admin" in line:
|
||||
print(f"found password line: ---{line}---")
|
||||
admin_password = line.split("password for admin is:")[1].strip()
|
||||
print(f"Extracted admin password: {admin_password}")
|
||||
return admin_password
|
||||
|
||||
raise RuntimeError(f"no admin password found, check {LOG_PATH} for details")
|
||||
for attempt in range(60): # wait up to 60 seconds (1 minute)
|
||||
time.sleep(1)
|
||||
|
||||
# read the log file
|
||||
with open("/tmp/backend.log", "r") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if "password for admin" in line:
|
||||
print(f"found password line: ---{line}---")
|
||||
admin_password = line.split("password for admin is:")[1].strip()
|
||||
print(f"Extracted admin password: {admin_password}")
|
||||
return admin_password
|
||||
|
||||
raise RuntimeError(f"no admin password found after 60 seconds, check {LOG_PATH} for details")
|
||||
|
||||
|
||||
def get_token(admin_password: str) -> str:
|
||||
|
||||
@@ -15,23 +15,21 @@ def run():
|
||||
# clean port 4100 for backend server
|
||||
cxc_toolkit.exec.run_command("fuser -k 4100/tcp", ignore_failure=True)
|
||||
|
||||
# clean port 50052 for fs-tree-manager server
|
||||
cxc_toolkit.exec.run_command("fuser -k 50052/tcp", ignore_failure=True)
|
||||
|
||||
# =========================================================================
|
||||
# config server
|
||||
# =========================================================================
|
||||
cxc_toolkit.exec.run_command("npm install")
|
||||
common.init_backend_config()
|
||||
admin_password = common.get_admin_password()
|
||||
|
||||
# =========================================================================
|
||||
# start backend server
|
||||
# =========================================================================
|
||||
cxc_toolkit.exec.run_background(
|
||||
"npm start", work_dir=common.PUTER_ROOT, log_path="/tmp/backend.log"
|
||||
"npm start", work_dir=common.PUTER_ROOT, log_path="/tmp/backend.log"
|
||||
)
|
||||
# wait 10s for the server to start
|
||||
admin_password = common.get_admin_password()
|
||||
# wait 10 more sec for the server to start
|
||||
time.sleep(10)
|
||||
|
||||
# =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user