Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
BBC4E06F9B0A1EED3C45E9F2D7F9252F4E5759D47A90F8507502F9A94CED3CFD
E009AF9F9307C1F4CF27D6EDFDA0F4344DDF74E4CEA80F06641BB5E5EEED5D55
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,24 @@ export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './t
* ```
*/
export class ReferenceExpression {
private readonly _format: string;
private readonly _valueProviders: unknown[];

private constructor(format: string, valueProviders: unknown[]) {
this._format = format;
this._valueProviders = valueProviders;
// Expression mode fields
private readonly _format?: string;
private readonly _valueProviders?: unknown[];

// Handle mode fields (when wrapping a server-returned handle)
private readonly _handle?: Handle;
private readonly _client?: AspireClient;

constructor(format: string, valueProviders: unknown[]);
constructor(handle: Handle, client: AspireClient);
constructor(handleOrFormat: Handle | string, clientOrValueProviders: AspireClient | unknown[]) {
if (typeof handleOrFormat === 'string') {
this._format = handleOrFormat;
this._valueProviders = clientOrValueProviders as unknown[];
} else {
this._handle = handleOrFormat;
this._client = clientOrValueProviders as AspireClient;
}
}

/**
Expand Down Expand Up @@ -72,13 +84,18 @@ export class ReferenceExpression {

/**
* Serializes the reference expression for JSON-RPC transport.
* Uses the $expr format recognized by the server.
* In template-literal mode, uses the $expr format.
* In handle mode, delegates to the handle's serialization.
*/
toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } {
toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } | MarshalledHandle {
if (this._handle) {
return this._handle.toJSON();
}

return {
$expr: {
format: this._format,
valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined
format: this._format!,
valueProviders: this._valueProviders && this._valueProviders.length > 0 ? this._valueProviders : undefined
}
};
}
Expand All @@ -87,6 +104,9 @@ export class ReferenceExpression {
* String representation for debugging.
*/
toString(): string {
if (this._handle) {
return `ReferenceExpression(handle)`;
}
return `ReferenceExpression(${this._format})`;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,27 @@ export function registerCallback<TResult = void>(

if (argArray.length > 0) {
// Spread positional arguments to callback
return await callback(...argArray);
const result = await callback(...argArray);
// DTO writeback protocol: when a void callback returns undefined, we
// return the original args object so the .NET host can detect property
// mutations made by the callback and apply them back to the original
// C# DTO objects. DTO args are plain JS objects (not Handle wrappers),
// so any property changes the callback made are reflected in args.
//
// Non-void callbacks (result !== undefined) return their actual result.
// The .NET side only activates writeback for void delegates whose
// parameters include [AspireDto] types — all other cases discard the
// returned args object, so the extra wire payload is harmless.
//
// IMPORTANT: callbacks that intentionally return undefined will also
// trigger this path. For non-void delegate types, the C# proxy uses
// a result-unmarshalling path (not writeback), so returning args will
// cause an unmarshal error. Void callbacks should never return a
// meaningful value; non-void callbacks should always return one.
return result !== undefined ? result : args;
}

// No positional params found - call with no args
// No positional params found — nothing to write back
return await callback();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
BFDBEE79E391368156C929FBA3E89038416E658D6130E0C7BE7C4AE69BF97E8D
0B8E5E5C065C4224832806DB93EB742BF33571136DBB1ABECB65A683983B64A7
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,24 @@ export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './t
* ```
*/
export class ReferenceExpression {
private readonly _format: string;
private readonly _valueProviders: unknown[];

private constructor(format: string, valueProviders: unknown[]) {
this._format = format;
this._valueProviders = valueProviders;
// Expression mode fields
private readonly _format?: string;
private readonly _valueProviders?: unknown[];

// Handle mode fields (when wrapping a server-returned handle)
private readonly _handle?: Handle;
private readonly _client?: AspireClient;

constructor(format: string, valueProviders: unknown[]);
constructor(handle: Handle, client: AspireClient);
constructor(handleOrFormat: Handle | string, clientOrValueProviders: AspireClient | unknown[]) {
if (typeof handleOrFormat === 'string') {
this._format = handleOrFormat;
this._valueProviders = clientOrValueProviders as unknown[];
} else {
this._handle = handleOrFormat;
this._client = clientOrValueProviders as AspireClient;
}
}

/**
Expand Down Expand Up @@ -72,13 +84,18 @@ export class ReferenceExpression {

/**
* Serializes the reference expression for JSON-RPC transport.
* Uses the $expr format recognized by the server.
* In template-literal mode, uses the $expr format.
* In handle mode, delegates to the handle's serialization.
*/
toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } {
toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } | MarshalledHandle {
if (this._handle) {
return this._handle.toJSON();
}

return {
$expr: {
format: this._format,
valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined
format: this._format!,
valueProviders: this._valueProviders && this._valueProviders.length > 0 ? this._valueProviders : undefined
}
};
}
Expand All @@ -87,6 +104,9 @@ export class ReferenceExpression {
* String representation for debugging.
*/
toString(): string {
if (this._handle) {
return `ReferenceExpression(handle)`;
}
return `ReferenceExpression(${this._format})`;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,27 @@ export function registerCallback<TResult = void>(

if (argArray.length > 0) {
// Spread positional arguments to callback
return await callback(...argArray);
const result = await callback(...argArray);
// DTO writeback protocol: when a void callback returns undefined, we
// return the original args object so the .NET host can detect property
// mutations made by the callback and apply them back to the original
// C# DTO objects. DTO args are plain JS objects (not Handle wrappers),
// so any property changes the callback made are reflected in args.
//
// Non-void callbacks (result !== undefined) return their actual result.
// The .NET side only activates writeback for void delegates whose
// parameters include [AspireDto] types — all other cases discard the
// returned args object, so the extra wire payload is harmless.
//
// IMPORTANT: callbacks that intentionally return undefined will also
// trigger this path. For non-void delegate types, the C# proxy uses
// a result-unmarshalling path (not writeback), so returning args will
// cause an unmarshal error. Void callbacks should never return a
// meaningful value; non-void callbacks should always return one.
return result !== undefined ? result : args;
}

// No positional params found - call with no args
// No positional params found — nothing to write back
return await callback();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7EF947E3DB9CB01B5D6008ADF07D860AB6B45E6F611A401E305D8A2BB42EA1DF
06CC658536930207FF3C36815931591FA76882599F17680297D44D6848FB6E5A
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,24 @@ export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './t
* ```
*/
export class ReferenceExpression {
private readonly _format: string;
private readonly _valueProviders: unknown[];

private constructor(format: string, valueProviders: unknown[]) {
this._format = format;
this._valueProviders = valueProviders;
// Expression mode fields
private readonly _format?: string;
private readonly _valueProviders?: unknown[];

// Handle mode fields (when wrapping a server-returned handle)
private readonly _handle?: Handle;
private readonly _client?: AspireClient;

constructor(format: string, valueProviders: unknown[]);
constructor(handle: Handle, client: AspireClient);
constructor(handleOrFormat: Handle | string, clientOrValueProviders: AspireClient | unknown[]) {
if (typeof handleOrFormat === 'string') {
this._format = handleOrFormat;
this._valueProviders = clientOrValueProviders as unknown[];
} else {
this._handle = handleOrFormat;
this._client = clientOrValueProviders as AspireClient;
}
}

/**
Expand Down Expand Up @@ -72,13 +84,18 @@ export class ReferenceExpression {

/**
* Serializes the reference expression for JSON-RPC transport.
* Uses the $expr format recognized by the server.
* In template-literal mode, uses the $expr format.
* In handle mode, delegates to the handle's serialization.
*/
toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } {
toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } | MarshalledHandle {
if (this._handle) {
return this._handle.toJSON();
}

return {
$expr: {
format: this._format,
valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined
format: this._format!,
valueProviders: this._valueProviders && this._valueProviders.length > 0 ? this._valueProviders : undefined
}
};
}
Expand All @@ -87,6 +104,9 @@ export class ReferenceExpression {
* String representation for debugging.
*/
toString(): string {
if (this._handle) {
return `ReferenceExpression(handle)`;
}
return `ReferenceExpression(${this._format})`;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,27 @@ export function registerCallback<TResult = void>(

if (argArray.length > 0) {
// Spread positional arguments to callback
return await callback(...argArray);
const result = await callback(...argArray);
// DTO writeback protocol: when a void callback returns undefined, we
// return the original args object so the .NET host can detect property
// mutations made by the callback and apply them back to the original
// C# DTO objects. DTO args are plain JS objects (not Handle wrappers),
// so any property changes the callback made are reflected in args.
//
// Non-void callbacks (result !== undefined) return their actual result.
// The .NET side only activates writeback for void delegates whose
// parameters include [AspireDto] types — all other cases discard the
// returned args object, so the extra wire payload is harmless.
//
// IMPORTANT: callbacks that intentionally return undefined will also
// trigger this path. For non-void delegate types, the C# proxy uses
// a result-unmarshalling path (not writeback), so returning args will
// cause an unmarshal error. Void callbacks should never return a
// meaningful value; non-void callbacks should always return one.
return result !== undefined ? result : args;
}

// No positional params found - call with no args
// No positional params found — nothing to write back
return await callback();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
31B8640EE31CD920C45A7A3F7C2ABBDCE9F0AA8304B58DC03F170971E1A1F61A
2AC3FFFB60C637F746D87E10A987A202B058E6DDCB0754885D0F70363464CB8E
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,24 @@ export { AtsErrorCodes, isMarshalledHandle, isAtsError, wrapIfHandle } from './t
* ```
*/
export class ReferenceExpression {
private readonly _format: string;
private readonly _valueProviders: unknown[];

private constructor(format: string, valueProviders: unknown[]) {
this._format = format;
this._valueProviders = valueProviders;
// Expression mode fields
private readonly _format?: string;
private readonly _valueProviders?: unknown[];

// Handle mode fields (when wrapping a server-returned handle)
private readonly _handle?: Handle;
private readonly _client?: AspireClient;

constructor(format: string, valueProviders: unknown[]);
constructor(handle: Handle, client: AspireClient);
constructor(handleOrFormat: Handle | string, clientOrValueProviders: AspireClient | unknown[]) {
if (typeof handleOrFormat === 'string') {
this._format = handleOrFormat;
this._valueProviders = clientOrValueProviders as unknown[];
} else {
this._handle = handleOrFormat;
this._client = clientOrValueProviders as AspireClient;
}
}

/**
Expand Down Expand Up @@ -72,13 +84,18 @@ export class ReferenceExpression {

/**
* Serializes the reference expression for JSON-RPC transport.
* Uses the $expr format recognized by the server.
* In template-literal mode, uses the $expr format.
* In handle mode, delegates to the handle's serialization.
*/
toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } {
toJSON(): { $expr: { format: string; valueProviders?: unknown[] } } | MarshalledHandle {
if (this._handle) {
return this._handle.toJSON();
}

return {
$expr: {
format: this._format,
valueProviders: this._valueProviders.length > 0 ? this._valueProviders : undefined
format: this._format!,
valueProviders: this._valueProviders && this._valueProviders.length > 0 ? this._valueProviders : undefined
}
};
}
Expand All @@ -87,6 +104,9 @@ export class ReferenceExpression {
* String representation for debugging.
*/
toString(): string {
if (this._handle) {
return `ReferenceExpression(handle)`;
}
return `ReferenceExpression(${this._format})`;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,27 @@ export function registerCallback<TResult = void>(

if (argArray.length > 0) {
// Spread positional arguments to callback
return await callback(...argArray);
const result = await callback(...argArray);
// DTO writeback protocol: when a void callback returns undefined, we
// return the original args object so the .NET host can detect property
// mutations made by the callback and apply them back to the original
// C# DTO objects. DTO args are plain JS objects (not Handle wrappers),
// so any property changes the callback made are reflected in args.
//
// Non-void callbacks (result !== undefined) return their actual result.
// The .NET side only activates writeback for void delegates whose
// parameters include [AspireDto] types — all other cases discard the
// returned args object, so the extra wire payload is harmless.
//
// IMPORTANT: callbacks that intentionally return undefined will also
// trigger this path. For non-void delegate types, the C# proxy uses
// a result-unmarshalling path (not writeback), so returning args will
// cause an unmarshal error. Void callbacks should never return a
// meaningful value; non-void callbacks should always return one.
return result !== undefined ? result : args;
}

// No positional params found - call with no args
// No positional params found — nothing to write back
return await callback();
}

Expand Down
Loading
Loading