godprotocol 2.3.15 → 2.3.17

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.17",
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,17 @@ 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_name = ver.config?.db_name === true ? version : ver.config?.db_name;
31
+
32
+ this.db_prefix =
33
+ ver.config?.db_prefix === true ? version : ver.config?.db_prefix;
34
+
30
35
  return ver;
31
36
  };
32
37
 
@@ -74,10 +79,12 @@ class Route_table extends Headers {
74
79
  return route;
75
80
  };
76
81
 
82
+ getValue = (obj, path) => path.split(".").reduce((o, key) => o?.[key], obj);
83
+
77
84
  check_validation = async (rule, data) => {
78
- let { prop, type, required } = rule;
85
+ let { prop, type, required, enum: allowed } = rule;
79
86
 
80
- let data_value = data[prop];
87
+ let data_value = this.getValue(data, prop);
81
88
 
82
89
  if (data_value === undefined && rule.hasOwnProperty("default_value")) {
83
90
  data_value = rule.default_value;
@@ -90,92 +97,139 @@ class Route_table extends Headers {
90
97
  ok: false,
91
98
  message: `Field '${prop}' is required`,
92
99
  };
93
- } else {
94
- return { ok: true };
95
100
  }
101
+ return { ok: true };
96
102
  }
97
103
 
104
+ // type validation
105
+ // =========================
106
+ // Type validation
107
+ // =========================
108
+
98
109
  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)
110
+ let descriptor = type;
111
+
112
+ // Logical schemas may provide a map:
113
+ // type: {
114
+ // intervals: { value: "array", min: 1 },
115
+ // throttle: { value: "number", min: 1000 }
116
+ // }
117
+ if (typeof type === "object" && !Array.isArray(type)) {
118
+ descriptor = type[prop];
119
+
120
+ // No type rule for this property
121
+ if (!descriptor) {
122
+ descriptor = null;
123
+ }
124
+ }
125
+
126
+ if (descriptor) {
127
+ // Allow shorthand:
128
+ // "string"
129
+ // or
130
+ // { value: "string", ... }
131
+ if (typeof descriptor === "string") {
132
+ descriptor = {
133
+ value: descriptor,
134
+ };
135
+ }
136
+
137
+ const expected = descriptor.value;
138
+
139
+ let actual;
140
+
141
+ if (expected === "array") {
142
+ actual = Array.isArray(data_value) ? "array" : typeof data_value;
143
+ } else {
144
+ actual = typeof data_value;
145
+ }
146
+
147
+ if (actual !== expected) {
107
148
  return {
108
149
  ok: false,
109
- message: `Field '${prop}' must be of type '${type}' got '${type_of}'`,
150
+ message: `Field '${prop}' must be of type '${expected}', got '${actual}'`,
110
151
  };
152
+ }
111
153
  }
112
154
  }
113
155
 
156
+ // enum validation
157
+ if (
158
+ data_value !== undefined &&
159
+ data_value !== null &&
160
+ allowed &&
161
+ !allowed.includes(data_value)
162
+ ) {
163
+ return {
164
+ ok: false,
165
+ message: `Field '${prop}' must be one of: ${allowed.join(", ")}`,
166
+ };
167
+ }
168
+
114
169
  return { ok: true };
115
170
  };
116
171
 
117
172
  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
- );
173
+ for (const section of Object.keys(schema)) {
174
+ const rules = schema[section];
175
+ const target = data[section] || {};
176
+
177
+ for (const prop in rules) {
178
+ const rule = rules[prop];
179
+
180
+ if (prop === "$logic") {
181
+ // OR logic
182
+ if (rule.or) {
183
+ for (const orRule of rule.or) {
184
+ let passed = false;
185
+
186
+ for (const property of orRule.properties) {
187
+ const result = await this.check_validation(
188
+ { prop: property, ...orRule },
189
+ target,
190
+ );
191
+
192
+ if (result.ok) {
193
+ passed = true;
194
+ break;
195
+ }
196
+ }
160
197
 
161
- if (and_rule.required && !and_rule_check?.ok) {
198
+ if (orRule.required && !passed) {
162
199
  return {
163
200
  ok: false,
164
- message: `Field '${prop}' is required`,
201
+ message: `At least one of the following fields is required: ${orRule.properties.join(
202
+ ", ",
203
+ )}`,
165
204
  };
166
205
  }
167
206
  }
168
207
  }
208
+
209
+ // AND logic
210
+ if (rule.and) {
211
+ for (const andRule of rule.and) {
212
+ for (const property of andRule.properties) {
213
+ const result = await this.check_validation(
214
+ { prop: property, ...andRule },
215
+ target,
216
+ );
217
+
218
+ if (!result.ok) {
219
+ return result;
220
+ }
221
+ }
222
+ }
223
+ }
224
+
225
+ continue;
169
226
  }
170
- }
171
227
 
172
- let validation_result = await this.check_validation(
173
- { prop, ...rule },
174
- data_body,
175
- );
228
+ const result = await this.check_validation({ prop, ...rule }, target);
176
229
 
177
- if (!validation_result.ok) {
178
- return validation_result;
230
+ if (!result.ok) {
231
+ return result;
232
+ }
179
233
  }
180
234
  }
181
235
 
@@ -34,6 +34,7 @@ class Services {
34
34
  constructor() {
35
35
  this.services = new Object();
36
36
 
37
+ this.dbs = 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,21 @@ class Services {
156
154
  };
157
155
 
158
156
  platform_db = async () => {
159
- if (this.db) return this.db;
157
+ let prefix = this.db_prefix,
158
+ name = this.db_name || this.db_config.name;
159
+
160
+ if (prefix) {
161
+ name = `${prefix}:${name}`;
162
+ }
160
163
 
161
- this.db = new DB(this.db_config, this);
164
+ let db = this.dbs[name];
165
+ if (!db) {
166
+ db = new DB({ ...this.db_config, name }, this);
167
+
168
+ this.dbs[name] = db;
169
+ }
162
170
 
163
- return this.db;
171
+ return db;
164
172
  };
165
173
 
166
174
  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;