Skip to content

feat: leave a resource method out of one target with @nexus.api-omit - #410

Merged
tconley1428 merged 90 commits into
mainfrom
moe/up/method-omit-target
Nov 13, 2026
Merged

tconley1428 merged 90 commits into
mainfrom
moe/up/method-omit-target

Conversation

@moetemp

@moetemp moetemp commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

This PR lets @nexus.api-omit leave a resource method out of one target.

The directive worked on a field or a function, not on a resource method. The stream sample needs it, since Workflow code can't append to a Stream or close it in this release, and client code can.

/// @nexus.operation "close-stream"
/// @nexus.close
/// @nexus.api-omit targets="workflow"
close: func(producer: option<producer>);

The sample's Workflow Stream has no append and no close in Python, TypeScript and .NET. The operation stays in the service.

tconley1428 and others added 30 commits November 5, 2026 11:01
A resource with `@nexus.type-parameter "<alias>"` is generic in Python, TypeScript and .NET. An
operation that returns it, or that its method binds, takes a runtime type for each type parameter
of its output, so a response decodes its generic values.
The kept fixtures cover an undeclared type parameter, a generic resource in a record field or in a result with no proto message, and a language that refuses it. The others test directive syntax, rare name clashes or another copy of a kept check.
Co-authored-by: Tim Conley <timothy.conley@temporal.io>
A resource that uses a type parameter, also through its records, is generic in it, as a record
is. So a resource needs no annotation, and `@nexus.type-parameter` is valid only on a type alias
again.
Only a returned resource gives its type parameters, as the guide says, so a
parameter or field that holds one doesn't. The declaration order doesn't change
when a method moves.
A list, map, tuple, result or variant case builds the resource from the record's
message too, so it gets no type argument either.
The old reason said a proto message holds the type arguments, which it doesn't.
Two type parameters such as `body` and `body-t` give the same runtime type name,
and a method can take it too. Either one makes a duplicate parameter or member.
The typed hook of a generic response took only the request, so the terminal
decoded `ReadRecordsResponse[Turn]` with the plain class and lost `Turn`.
C# generics are invariant, so the `<object>` checks refused a `Stream<Turn>` call.
The dispatch now compares generic type definitions and keeps the call's types.
A subclass such as `class TurnStream(Stream[Turn])` has no `__orig_class__`, so
the handle reads `__orig_bases__` too. A factory tests `body_type is None`,
since a class can be falsy.
The TypeScript stream test now decodes a body with a runtime type. The Python
test decodes to the bare handle class, since a generic alias fails for another
reason.
No release has the Python constructor change, so it belongs with the added
entry. The fixed entry now describes the System Nexus dispatch fixes.
A few comments used "name" as a verb, ran over two lines or over 100 columns.
The guide's first paragraph read as one long sentence.
Drop the tests that repeat another test or restate generated code, and keep the
ones that guard behavior. Shorten the guide section and the comments.
Python can't subscript a function, so each generic call is an object whose
subscript binds the types, as in `client.get_stream[Turn](ref=ref)`. A factory's
optional field defaults to `None`.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
`@nexus.close` marks the method that ends a resource. Python calls it at the end of `async with`,
and a call that returns the resource returns a `ResourceCall`.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
`@nexus.varargs` makes a resource method take a list's items as positional arguments, and a list of
a flattened one-field record takes that field's values. The Stream's publish takes values and
returns the last offset.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
Workflow code gets a handle on an existing Stream with `get_stream[T]`, from the fields of its ref,
with no call.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
Each client call and client resource method takes `rpc_metadata` and `rpc_timeout`, and passes
them to the `start_operation` of its Nexus client.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
`@nexus.flatten-in-api` on a request field makes that call take the fields of the field's record,
and the models keep the record. The Stream create takes the id, the owner and the backend of its
ref this way, and the other Stream calls keep `ref`.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
A field can leave the API of one target and take a source in another. A call of a target that omits
a required list sends it empty.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
moetemp and others added 4 commits November 13, 2026 01:36
A TypeScript resource method calls the Workflow API, so a method omitted for `workflow` goes from
the class. Its request helper goes too when no other method used it.
A .NET resource method calls the Workflow API, so a method omitted for `workflow` goes from the
class. The request overload that only it called becomes private.
Go has no sample that would show its output without the method, so it refuses the directive as it
refuses `@nexus.varargs`. A method omitted only for `client` changes nothing in Go.
In this release Workflow code can't append to a Stream or close it, so the Workflow target omits
both methods. The client `Stream` keeps them, and the Workflow `create_stream` is a plain call.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
…409)

The SDK's `Client` inherits the generated extension, so `temporalio.client` imports the generated
package. A run-time import back made importing the package first a circular import.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
Base automatically changed from moe/up/client-import-cycle to moe/up/source-fallback November 13, 2026 18:04
moetemp and others added 4 commits November 13, 2026 11:22
A resource method passed an optional parameter as it was and dropped the default of the field.
A source is a helper value and never an argument, so it no longer fills an optional parameter.
A resource method hands an optional parameter to its operation, which applies the field's default.
A source is a helper value and never an argument, so it no longer fills an optional parameter.
The stream sample's resource methods go through the options type, which applies the default.
A source is a helper value and never an argument, so it no longer fills an optional parameter.
A default is an omittable argument, which the optional `producer` of `append` and `close` needs.
The guide and the changelog describe the default rule for resource methods.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
@moetemp
moetemp marked this pull request as ready for review November 13, 2026 18:24
@moetemp
moetemp requested a review from a team as a code owner November 13, 2026 18:24
@moetemp
moetemp added this pull request to stack #411 November 13, 2026 18:26
Comment thread architecture.md Outdated
public surface (the Python `__all__` entry and function, the TypeScript barrel
export, the .NET public options type and method, and the Go exported wrapper).

On a resource method, the parser records the omitted targets on

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't seem understandable architecture documentation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrote this paragraph.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still doesn't seem high level enough to matter here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair. I cut it to two sentences in e325c6f. Wdyt?

moetemp and others added 6 commits November 13, 2026 11:37
The import cycle fix landed on this branch while the default rework was built on the commit
before it. The result is the tree that the checks ran on.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
The Producer of the stream sample became a default. The Workflow `Stream` still has no `append`
or `close`, so its test stays as this branch had it.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
The note listed type names and did not say what happens. It says what the directive does and
that planning owns the choice.

Co-authored-by: Tim Conley <timothy.conley@temporal.io>
@moetemp
moetemp requested a review from tconley1428 November 13, 2026 18:46
Base automatically changed from moe/up/source-fallback to main November 13, 2026 19:03
@tconley1428
tconley1428 merged commit 9653a0f into main Nov 13, 2026
5 checks passed
@tconley1428
tconley1428 deleted the moe/up/method-omit-target branch November 13, 2026 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants