@cocreate/api 1.29.0 → 1.31.0

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.
Files changed (2) hide show
  1. package/package.json +8 -8
  2. package/src/server.js +51 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/api",
3
- "version": "1.29.0",
3
+ "version": "1.31.0",
4
4
  "description": "A secure, multi-tenant API execution gateway and proxy layer that dynamically resolves endpoint actions, processes AST micro-operators, handles webhooks, and manages third-party integrations with strict tenant environment isolation.",
5
5
  "keywords": [
6
6
  "api-orchestration",
@@ -51,15 +51,15 @@
51
51
  }
52
52
  },
53
53
  "dependencies": {
54
- "@cocreate/actions": "^1.23.0",
55
- "@cocreate/crud-client": "^1.36.0",
56
- "@cocreate/element-prototype": "^1.34.0",
57
- "@cocreate/render": "^1.49.2",
58
- "@cocreate/socket-client": "^1.42.0",
59
- "@cocreate/utils": "^1.50.3"
54
+ "@cocreate/actions": "^1.24.0",
55
+ "@cocreate/crud-client": "^1.36.1",
56
+ "@cocreate/element-prototype": "^1.35.0",
57
+ "@cocreate/render": "^1.50.0",
58
+ "@cocreate/socket-client": "^1.42.1",
59
+ "@cocreate/utils": "^1.52.0"
60
60
  },
61
61
  "devDependencies": {
62
- "@cocreate/webpack": "^1.7.0"
62
+ "@cocreate/webpack": "^1.8.0"
63
63
  },
64
64
  "allowScripts": {
65
65
  "@cocreate/actions@1.21.4": true,
package/src/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (C) 2023 CoCreate and Contributors.
2
+ * Copyright (C) 2023-2026 CoCreate and Contributors.
3
3
  *
4
4
  * This program is free software: you can redistribute it and/or modify
5
5
  * it under the terms of the GNU Affero General Public License as published
@@ -13,16 +13,10 @@
13
13
  *
14
14
  * You should have received a copy of the GNU Affero General Public License
15
15
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
- *
17
16
  ********************************************************************************/
18
17
 
19
- // Commercial Licensing Information:
20
- // For commercial use of this software without the copyleft provisions of the AGPLv3,
21
- // you must obtain a commercial license from CoCreate LLC.
22
- // For details, visit <https://cocreate.app/licenses/> or contact us at sales@cocreate.app.
23
-
24
18
  import { URL } from 'node:url';
25
- import { getValueFromObject, objectToSearchParams, astAsync, generateJWT, verifySignature, buildAuthHeaders } from '@cocreate/utils';
19
+ import { getValueFromObject, objectToSearchParams, astAsync, security } from '@cocreate/utils';
26
20
 
27
21
  // Core module references bound dynamically upon initialization
28
22
  let server = null;
@@ -33,13 +27,17 @@ const API = {
33
27
  init,
34
28
  executeApi,
35
29
  request,
36
- generateJWT,
37
- verifySignature,
30
+ security,
38
31
  makeHttpRequest,
39
32
  getApiConfig,
40
33
  normalizeConfig
41
34
  };
42
35
 
36
+ /**
37
+ * Binds server core services and registers WebSocket event handlers.
38
+ * @param {Object} Server - Server core instance containing wsManager and crud
39
+ * @returns {Object} Exported API service interface
40
+ */
43
41
  export async function init(Server) {
44
42
  server = Server;
45
43
  wsManager = server.wsManager;
@@ -56,6 +54,12 @@ export async function init(Server) {
56
54
  return API;
57
55
  }
58
56
 
57
+ /**
58
+ * Normalizes raw API configuration structures into a uniform key/url/headers shape.
59
+ * @param {string|Object} apiConfig - Raw configuration object or API key string
60
+ * @param {string} name - Provider identifier
61
+ * @returns {Object} Standardized configuration container
62
+ */
59
63
  export function normalizeConfig(apiConfig, name) {
60
64
  let key = null;
61
65
  let url = null;
@@ -85,11 +89,12 @@ export function normalizeConfig(apiConfig, name) {
85
89
  }
86
90
 
87
91
  /**
88
- * Builds a secure sandboxed execution context for evaluateAST.
89
- * Inherits native globals from AST parser automatically, only injecting runtime-specific scopes.
92
+ * Constructs an isolated execution sandbox enforcing multi-tenant isolation via Proxy firewalls.
93
+ * @param {Object} context - Execution context containing organization, host, data, and request info
94
+ * @returns {Object} Secure sandbox context for AST execution
90
95
  */
91
96
  function createSandbox(context) {
92
- // SECURITY FIREWALL: Automatically proxy local system database calls to seal tenant-isolated metadata.
97
+ // SECURITY FIREWALL: Proxy database calls to enforce multi-tenant isolation.
93
98
  const secureCrud = context.crud ? new Proxy(context.crud, {
94
99
  get(target, prop) {
95
100
  const original = target[prop];
@@ -111,6 +116,7 @@ function createSandbox(context) {
111
116
  }
112
117
  }) : undefined;
113
118
 
119
+ // SECURITY FIREWALL: Proxy WebSocket manager calls for multi-tenant isolation.
114
120
  const secureWsManager = context.wsManager ? new Proxy(context.wsManager, {
115
121
  get(target, prop) {
116
122
  const original = target[prop];
@@ -148,6 +154,9 @@ function createSandbox(context) {
148
154
  socket: secureWsManager,
149
155
  wsManager: secureWsManager,
150
156
 
157
+ // Security Utility Instance
158
+ security,
159
+
151
160
  // Host Context Identifiers
152
161
  key: context.key,
153
162
  config: context.config,
@@ -159,11 +168,6 @@ function createSandbox(context) {
159
168
  send: async (apiData) => {
160
169
  return await executeApi(apiData, context);
161
170
  }
162
- },
163
- jwt: (args) => {
164
- const privateKey = args?.privateKey || args?.secret;
165
- if (!privateKey) throw new Error("Missing cryptographic signing key inside $jwt context parameters");
166
- return generateJWT(args, privateKey, args.alg || 'HS256');
167
171
  }
168
172
  };
169
173
 
@@ -175,6 +179,12 @@ function createSandbox(context) {
175
179
  return sandbox;
176
180
  }
177
181
 
182
+ /**
183
+ * Resolves endpoint definitions, executes AST macros, or dispatches HTTP requests.
184
+ * @param {Object} data - API execution payload containing directives
185
+ * @param {Object} [parentContext=null] - Optional outer sandbox execution context
186
+ * @returns {Promise<any>} Execution response payload
187
+ */
178
188
  export async function executeApi(data, parentContext = null) {
179
189
  try {
180
190
  const orgId = parentContext?.organization_id || data.socket?.organization_id || data.organization_id;
@@ -267,7 +277,6 @@ export async function executeApi(data, parentContext = null) {
267
277
  return;
268
278
  }
269
279
 
270
- // --- Standard Outbound Construction Path ---
271
280
  if (!apiConfig.url) {
272
281
  throw new Error(`Configuration missing 'url' base for provider '${providerName}'.`);
273
282
  }
@@ -322,6 +331,11 @@ export async function executeApi(data, parentContext = null) {
322
331
  }
323
332
  }
324
333
 
334
+ /**
335
+ * Processes incoming HTTP webhook requests, validates security signatures, and executes pipelines.
336
+ * @param {Object} req - HTTP request object
337
+ * @param {Object} res - HTTP response object
338
+ */
325
339
  export async function request(req, res) {
326
340
  try {
327
341
  const urlObject = new URL(`http://${req.headers.host}${req.url}`);
@@ -400,7 +414,10 @@ export async function request(req, res) {
400
414
  const signature = resolvedParams[1];
401
415
  const secret = resolvedParams[2];
402
416
 
403
- if (!verifySignature(payload, signature, secret, "sha256")) {
417
+ const computedSignature = security.createWebhookSignature(payload, secret, { format: 'github' });
418
+ const expectedSignature = String(signature);
419
+
420
+ if (!security.timingSafeEqual(computedSignature, expectedSignature)) {
404
421
  res.writeHead(401, { "Content-Type": "application/json" });
405
422
  return res.end(JSON.stringify({ error: "Unauthorized access: signature verification failed." }));
406
423
  }
@@ -448,9 +465,15 @@ export async function request(req, res) {
448
465
  }
449
466
  }
450
467
 
451
- // Unified re-exports from security helper module to prevent duplicate function definitions
452
- export { generateJWT, verifySignature, buildAuthHeaders };
468
+ // Re-export security library instance
469
+ export { security };
453
470
 
471
+ /**
472
+ * Low-level HTTP dispatch utility wrapping global fetch with AbortController timeout handling.
473
+ * @param {string} url - Target URL endpoint
474
+ * @param {Object} options - Fetch options (method, headers, body, signal, timeout)
475
+ * @returns {Promise<Response>} Native fetch response instance
476
+ */
454
477
  export async function makeHttpRequest(url, options) {
455
478
  let controller, timeoutId;
456
479
  if (global.AbortController) {
@@ -485,6 +508,12 @@ export async function makeHttpRequest(url, options) {
485
508
  }
486
509
  }
487
510
 
511
+ /**
512
+ * Queries database storage for provider connection credentials and API configuration.
513
+ * @param {Object} data - Context query parameters (organization_id, host)
514
+ * @param {string} name - API provider name
515
+ * @returns {Promise<Object>} API provider configuration object
516
+ */
488
517
  export async function getApiConfig(data, name) {
489
518
  let orgId = data.organization_id;
490
519
  let host = data.host;