@objectstack/runtime 3.1.1 → 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.1 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
@@ -10,13 +10,13 @@
10
10
  CLI Cleaning output folder
11
11
  ESM Build start
12
12
  CJS Build start
13
- CJS dist/index.cjs 57.43 KB
14
- CJS dist/index.cjs.map 123.73 KB
15
- CJS ⚡️ Build success in 149ms
16
13
  ESM dist/index.js 55.51 KB
17
14
  ESM dist/index.js.map 123.66 KB
18
- ESM ⚡️ Build success in 167ms
15
+ ESM ⚡️ Build success in 91ms
16
+ CJS dist/index.cjs 57.43 KB
17
+ CJS dist/index.cjs.map 123.73 KB
18
+ CJS ⚡️ Build success in 92ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 7492ms
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,15 @@
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
+
3
13
  ## 3.1.1
4
14
 
5
15
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/runtime",
3
- "version": "3.1.1",
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.1",
19
- "@objectstack/rest": "3.1.1",
20
- "@objectstack/spec": "3.1.1",
21
- "@objectstack/types": "3.1.1"
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
  // ═══════════════════════════════════════════════════════════════