godprotocol 2.3.15 → 2.3.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "godprotocol",
3
- "version": "2.3.15",
3
+ "version": "2.3.16",
4
4
  "description": "A distributed computing environment for Web 4.0 — integrating AI, decentralisation, and virtual computation.",
5
5
  "main": "Index.js",
6
6
  "type": "module",
@@ -284,7 +284,7 @@ class Headers extends Services {
284
284
 
285
285
  let val;
286
286
  if (config.security?.includes("auth_token")) {
287
- if (authorisation?.startsWith("p")) {
287
+ if (authorisation?.startsWith("p") || authorisation?.startsWith("o")) {
288
288
  val = await this.validate_api_key(authorisation);
289
289
  } else
290
290
  val = await this.validate_third_party(
@@ -21,12 +21,15 @@ class Route_table extends Headers {
21
21
  this.validators = {};
22
22
  }
23
23
 
24
- get_version = (version) => {
24
+ get_version = (version = this.active_version) => {
25
25
  let ver = this.versions[version];
26
26
  if (!ver) return;
27
27
 
28
28
  this.active_version = version;
29
29
 
30
+ this.db_prefix =
31
+ ver.config?.db_prefix === true ? version : ver.config?.db_prefix;
32
+
30
33
  return ver;
31
34
  };
32
35
 
@@ -74,10 +77,12 @@ class Route_table extends Headers {
74
77
  return route;
75
78
  };
76
79
 
80
+ getValue = (obj, path) => path.split(".").reduce((o, key) => o?.[key], obj);
81
+
77
82
  check_validation = async (rule, data) => {
78
- let { prop, type, required } = rule;
83
+ let { prop, type, required, enum: allowed } = rule;
79
84
 
80
- let data_value = data[prop];
85
+ let data_value = this.getValue(data, prop);
81
86
 
82
87
  if (data_value === undefined && rule.hasOwnProperty("default_value")) {
83
88
  data_value = rule.default_value;
@@ -90,92 +95,139 @@ class Route_table extends Headers {
90
95
  ok: false,
91
96
  message: `Field '${prop}' is required`,
92
97
  };
93
- } else {
94
- return { ok: true };
95
98
  }
99
+ return { ok: true };
96
100
  }
97
101
 
102
+ // type validation
103
+ // =========================
104
+ // Type validation
105
+ // =========================
106
+
98
107
  if (type) {
99
- if (type.startsWith("/")) {
100
- } else {
101
- let type_of;
102
- if (type === "array") {
103
- type_of = Array.isArray(data_value) ? "array" : typeof data_value;
104
- } else type_of = typeof data_value;
105
-
106
- if (type_of !== type)
108
+ let descriptor = type;
109
+
110
+ // Logical schemas may provide a map:
111
+ // type: {
112
+ // intervals: { value: "array", min: 1 },
113
+ // throttle: { value: "number", min: 1000 }
114
+ // }
115
+ if (typeof type === "object" && !Array.isArray(type)) {
116
+ descriptor = type[prop];
117
+
118
+ // No type rule for this property
119
+ if (!descriptor) {
120
+ descriptor = null;
121
+ }
122
+ }
123
+
124
+ if (descriptor) {
125
+ // Allow shorthand:
126
+ // "string"
127
+ // or
128
+ // { value: "string", ... }
129
+ if (typeof descriptor === "string") {
130
+ descriptor = {
131
+ value: descriptor,
132
+ };
133
+ }
134
+
135
+ const expected = descriptor.value;
136
+
137
+ let actual;
138
+
139
+ if (expected === "array") {
140
+ actual = Array.isArray(data_value) ? "array" : typeof data_value;
141
+ } else {
142
+ actual = typeof data_value;
143
+ }
144
+
145
+ if (actual !== expected) {
107
146
  return {
108
147
  ok: false,
109
- message: `Field '${prop}' must be of type '${type}' got '${type_of}'`,
148
+ message: `Field '${prop}' must be of type '${expected}', got '${actual}'`,
110
149
  };
150
+ }
111
151
  }
112
152
  }
113
153
 
154
+ // enum validation
155
+ if (
156
+ data_value !== undefined &&
157
+ data_value !== null &&
158
+ allowed &&
159
+ !allowed.includes(data_value)
160
+ ) {
161
+ return {
162
+ ok: false,
163
+ message: `Field '${prop}' must be one of: ${allowed.join(", ")}`,
164
+ };
165
+ }
166
+
114
167
  return { ok: true };
115
168
  };
116
169
 
117
170
  validate = async (schema, data) => {
118
- let { body: schema_body } = schema;
119
- let { body: data_body } = data;
120
-
121
- for (let prop in schema_body) {
122
- let rule = schema_body[prop];
123
-
124
- if (prop === "$logic") {
125
- let or_logic = rule.or;
126
- if (or_logic) {
127
- for (let o = 0; o < or_logic.length; o++) {
128
- let or_rule = or_logic[o],
129
- or_rule_check;
130
-
131
- for (let proper of or_rule.properties) {
132
- or_rule_check = await this.check_validation(
133
- { prop: proper, ...or_rule },
134
- data_body,
135
- );
136
-
137
- if (or_rule_check?.ok) break;
138
- }
139
- if (or_rule.required && !or_rule_check?.ok) {
140
- return {
141
- ok: false,
142
- message: `At least one of the following fields is required: ${or_rule.properties.join(
143
- ", ",
144
- )}`,
145
- };
146
- }
147
- }
148
- }
149
-
150
- let and_logic = rule.and;
151
- if (and_logic) {
152
- for (let a = 0; a < and_logic.length; a++) {
153
- let and_rule = and_logic[a];
154
-
155
- for (let prop of and_rule.properties) {
156
- let and_rule_check = await this.check_validation(
157
- { prop, ...and_rule },
158
- data_body,
159
- );
171
+ for (const section of Object.keys(schema)) {
172
+ const rules = schema[section];
173
+ const target = data[section] || {};
174
+
175
+ for (const prop in rules) {
176
+ const rule = rules[prop];
177
+
178
+ if (prop === "$logic") {
179
+ // OR logic
180
+ if (rule.or) {
181
+ for (const orRule of rule.or) {
182
+ let passed = false;
183
+
184
+ for (const property of orRule.properties) {
185
+ const result = await this.check_validation(
186
+ { prop: property, ...orRule },
187
+ target,
188
+ );
189
+
190
+ if (result.ok) {
191
+ passed = true;
192
+ break;
193
+ }
194
+ }
160
195
 
161
- if (and_rule.required && !and_rule_check?.ok) {
196
+ if (orRule.required && !passed) {
162
197
  return {
163
198
  ok: false,
164
- message: `Field '${prop}' is required`,
199
+ message: `At least one of the following fields is required: ${orRule.properties.join(
200
+ ", ",
201
+ )}`,
165
202
  };
166
203
  }
167
204
  }
168
205
  }
206
+
207
+ // AND logic
208
+ if (rule.and) {
209
+ for (const andRule of rule.and) {
210
+ for (const property of andRule.properties) {
211
+ const result = await this.check_validation(
212
+ { prop: property, ...andRule },
213
+ target,
214
+ );
215
+
216
+ if (!result.ok) {
217
+ return result;
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ continue;
169
224
  }
170
- }
171
225
 
172
- let validation_result = await this.check_validation(
173
- { prop, ...rule },
174
- data_body,
175
- );
226
+ const result = await this.check_validation({ prop, ...rule }, target);
176
227
 
177
- if (!validation_result.ok) {
178
- return validation_result;
228
+ if (!result.ok) {
229
+ return result;
230
+ }
179
231
  }
180
232
  }
181
233
 
@@ -34,6 +34,7 @@ class Services {
34
34
  constructor() {
35
35
  this.services = new Object();
36
36
 
37
+ this.db_prefixes = new Object();
37
38
  this.load_services(gp_services);
38
39
  }
39
40
 
@@ -46,18 +47,14 @@ class Services {
46
47
  get_token = async (service, id) => {
47
48
  let token;
48
49
 
49
- // debug(service, id, "gettok");
50
50
  let db = await this.platform_db();
51
51
  token = await db.read_cache(
52
52
  { platform_uri: service.uri, id: id.profile },
53
53
  "token",
54
54
  );
55
55
 
56
- // debug(token, "in-cache");
57
56
  if (token) return token.token;
58
57
  try {
59
- // debug(this.api_key, gp_services.profile);
60
-
61
58
  let gp_profile = gp_services().profile;
62
59
  let ftch = await fetch(`${gp_profile.url}/get_token`, {
63
60
  method: "POST",
@@ -70,9 +67,7 @@ class Services {
70
67
  body: JSON.stringify({ platform_uri: service.uri, ...id }),
71
68
  });
72
69
 
73
- // debug("whats it like??");
74
70
  token = await ftch.json();
75
- // debug(token, "HOOWWW");
76
71
 
77
72
  if (token?.ok) {
78
73
  await db.save_cache(
@@ -100,6 +95,7 @@ class Services {
100
95
  if (!servic) return;
101
96
 
102
97
  return {
98
+ uri: servic.uri,
103
99
  call: async (path, body, header) => {
104
100
  let headers = {
105
101
  "Content-Type": "application/json",
@@ -107,7 +103,9 @@ class Services {
107
103
  "x-api-version": servic.api_version || "v1",
108
104
  };
109
105
  let token;
110
- if (header?.token || header?.profile) {
106
+ if (servic.profile_key) {
107
+ headers["Authorization"] = `${servic.profile_key}`;
108
+ } else if (header?.token || header?.profile) {
111
109
  if (header.token) {
112
110
  token = header.token;
113
111
  } else if (header.profile) {
@@ -156,11 +154,26 @@ class Services {
156
154
  };
157
155
 
158
156
  platform_db = async () => {
159
- if (this.db) return this.db;
160
-
161
- this.db = new DB(this.db_config, this);
157
+ let prefix = this.db_prefix;
158
+ let db;
159
+ if (prefix) {
160
+ db = this.db_prefixes[prefix];
161
+ if (!db) {
162
+ let conf = { ...this.db_config };
163
+ conf.name = `${prefix}:${this.db_config.name}`;
164
+
165
+ db = new DB(conf, this);
166
+ this.db_prefixes[prefix] = db;
167
+ }
168
+ } else {
169
+ db = this.db;
170
+ if (!db) {
171
+ db = new DB(this.db_config, this);
172
+ this.db = db;
173
+ }
174
+ }
162
175
 
163
- return this.db;
176
+ return db;
164
177
  };
165
178
 
166
179
  handle_webhook_prior = async (req) => {
@@ -35,6 +35,7 @@ const applyCors = (req, res) => {
35
35
  res.setHeader(
36
36
  "Access-Control-Allow-Headers",
37
37
  "Content-Type, Authorization, x-api-version, x-api-key, x-platform",
38
+ "x-secret",
38
39
  );
39
40
 
40
41
  // IMPORTANT: do NOT enable credentials with "*"
@@ -75,6 +76,10 @@ const respond = (result, res) => {
75
76
  response.token = result.token;
76
77
  }
77
78
 
79
+ if (result?.next) {
80
+ response.next = result.next;
81
+ }
82
+
78
83
  const status = result?.status || (result?.ok ? 200 : 403);
79
84
 
80
85
  res.statusCode = status;