godprotocol 1.2.54 → 2.2.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.
- package/Godprotocol.js +33 -0
- package/Index.js +10 -5
- package/package.json +1 -1
- package/server/Routable/Header.js +240 -0
- package/server/Routable/Route_table.js +198 -0
- package/server/Routable/Services.js +193 -0
- package/server/utils.js +54 -0
- package/server/version_control.js +71 -0
- package/{Objects → virtual_machine/Objects}/Clock.js +9 -9
- package/{Objects → virtual_machine/Objects}/Events.js +47 -47
- package/{callables → virtual_machine/callables}/functions/assert.js +9 -9
- package/{callables → virtual_machine/callables}/functions/env.js +4 -4
- package/{callables → virtual_machine/callables}/functions/query.js +17 -17
- package/{callables → virtual_machine/callables}/functions/wait.js +8 -8
- package/{html → virtual_machine/html}/create.js +95 -95
- package/{html → virtual_machine/html}/index.js +125 -125
- package/{html → virtual_machine/html}/load.js +166 -166
- package/{html → virtual_machine/html}/parse.js +170 -170
- package/{html → virtual_machine/html}/run.js +150 -150
- package/{html → virtual_machine/html}/util.js +4 -4
- /package/{Datatypes → virtual_machine/Datatypes}/arr.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/bool.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/callable.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/cls.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/conf.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/err.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/func.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/functions/storage.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/functions/wallet.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/instance.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/num.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/str.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/twa.js +0 -0
- /package/{Datatypes → virtual_machine/Datatypes}/voi.js +0 -0
- /package/{Instances → virtual_machine/Instances}/account.js +0 -0
- /package/{Instances → virtual_machine/Instances}/event.js +0 -0
- /package/{Instances → virtual_machine/Instances}/fold.js +0 -0
- /package/{Instances → virtual_machine/Instances}/folder_queries.js +0 -0
- /package/{Instances → virtual_machine/Instances}/response.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Account.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Block.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Blockweb.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Callable.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Chain.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Datatypes.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Manager.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Oracle.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Repository.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Trinity.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Utils.js +0 -0
- /package/{Objects → virtual_machine/Objects}/Virtual_machine.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/display.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/event.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/exit.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/folder.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/get_uid.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/hash.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/import_.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/local.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/net.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/parse.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/render.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/servers.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/spawn.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/store.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/super_.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/twain.js +0 -0
- /package/{callables → virtual_machine/callables}/functions/typeof.js +0 -0
- /package/{callables → virtual_machine/callables}/register.js +0 -0
- /package/{utils → virtual_machine/utils}/create_server.js +0 -0
- /package/{utils → virtual_machine/utils}/functions.js +0 -0
- /package/{utils → virtual_machine/utils}/hash.js +0 -0
- /package/{utils → virtual_machine/utils}/ops.js +0 -0
- /package/{utils → virtual_machine/utils}/oracle_handlers.js +0 -0
- /package/{utils → virtual_machine/utils}/server.cert +0 -0
- /package/{utils → virtual_machine/utils}/server.key +0 -0
- /package/{utils → virtual_machine/utils}/services.js +0 -0
- /package/{utils → virtual_machine/utils}/socket_server.js +0 -0
- /package/{utils → virtual_machine/utils}/vm_utils.js +0 -0
package/Godprotocol.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Route_table from "./server/Routable/Route_table";
|
|
2
|
+
import version_middleware from "./server/version_control";
|
|
3
|
+
|
|
4
|
+
class GodProtocol {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.db_config = config.db_config;
|
|
7
|
+
|
|
8
|
+
this.api_key = config.api_key;
|
|
9
|
+
this.platform_uri = config.platform_uri;
|
|
10
|
+
this.route_table = new Route_table(this);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
load_services = async (services) => {
|
|
14
|
+
await this.route_table.load_services(services);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
add_router = async (version, routes, opts) => {
|
|
18
|
+
if (opts.is_old) {
|
|
19
|
+
await this.route_table.init_version("v1", { is_old: true });
|
|
20
|
+
this.route_table.versions[version].routes = routes;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
await this.route_table.init_version(version);
|
|
24
|
+
|
|
25
|
+
await this.route_table.load_routes(routes);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
on_request = async (req, res) => {
|
|
29
|
+
await version_middleware(req, res, this.route_table);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default GodProtocol;
|
package/Index.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import Oracle from "./Objects/Oracle.js";
|
|
1
|
+
import GodProtocol from "./Godprotocol";
|
|
3
2
|
|
|
4
|
-
let
|
|
3
|
+
let gp = new GodProtocol({
|
|
4
|
+
platform_uri: "profile.savvyaisolution.com",
|
|
5
|
+
api_key: process.env.API_KEY,
|
|
6
|
+
db_config: {},
|
|
7
|
+
});
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
gp.add_router("v2", {});
|
|
10
|
+
|
|
11
|
+
app.use((req, res) => gp.on_request(req, res));
|
|
12
|
+
export default GodProtocol;
|
package/package.json
CHANGED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { Mongo } from "@godprotocol/repositories";
|
|
2
|
+
import { post_request } from "../../utils/services.js";
|
|
3
|
+
import Services from "./Services.js";
|
|
4
|
+
|
|
5
|
+
class DB {
|
|
6
|
+
constructor(config, router) {
|
|
7
|
+
this.router = router;
|
|
8
|
+
this.db = new Mongo({
|
|
9
|
+
db_url: config.db_url,
|
|
10
|
+
db_name: router?.gp?.platform_uri.replace(/\./g, "-"),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
this.folders = {};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
read_cache = async (query, category) => {
|
|
17
|
+
let coll = this.db.collection(`$CACHE-${category}`);
|
|
18
|
+
const doc = await coll.findOne(query);
|
|
19
|
+
if (!doc) return null;
|
|
20
|
+
|
|
21
|
+
if (doc.expiry && new Date(doc.expiry) < new Date()) {
|
|
22
|
+
await coll.deleteOne({ _id: doc._id });
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return { ...doc };
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
save_cache = async (
|
|
30
|
+
query,
|
|
31
|
+
payload,
|
|
32
|
+
category,
|
|
33
|
+
ttlMs = 7 * 24 * 60 * 60 * 1000,
|
|
34
|
+
) => {
|
|
35
|
+
let coll = this.db.collection(`$CACHE-${category}`);
|
|
36
|
+
const now = new Date();
|
|
37
|
+
|
|
38
|
+
const toSet = {
|
|
39
|
+
payload: JSON.stringify(payload),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// 🔥 set expiry if TTL provided
|
|
43
|
+
if (ttlMs) {
|
|
44
|
+
toSet.expiry = new Date(now.getTime() + ttlMs);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// OR use payload expiry if present
|
|
48
|
+
else if (payload?.expiry) {
|
|
49
|
+
toSet.expiry = new Date(payload.expiry);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const res = await coll.updateOne(
|
|
53
|
+
query,
|
|
54
|
+
{
|
|
55
|
+
$set: toSet,
|
|
56
|
+
$setOnInsert: {
|
|
57
|
+
_id: crypto.randomUUID(),
|
|
58
|
+
created: now,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{ upsert: true },
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return res;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
folder = async (name) => {
|
|
68
|
+
let folder = this.folders[name];
|
|
69
|
+
|
|
70
|
+
if (folder) return folder;
|
|
71
|
+
|
|
72
|
+
folder = this.db.collection(name);
|
|
73
|
+
this.folders[name] = folder;
|
|
74
|
+
|
|
75
|
+
return folder;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
class Headers extends Services {
|
|
80
|
+
constructor() {
|
|
81
|
+
super();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
validate_api_key = async (api_key, authorization) => {
|
|
85
|
+
const db = await this.platform_db();
|
|
86
|
+
|
|
87
|
+
const query = {
|
|
88
|
+
type: "api_key",
|
|
89
|
+
api_key,
|
|
90
|
+
authorization: authorization || null,
|
|
91
|
+
platform: process.env.PLATFORM_URI,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// 🔹 1. Try cache
|
|
95
|
+
const cached = await db.read_cache(query, "auth");
|
|
96
|
+
|
|
97
|
+
if (cached?.payload) {
|
|
98
|
+
try {
|
|
99
|
+
return {
|
|
100
|
+
ok: true,
|
|
101
|
+
data: JSON.parse(cached.payload),
|
|
102
|
+
};
|
|
103
|
+
} catch {
|
|
104
|
+
// corrupted cache → ignore
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 🔹 2. Call remote
|
|
109
|
+
const headers = {
|
|
110
|
+
"x-api-version": "v2",
|
|
111
|
+
"x-api-key": api_key,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
if (authorization) {
|
|
115
|
+
headers["authorization"] = `Bearer ${authorization}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const res = await post_request(`$PROFILE/validate`, {}, headers);
|
|
119
|
+
|
|
120
|
+
// 🔹 3. Save cache if valid
|
|
121
|
+
if (res.ok && res.data) {
|
|
122
|
+
await db.save_cache(query, res.data, "auth");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return res;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
validate_third_party = async (xplatform, authorization) => {
|
|
129
|
+
const db = await this.platform_db();
|
|
130
|
+
|
|
131
|
+
const query = {
|
|
132
|
+
type: "third_party",
|
|
133
|
+
xplatform,
|
|
134
|
+
authorization: authorization || null,
|
|
135
|
+
platform: process.env.PLATFORM_URI,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// 🔹 1. Try cache
|
|
139
|
+
const cached = await db.read_cache(query, "auth");
|
|
140
|
+
|
|
141
|
+
if (cached?.payload) {
|
|
142
|
+
try {
|
|
143
|
+
return {
|
|
144
|
+
ok: true,
|
|
145
|
+
data: JSON.parse(cached.payload),
|
|
146
|
+
};
|
|
147
|
+
} catch {
|
|
148
|
+
// corrupted cache → ignore
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 🔹 2. Call remote
|
|
153
|
+
const headers = {
|
|
154
|
+
"x-api-version": "v2",
|
|
155
|
+
"x-api-key": process.env.API_KEY,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
if (authorization) {
|
|
159
|
+
headers["authorization"] = `Bearer ${authorization}`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const res = await post_request(
|
|
163
|
+
`$PROFILE/validate_third_party`,
|
|
164
|
+
{ platform_uri: xplatform },
|
|
165
|
+
headers,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// 🔹 3. Save cache
|
|
169
|
+
if (res.ok && res.data) {
|
|
170
|
+
await db.save_cache(query, res.data, "auth");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return res;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
check_security = (requirements, payload) => {
|
|
177
|
+
if (!requirements?.length) return true;
|
|
178
|
+
|
|
179
|
+
let headers = payload.headers || {};
|
|
180
|
+
|
|
181
|
+
let checks = {
|
|
182
|
+
api_key: () => !!headers["x-api-key"],
|
|
183
|
+
bearer_token: () => !!headers["authorization"],
|
|
184
|
+
xplatform: () => !!headers["x-platform"],
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
return requirements.every((r) => checks[r]?.());
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
handle_security = async (name, request) => {
|
|
191
|
+
let route = await this.get_route(name);
|
|
192
|
+
|
|
193
|
+
if (!route.config.security?.length) return true;
|
|
194
|
+
|
|
195
|
+
if (!this.check_security(route.config.security, request)) {
|
|
196
|
+
console.log("Unauthorized access attempt to route:", name);
|
|
197
|
+
return {
|
|
198
|
+
ok: false,
|
|
199
|
+
status: 401,
|
|
200
|
+
message: "Unauthorized",
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
let xplatform = request.headers["x-platform"],
|
|
205
|
+
api_key = request.headers["x-api-key"],
|
|
206
|
+
authorisation = request.headers["authorization"];
|
|
207
|
+
if (authorisation) authorisation = authorisation.replace("Bearer ", "");
|
|
208
|
+
|
|
209
|
+
let val;
|
|
210
|
+
if (xplatform) {
|
|
211
|
+
val = await this.validate_third_party(xplatform, authorisation);
|
|
212
|
+
} else {
|
|
213
|
+
console.log(api_key, authorisation);
|
|
214
|
+
val = await this.validate_api_key(api_key, authorisation);
|
|
215
|
+
console.log(val, "Uhh");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
console.log(val);
|
|
219
|
+
if (!val?.ok) {
|
|
220
|
+
return val;
|
|
221
|
+
} else {
|
|
222
|
+
val = val.data;
|
|
223
|
+
if (!val) {
|
|
224
|
+
return {
|
|
225
|
+
ok: false,
|
|
226
|
+
message: "malformed header validation",
|
|
227
|
+
status: 403,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
request.headers.profile = val.profile;
|
|
231
|
+
request.headers.xplatform = val.xplatform;
|
|
232
|
+
request.headers.platform = val.platform;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return true;
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export default Headers;
|
|
240
|
+
export { DB };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import Headers from "./Header.js";
|
|
2
|
+
|
|
3
|
+
let securities = {
|
|
4
|
+
both: ["api_key", "bearer_token"],
|
|
5
|
+
first: ["api_key"],
|
|
6
|
+
second: ["bearer_token"],
|
|
7
|
+
all: ["api_key", "bearer_token", "xplatform"],
|
|
8
|
+
none: [],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class Route_table extends Headers {
|
|
12
|
+
constructor(gp) {
|
|
13
|
+
super();
|
|
14
|
+
|
|
15
|
+
this.gp = gp;
|
|
16
|
+
this.db_config = gp.db_config;
|
|
17
|
+
this.versions = {};
|
|
18
|
+
this.validators = {};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get_version = (version) => {
|
|
22
|
+
let ver = this.versions[version];
|
|
23
|
+
if (!ver) return;
|
|
24
|
+
|
|
25
|
+
this.active_version = version;
|
|
26
|
+
|
|
27
|
+
return ver;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
init_version = async (version, config) => {
|
|
31
|
+
this.versions[version] = { config, routes: {} };
|
|
32
|
+
|
|
33
|
+
this.active_version = version;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// 🔌 extensibility
|
|
37
|
+
register_validator = (name, fn) => {
|
|
38
|
+
this.validators[name] = fn;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
load_routes = async (routes) => {
|
|
42
|
+
for (let name in routes) {
|
|
43
|
+
let { handler, ...config } = routes[name];
|
|
44
|
+
|
|
45
|
+
config.security = securities[config.security || "none"];
|
|
46
|
+
|
|
47
|
+
await this.add_route(name, handler, config);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
add_route = async (name, handler, config) => {
|
|
52
|
+
this.versions[this.active_version].routes[name] = { handler, config };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
get_route = async (name) => this.versions[this.active_version].routes[name];
|
|
56
|
+
|
|
57
|
+
check_validation = async (rule, data) => {
|
|
58
|
+
let { prop, type, required, default: is_default } = rule;
|
|
59
|
+
|
|
60
|
+
let data_value = data[prop];
|
|
61
|
+
|
|
62
|
+
data_value =
|
|
63
|
+
data_value == null || data_value == undefined ? is_default : data_value;
|
|
64
|
+
|
|
65
|
+
if (required && (data_value == null || data_value == is_default))
|
|
66
|
+
return { ok: false, message: `Field '${prop}' is required` };
|
|
67
|
+
|
|
68
|
+
if (data_value == null) {
|
|
69
|
+
return { ok: true };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (type) {
|
|
73
|
+
if (type.startsWith("/")) {
|
|
74
|
+
} else {
|
|
75
|
+
let type_of = typeof data_value;
|
|
76
|
+
if (type_of !== type)
|
|
77
|
+
return {
|
|
78
|
+
ok: false,
|
|
79
|
+
message: `Field '${prop}' must be of type '${type}' got '${type_of}'`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { ok: true };
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
validate = async (schema, data) => {
|
|
88
|
+
let { body: schema_body } = schema;
|
|
89
|
+
let { body: data_body } = data;
|
|
90
|
+
|
|
91
|
+
for (let prop in schema_body) {
|
|
92
|
+
let rule = schema_body[prop];
|
|
93
|
+
|
|
94
|
+
if (prop === "$logic") {
|
|
95
|
+
let or_logic = rule.or;
|
|
96
|
+
if (or_logic) {
|
|
97
|
+
for (let o = 0; o < or_logic.length; o++) {
|
|
98
|
+
let or_rule = or_logic[o],
|
|
99
|
+
or_rule_check;
|
|
100
|
+
|
|
101
|
+
for (let proper of or_rule.properties) {
|
|
102
|
+
or_rule_check = await this.check_validation(
|
|
103
|
+
{ prop: proper, ...or_rule },
|
|
104
|
+
data_body,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (or_rule_check?.ok) break;
|
|
108
|
+
}
|
|
109
|
+
if (or_rule.required && !or_rule_check?.ok) {
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
message: `At least one of the following fields is required: ${or_rule.properties.join(
|
|
113
|
+
", ",
|
|
114
|
+
)}`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let and_logic = rule.and;
|
|
121
|
+
if (and_logic) {
|
|
122
|
+
for (let a = 0; a < and_logic.length; a++) {
|
|
123
|
+
let and_rule = and_logic[a];
|
|
124
|
+
|
|
125
|
+
for (let prop of and_rule.properties) {
|
|
126
|
+
let and_rule_check = await this.check_validation(
|
|
127
|
+
{ prop, ...and_rule },
|
|
128
|
+
data_body,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (and_rule.required && !and_rule_check?.ok) {
|
|
132
|
+
return {
|
|
133
|
+
ok: false,
|
|
134
|
+
message: `Field '${prop}' is required`,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let validation_result = await this.check_validation(
|
|
143
|
+
{ prop, ...rule },
|
|
144
|
+
data_body,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
if (!validation_result.ok) {
|
|
148
|
+
return validation_result;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return { ok: true };
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
get_route_config = async (name) => {
|
|
156
|
+
let rot = await this.get_route(name);
|
|
157
|
+
|
|
158
|
+
return rot.config;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// =========================
|
|
162
|
+
// 🚀 EXECUTION PIPELINE
|
|
163
|
+
// =========================
|
|
164
|
+
execute = async (name, payload) => {
|
|
165
|
+
let route = await this.get_route(name);
|
|
166
|
+
|
|
167
|
+
if (!route) {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
status: 404,
|
|
171
|
+
message: "Route not found",
|
|
172
|
+
data: { path: `/${name}`, name },
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let { handler, config } = route;
|
|
177
|
+
|
|
178
|
+
// 📜 schema
|
|
179
|
+
if (config.schema) {
|
|
180
|
+
let resp = await this.validate(config.schema, payload);
|
|
181
|
+
|
|
182
|
+
console.log("Validation result for route", name, ":", resp);
|
|
183
|
+
|
|
184
|
+
if (!resp.ok) return resp;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ⚙️ middleware
|
|
188
|
+
for (let middleware of config.middlewares || []) {
|
|
189
|
+
let result = await middleware(payload);
|
|
190
|
+
if (!result?.ok) return result;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// 🎯 handler
|
|
194
|
+
return await handler(payload);
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export default Route_table;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { post_request } from "../../utils/services.js";
|
|
2
|
+
import { DB } from "./Header.js";
|
|
3
|
+
|
|
4
|
+
let gp_services = {
|
|
5
|
+
profile: "https://profile-api.savvyaisolution.com",
|
|
6
|
+
settings: "https://settings-api.savvyaisolution.com",
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
class Services {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.services = new Object();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
load_services = async (services) => {
|
|
15
|
+
this.services = services;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
get_token = async (service, id) => {
|
|
19
|
+
let token;
|
|
20
|
+
|
|
21
|
+
let db = await this.platform_db();
|
|
22
|
+
token = await db.read_cache(
|
|
23
|
+
{ platform_uri: service.uri, id: id.profile || id.platform },
|
|
24
|
+
"token",
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
if (token) return token;
|
|
28
|
+
|
|
29
|
+
let ftch = await fetch(`${gp_services.profile}/get_token`, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: {
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
Accept: "application/json",
|
|
34
|
+
"x-api-version": "v2",
|
|
35
|
+
"x-api-key": this.api_key,
|
|
36
|
+
},
|
|
37
|
+
body: JSON.stringify({ platform_uri: service.uri, ...id }),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
token = await ftch.json();
|
|
41
|
+
|
|
42
|
+
if (token?.ok) {
|
|
43
|
+
await db.save_cache(
|
|
44
|
+
{ id: id.profile || id.platform, platform_uri: service.uri },
|
|
45
|
+
token.data,
|
|
46
|
+
"token",
|
|
47
|
+
);
|
|
48
|
+
return token.data;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return null;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
get_service = async (service) => {
|
|
55
|
+
let servic = this.services[service];
|
|
56
|
+
if (!servic) return;
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
call: async (path, body, header) => {
|
|
60
|
+
let headers = {
|
|
61
|
+
"Content-Type": "application/json",
|
|
62
|
+
Accept: "application/json",
|
|
63
|
+
"x-api-version": servic.api_version || "v1",
|
|
64
|
+
};
|
|
65
|
+
let token;
|
|
66
|
+
if (header) {
|
|
67
|
+
if (header.token) {
|
|
68
|
+
token = header.token;
|
|
69
|
+
} else if (header.profile) {
|
|
70
|
+
token = await this.get_token(servic, header);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
74
|
+
headers["x-platform"] = this.platform_uri;
|
|
75
|
+
|
|
76
|
+
let response = await fetch(`${servic.url}/${path}`, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers,
|
|
79
|
+
body: JSON.stringify(body || {}),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return await response.json();
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
platform_db = async () => {
|
|
88
|
+
return new DB(this.db_config, this);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
resolve_db = async (req) => {
|
|
92
|
+
const { platform } = req.headers;
|
|
93
|
+
|
|
94
|
+
// 🔹 Internal system call → use base DB
|
|
95
|
+
if (req.headers["x-api-key"] === process.env.API_KEY) {
|
|
96
|
+
const db = await this.platform_db();
|
|
97
|
+
req.db = db;
|
|
98
|
+
return db;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!platform?.uri || !platform?._id) {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
message: "Platform context missing",
|
|
105
|
+
status: 400,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const baseDB = await this.platform_db();
|
|
110
|
+
|
|
111
|
+
const query = {
|
|
112
|
+
type: "db_config",
|
|
113
|
+
key: platform.uri,
|
|
114
|
+
platform: this.platform_uri,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// 🔹 1. Try cache
|
|
118
|
+
const cached = await baseDB.read_cache(query, "config");
|
|
119
|
+
|
|
120
|
+
let config;
|
|
121
|
+
|
|
122
|
+
if (cached?.payload) {
|
|
123
|
+
try {
|
|
124
|
+
config = JSON.parse(cached.payload);
|
|
125
|
+
} catch {
|
|
126
|
+
config = null; // corrupted cache → ignore
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 🔹 2. Fetch remote if no valid cache
|
|
131
|
+
if (!config) {
|
|
132
|
+
const tokenRes = await this.get_token(
|
|
133
|
+
{ uri: "settings.savvyaisolution.com" },
|
|
134
|
+
{ platform: platform._id },
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
if (!tokenRes.token) {
|
|
138
|
+
return {
|
|
139
|
+
ok: false,
|
|
140
|
+
message: "Failed to retrieve platform token",
|
|
141
|
+
status: 403,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let ftch = await fetch(`${gp_services.settings}/get_settings`, {
|
|
146
|
+
method: "POST",
|
|
147
|
+
headers: {
|
|
148
|
+
Authorization: `Bearer ${tokenRes.token}`,
|
|
149
|
+
"x-platform": this.platform_uri,
|
|
150
|
+
"x-api-version": "v1",
|
|
151
|
+
Accept: "application/json",
|
|
152
|
+
"Content-Type": "application/json",
|
|
153
|
+
},
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
category: "db",
|
|
156
|
+
key: [this.platform_uri, "general"],
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
159
|
+
let dbRes = await ftch.json();
|
|
160
|
+
|
|
161
|
+
if (!dbRes.ok) {
|
|
162
|
+
return {
|
|
163
|
+
ok: false,
|
|
164
|
+
message: "Failed to retrieve database configuration",
|
|
165
|
+
status: 500,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
config =
|
|
170
|
+
dbRes.data?.db?.[`${this.platform_uri}`] || dbRes.data?.db?.["general"];
|
|
171
|
+
|
|
172
|
+
if (!config) {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
message: "Database configuration not found",
|
|
176
|
+
status: 404,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 🔹 3. Save cache
|
|
181
|
+
await baseDB.save_cache(query, config, "config");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 🔹 4. Instantiate scoped DB
|
|
185
|
+
const db = new DB(config, this);
|
|
186
|
+
|
|
187
|
+
req.db = db;
|
|
188
|
+
|
|
189
|
+
return db;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export default Services;
|