@objectstack/runtime 3.1.0 → 3.2.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @objectstack/runtime@3.1.0 build /home/runner/work/spec/spec/packages/runtime
2
+ > @objectstack/runtime@3.2.0 build /home/runner/work/spec/spec/packages/runtime
3
3
  > tsup --config ../../tsup.config.ts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -12,11 +12,11 @@
12
12
  CJS Build start
13
13
  ESM dist/index.js 55.51 KB
14
14
  ESM dist/index.js.map 123.66 KB
15
- ESM ⚡️ Build success in 166ms
15
+ ESM ⚡️ Build success in 91ms
16
16
  CJS dist/index.cjs 57.43 KB
17
17
  CJS dist/index.cjs.map 123.73 KB
18
- CJS ⚡️ Build success in 166ms
18
+ CJS ⚡️ Build success in 92ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 6928ms
20
+ DTS ⚡️ Build success in 8046ms
21
21
  DTS dist/index.d.ts 20.64 KB
22
22
  DTS dist/index.d.cts 20.64 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @objectstack/runtime
2
2
 
3
+ ## 3.2.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [5901c29]
8
+ - @objectstack/spec@3.2.0
9
+ - @objectstack/core@3.2.0
10
+ - @objectstack/rest@3.2.0
11
+ - @objectstack/types@3.2.0
12
+
13
+ ## 3.1.1
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [953d667]
18
+ - @objectstack/spec@3.1.1
19
+ - @objectstack/core@3.1.1
20
+ - @objectstack/rest@3.1.1
21
+ - @objectstack/types@3.1.1
22
+
3
23
  ## 3.1.0
4
24
 
5
25
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/runtime",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "ObjectStack Core Runtime & Query Engine",
6
6
  "type": "module",
@@ -15,10 +15,10 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "zod": "^4.3.6",
18
- "@objectstack/core": "3.1.0",
19
- "@objectstack/rest": "3.1.0",
20
- "@objectstack/spec": "3.1.0",
21
- "@objectstack/types": "3.1.0"
18
+ "@objectstack/core": "3.2.0",
19
+ "@objectstack/rest": "3.2.0",
20
+ "@objectstack/spec": "3.2.0",
21
+ "@objectstack/types": "3.2.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "typescript": "^5.0.0",
@@ -439,6 +439,101 @@ describe('HttpDispatcher', () => {
439
439
  });
440
440
  });
441
441
 
442
+ // ═══════════════════════════════════════════════════════════════
443
+ // handleData — expand/populate parameter flow
444
+ // ═══════════════════════════════════════════════════════════════
445
+
446
+ describe('handleData', () => {
447
+ it('should pass expand and select to broker for GET /data/:object/:id', async () => {
448
+ mockBroker.call.mockResolvedValue({ object: 'order_item', id: 'oi_1', record: { _id: 'oi_1' } });
449
+
450
+ const result = await dispatcher.handleData(
451
+ '/order_item/oi_1', 'GET', {},
452
+ { expand: 'order,product', select: 'name,total' },
453
+ { request: {} }
454
+ );
455
+
456
+ expect(result.handled).toBe(true);
457
+ expect(result.response?.status).toBe(200);
458
+ expect(mockBroker.call).toHaveBeenCalledWith(
459
+ 'data.get',
460
+ { object: 'order_item', id: 'oi_1', expand: 'order,product', select: 'name,total' },
461
+ { request: {} }
462
+ );
463
+ });
464
+
465
+ it('should NOT pass non-allowlisted params for GET /data/:object/:id', async () => {
466
+ mockBroker.call.mockResolvedValue({ object: 'task', id: 't1', record: {} });
467
+
468
+ await dispatcher.handleData(
469
+ '/task/t1', 'GET', {},
470
+ { expand: 'assignee', malicious: 'drop_table', filter: 'hack' },
471
+ { request: {} }
472
+ );
473
+
474
+ // Only expand is passed; malicious and filter are dropped
475
+ expect(mockBroker.call).toHaveBeenCalledWith(
476
+ 'data.get',
477
+ { object: 'task', id: 't1', expand: 'assignee' },
478
+ { request: {} }
479
+ );
480
+ });
481
+
482
+ it('should pass full query (with expand/populate) for GET /data/:object list', async () => {
483
+ mockBroker.call.mockResolvedValue({ object: 'task', records: [], total: 0 });
484
+
485
+ const query = { populate: 'assignee,project', top: '10', skip: '0' };
486
+ const result = await dispatcher.handleData(
487
+ '/task', 'GET', {},
488
+ query,
489
+ { request: {} }
490
+ );
491
+
492
+ expect(result.handled).toBe(true);
493
+ expect(mockBroker.call).toHaveBeenCalledWith(
494
+ 'data.query',
495
+ { object: 'task', query },
496
+ { request: {} }
497
+ );
498
+ });
499
+
500
+ it('should pass expand in query for GET /data/:object list', async () => {
501
+ mockBroker.call.mockResolvedValue({ object: 'order', records: [], total: 0 });
502
+
503
+ const query = { expand: 'customer,products' };
504
+ await dispatcher.handleData('/order', 'GET', {}, query, { request: {} });
505
+
506
+ expect(mockBroker.call).toHaveBeenCalledWith(
507
+ 'data.query',
508
+ { object: 'order', query: { expand: 'customer,products' } },
509
+ { request: {} }
510
+ );
511
+ });
512
+
513
+ it('should return error if object name is missing', async () => {
514
+ const result = await dispatcher.handleData('/', 'GET', {}, {}, { request: {} });
515
+ expect(result.handled).toBe(true);
516
+ expect(result.response?.status).toBe(400);
517
+ });
518
+
519
+ it('should handle POST /data/:object/query with body containing expand', async () => {
520
+ mockBroker.call.mockResolvedValue({ object: 'task', records: [] });
521
+
522
+ await dispatcher.handleData(
523
+ '/task/query', 'POST',
524
+ { filter: { status: 'active' }, populate: ['assignee'] },
525
+ {},
526
+ { request: {} }
527
+ );
528
+
529
+ expect(mockBroker.call).toHaveBeenCalledWith(
530
+ 'data.query',
531
+ { object: 'task', filter: { status: 'active' }, populate: ['assignee'] },
532
+ { request: {} }
533
+ );
534
+ });
535
+ });
536
+
442
537
  // ═══════════════════════════════════════════════════════════════
443
538
  // Error handling for service method failures
444
539
  // ═══════════════════════════════════════════════════════════════