@cratis/arc 20.10.1 → 20.10.3

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 (23) hide show
  1. package/dist/cjs/queries/ObservableQueryFor.d.ts.map +1 -1
  2. package/dist/cjs/queries/ObservableQueryFor.js +1 -2
  3. package/dist/cjs/queries/ObservableQueryFor.js.map +1 -1
  4. package/dist/cjs/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_multiple_required_route_parameters.d.ts +2 -0
  5. package/dist/cjs/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_multiple_required_route_parameters.d.ts.map +1 -0
  6. package/dist/cjs/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_stale_descriptor_backed_instance_property.d.ts +2 -0
  7. package/dist/cjs/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_stale_descriptor_backed_instance_property.d.ts.map +1 -0
  8. package/dist/esm/queries/ObservableQueryFor.d.ts.map +1 -1
  9. package/dist/esm/queries/ObservableQueryFor.js +1 -2
  10. package/dist/esm/queries/ObservableQueryFor.js.map +1 -1
  11. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_multiple_required_route_parameters.d.ts +2 -0
  12. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_multiple_required_route_parameters.d.ts.map +1 -0
  13. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_multiple_required_route_parameters.js +72 -0
  14. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_multiple_required_route_parameters.js.map +1 -0
  15. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_stale_descriptor_backed_instance_property.d.ts +2 -0
  16. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_stale_descriptor_backed_instance_property.d.ts.map +1 -0
  17. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_stale_descriptor_backed_instance_property.js +74 -0
  18. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_stale_descriptor_backed_instance_property.js.map +1 -0
  19. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  20. package/package.json +1 -1
  21. package/queries/ObservableQueryFor.ts +9 -4
  22. package/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_multiple_required_route_parameters.ts +93 -0
  23. package/queries/for_ObservableQueryFor/when_subscribing/with_hub_mode_and_stale_descriptor_backed_instance_property.ts +99 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cratis/arc",
3
- "version": "20.10.1",
3
+ "version": "20.10.3",
4
4
  "description": "",
5
5
  "author": "Cratis",
6
6
  "license": "MIT",
@@ -103,14 +103,19 @@ export abstract class ObservableQueryFor<TDataType, TParameters = object> implem
103
103
  });
104
104
  }
105
105
 
106
- // For multiplexed mode, include route arguments as plain arguments in the subscribe payload.
107
- // In direct mode, route arguments are already part of the URL path and should not be duplicated.
106
+ // Descriptor-backed instance properties provide defaults; fresh args passed to subscribe()
107
+ // must take precedence over any stale instance property values. Spread parameterValues
108
+ // first so that the caller-supplied args can override them.
109
+ //
110
+ // In direct mode the route arguments are already embedded in the URL path, so only
111
+ // the unused (non-route) parameters are appended as additional query arguments.
112
+ // In multiplexed mode ALL arguments — including route-derived ones — must be included
113
+ // in the subscribe payload so the server can execute the query correctly.
108
114
  const parameterValues = ParametersHelper.collectParameterValues(this);
109
115
  const { unusedParameters } = UrlHelpers.replaceRouteParameters(this.route, args as object);
110
- const routeAndQueryArguments = (args as object) || {};
111
116
  const connectionQueryArguments: any = {
112
- ...(Globals.queryDirectMode ? unusedParameters : routeAndQueryArguments),
113
117
  ...parameterValues,
118
+ ...(Globals.queryDirectMode ? unusedParameters : (args as object) || {}),
114
119
  ...this.buildQueryArguments()
115
120
  };
116
121
 
@@ -0,0 +1,93 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { an_observable_query_for } from '../given/an_observable_query_for';
5
+ import { given } from '../../../given';
6
+ import { Globals } from '../../../Globals';
7
+ import { QueryTransportMethod } from '../../QueryTransportMethod';
8
+ import { ObservableQuerySubscription } from '../../ObservableQuerySubscription';
9
+ import { HubMessageType } from '../../WebSocketHubConnection';
10
+ import { resetSharedMultiplexer } from '../../ObservableQueryMultiplexer';
11
+
12
+ import * as sinon from 'sinon';
13
+
14
+ describe('when subscribing with hub mode and multiple required route parameters', given(an_observable_query_for, context => {
15
+ let callback: sinon.SinonStub;
16
+ let subscription: ObservableQuerySubscription<string>;
17
+ let fetchStub: sinon.SinonStub;
18
+ let originalQueryDirectMode: boolean;
19
+ let originalTransportMethod: QueryTransportMethod;
20
+ let eventSourceInstance: EventSource & {
21
+ onopen: (() => void) | null;
22
+ onmessage: ((event: { data: string }) => void) | null;
23
+ };
24
+
25
+ beforeEach(() => {
26
+ originalQueryDirectMode = Globals.queryDirectMode;
27
+ originalTransportMethod = Globals.queryTransportMethod;
28
+ resetSharedMultiplexer();
29
+
30
+ Globals.queryDirectMode = false;
31
+ Globals.queryTransportMethod = QueryTransportMethod.ServerSentEvents;
32
+
33
+ context.queryWithMultipleRequiredParameters.setOrigin('https://example.com');
34
+ callback = sinon.stub();
35
+
36
+ const FakeEventSourceConstructor = function (this: EventSource, url: string) {
37
+ void url;
38
+ eventSourceInstance = this as EventSource & {
39
+ onopen: (() => void) | null;
40
+ onmessage: ((event: { data: string }) => void) | null;
41
+ };
42
+ Object.assign(this, {
43
+ onopen: null,
44
+ onerror: null,
45
+ onmessage: null,
46
+ close: sinon.stub(),
47
+ addEventListener: sinon.stub(),
48
+ removeEventListener: sinon.stub(),
49
+ readyState: 0,
50
+ });
51
+ };
52
+ (globalThis as Record<string, unknown>)['EventSource'] = FakeEventSourceConstructor;
53
+
54
+ fetchStub = sinon.stub().resolves({ ok: true } as Response);
55
+ (globalThis as Record<string, unknown>)['fetch'] = fetchStub;
56
+
57
+ subscription = context.queryWithMultipleRequiredParameters.subscribe(callback, {
58
+ userId: 'user-42',
59
+ category: 'books'
60
+ });
61
+
62
+ eventSourceInstance.onopen?.();
63
+ eventSourceInstance.onmessage?.({
64
+ data: JSON.stringify({
65
+ type: HubMessageType.Connected,
66
+ payload: 'conn-1'
67
+ })
68
+ });
69
+ });
70
+
71
+ afterEach(() => {
72
+ Globals.queryDirectMode = originalQueryDirectMode;
73
+ Globals.queryTransportMethod = originalTransportMethod;
74
+ if (subscription) {
75
+ subscription.unsubscribe();
76
+ }
77
+ delete (globalThis as Record<string, unknown>)['EventSource'];
78
+ delete (globalThis as Record<string, unknown>)['fetch'];
79
+ resetSharedMultiplexer();
80
+ sinon.restore();
81
+ });
82
+
83
+ it('should include the first route parameter in the subscribe request', () => {
84
+ fetchStub.called.should.be.true;
85
+ const subscribeBody = JSON.parse(fetchStub.firstCall.args[1].body as string);
86
+ subscribeBody.request.arguments.userId.should.equal('user-42');
87
+ });
88
+
89
+ it('should include the second route parameter in the subscribe request', () => {
90
+ const subscribeBody = JSON.parse(fetchStub.firstCall.args[1].body as string);
91
+ subscribeBody.request.arguments.category.should.equal('books');
92
+ });
93
+ }));
@@ -0,0 +1,99 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { an_observable_query_for } from '../given/an_observable_query_for';
5
+ import { given } from '../../../given';
6
+ import { Globals } from '../../../Globals';
7
+ import { QueryTransportMethod } from '../../QueryTransportMethod';
8
+ import { ObservableQuerySubscription } from '../../ObservableQuerySubscription';
9
+ import { HubMessageType } from '../../WebSocketHubConnection';
10
+ import { resetSharedMultiplexer } from '../../ObservableQueryMultiplexer';
11
+
12
+ import * as sinon from 'sinon';
13
+
14
+ describe('when subscribing with hub mode and stale descriptor-backed instance property', given(an_observable_query_for, context => {
15
+ let callback: sinon.SinonStub;
16
+ let subscription: ObservableQuerySubscription<string>;
17
+ let fetchStub: sinon.SinonStub;
18
+ let originalQueryDirectMode: boolean;
19
+ let originalTransportMethod: QueryTransportMethod;
20
+ let eventSourceInstance: EventSource & {
21
+ onopen: (() => void) | null;
22
+ onmessage: ((event: { data: string }) => void) | null;
23
+ };
24
+
25
+ beforeEach(() => {
26
+ originalQueryDirectMode = Globals.queryDirectMode;
27
+ originalTransportMethod = Globals.queryTransportMethod;
28
+ resetSharedMultiplexer();
29
+
30
+ Globals.queryDirectMode = false;
31
+ Globals.queryTransportMethod = QueryTransportMethod.ServerSentEvents;
32
+
33
+ context.queryWithParameterDescriptorValues.setOrigin('https://example.com');
34
+ callback = sinon.stub();
35
+
36
+ // Simulate stale values on the descriptor-backed instance properties — these must be
37
+ // overridden by the fresh args passed to subscribe().
38
+ context.queryWithParameterDescriptorValues.filter = 'stale-filter';
39
+ context.queryWithParameterDescriptorValues.limit = 99;
40
+
41
+ const FakeEventSourceConstructor = function (this: EventSource, url: string) {
42
+ void url;
43
+ eventSourceInstance = this as EventSource & {
44
+ onopen: (() => void) | null;
45
+ onmessage: ((event: { data: string }) => void) | null;
46
+ };
47
+ Object.assign(this, {
48
+ onopen: null,
49
+ onerror: null,
50
+ onmessage: null,
51
+ close: sinon.stub(),
52
+ addEventListener: sinon.stub(),
53
+ removeEventListener: sinon.stub(),
54
+ readyState: 0,
55
+ });
56
+ };
57
+ (globalThis as Record<string, unknown>)['EventSource'] = FakeEventSourceConstructor;
58
+
59
+ fetchStub = sinon.stub().resolves({ ok: true } as Response);
60
+ (globalThis as Record<string, unknown>)['fetch'] = fetchStub;
61
+
62
+ // Fresh args: these must win over the stale instance property values above.
63
+ subscription = context.queryWithParameterDescriptorValues.subscribe(callback, {
64
+ filter: 'fresh-filter',
65
+ limit: 42
66
+ });
67
+
68
+ eventSourceInstance.onopen?.();
69
+ eventSourceInstance.onmessage?.({
70
+ data: JSON.stringify({
71
+ type: HubMessageType.Connected,
72
+ payload: 'conn-1'
73
+ })
74
+ });
75
+ });
76
+
77
+ afterEach(() => {
78
+ Globals.queryDirectMode = originalQueryDirectMode;
79
+ Globals.queryTransportMethod = originalTransportMethod;
80
+ if (subscription) {
81
+ subscription.unsubscribe();
82
+ }
83
+ delete (globalThis as Record<string, unknown>)['EventSource'];
84
+ delete (globalThis as Record<string, unknown>)['fetch'];
85
+ resetSharedMultiplexer();
86
+ sinon.restore();
87
+ });
88
+
89
+ it('should use fresh args filter value instead of stale instance property', () => {
90
+ fetchStub.called.should.be.true;
91
+ const subscribeBody = JSON.parse(fetchStub.firstCall.args[1].body as string);
92
+ subscribeBody.request.arguments.filter.should.equal('fresh-filter');
93
+ });
94
+
95
+ it('should use fresh args limit value instead of stale instance property', () => {
96
+ const subscribeBody = JSON.parse(fetchStub.firstCall.args[1].body as string);
97
+ subscribeBody.request.arguments.limit.should.equal('42');
98
+ });
99
+ }));