Skip to content

feat: register fn node sdk#1395

Merged
sergiofilhowz merged 2 commits intomainfrom
feat/register-fn-node-sdk
Apr 2, 2026
Merged

feat: register fn node sdk#1395
sergiofilhowz merged 2 commits intomainfrom
feat/register-fn-node-sdk

Conversation

@sergiofilhowz
Copy link
Copy Markdown
Contributor

@sergiofilhowz sergiofilhowz commented Apr 2, 2026

Summary by CodeRabbit

  • Refactor

    • Function registration API unified: pass the function ID as the first string argument; optional config moved to a trailing options argument.
  • Documentation

    • All examples and guides updated to the new string-first registration form across languages and tutorials.
  • Tests

    • Test suites adjusted to use the new registration call shape.

@mintlify
Copy link
Copy Markdown

mintlify bot commented Apr 2, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
iii 🟢 Ready View Preview Apr 2, 2026, 3:03 PM

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
iii-website Ready Ready Preview, Comment Apr 2, 2026 4:35pm
motia-docs Ready Ready Preview, Comment Apr 2, 2026 4:35pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

The PR changes the function registration API from an object-based form ({ id: ... }) to a positional string form (functionId: string) across docs, examples, tests, and the Node/browser SDKs, and introduces a new RegisterFunctionOptions type for optional metadata/options.

Changes

Cohort / File(s) Summary
API Reference Documentation
docs/api-reference/sdk-browser.mdx, docs/api-reference/sdk-node.mdx, docs/api-reference/sdk-python.mdx
Reworked registerFunction/register_function signatures and parameter docs to accept functionId: string, handler, and optional options; replaced RegisterFunctionInput docs with RegisterFunctionOptions.
How-To, Examples & Guides
docs/how-to/*, docs/examples/*, docs/architecture/*, docs/modules/*
Updated dozens of examples across guides and modules to call registerFunction('id', handler, options?) / register_function("id", ...) instead of passing { id: ... }.
Browser SDK Implementation
sdk/packages/node/iii-browser/src/iii.ts, sdk/packages/node/iii-browser/src/types.ts, sdk/packages/node/iii-browser/src/index.ts, sdk/packages/node/iii-browser/src/iii-types.ts
Changed Sdk.registerFunction API to (functionId: string, handlerOrInvocation, options?); removed HTTP invocation types re-exports; always build registration message from id: functionId + options.
Node SDK Implementation
sdk/packages/node/iii/src/iii.ts, sdk/packages/node/iii/src/types.ts, sdk/packages/node/iii/src/index.ts, sdk/packages/node/iii/src/iii-types.ts
Refactored Sdk.registerFunction signature to accept functionId and options?, added RegisterFunctionOptions type, and updated trigger wiring to pass function_id: functionId.
Tests & SDK Examples
sdk/packages/node/iii-browser/tests/*, sdk/packages/node/iii/tests/*, sdk/packages/node/iii-browser/src/*, sdk/packages/node/iii-example/src/*
Updated ~50+ tests and example sources to the new call form; adjusted assertions and some tests to optional-chaining; removed/downgraded HTTP-invocation-specific handling in tests where applicable.
Framework Integrations & Motia
frameworks/motia/motia-js/packages/motia/src/*, .../__tests__/*
Updated Motia integration code and tests to register functions using the string functionId and optional options metadata argument.
Website & Embedded Code Snippets
website/components/..., website/components/sections/..., website/components/sections/code-examples/iii/*
Updated 20+ embedded snippets, demo flows, terminal output examples, and dependency-extraction logic to detect registerFunction("id", ...) call shape.
Docs/README Updates
sdk/README.md, sdk/packages/node/iii-browser/README.md, sdk/packages/node/iii/README.md
Updated README examples and API tables to reflect new positional registerFunction(id, handler, options?) signature.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant SDK
participant Engine
Client->>SDK: registerFunction(functionId, handler, options?)
SDK->>SDK: build RegisterFunctionMessage { id: functionId, ...options, message_type }
SDK->>Engine: send(register_function_message)
Engine-->>SDK: ack / functions-available
SDK->>SDK: store functionRef(functionId, handler)
Client->>SDK: call fnRef.unregister()
SDK->>Engine: send(unregister_message with id=functionId)
Engine-->>SDK: ack

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • guibeira
  • ytallo

Poem

🐰 I hopped through docs and SDK land,
Swapped curly braces for a simpler strand.
One string, one call, options beside,
Registration now takes a tidier stride.
A carrot cheer — clean code, let's glide! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'feat: register fn node sdk' is vague and uses unclear abbreviations ('fn' and 'sdk') that don't convey the specific change being made. Clarify the title to describe the actual API change, such as 'feat: refactor registerFunction API to use string function IDs' or 'feat: simplify function registration with positional function ID parameter'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/register-fn-node-sdk

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (27)
docs/advanced/telemetry.mdx (1)

156-164: ⚠️ Potential issue | 🟡 Minor

Rust example has a syntax error and potential API inconsistency.

Line 158 has an extra closing parenthesis after .unwrap_or_default(). Additionally, based on learnings, Rust SDK docs should use RegisterFunctionMessage::new("id") for simple ID-only cases, not with_id.

🐛 Proposed fix
-iii.register_function((RegisterFunctionMessage::with_id("orders::process".into()), |input| async move {
+iii.register_function(RegisterFunctionMessage::new("orders::process"), |input| async move {
     with_span("validate-order", |span| async move {
-        span.set_attribute("order.id", input["orderId"].as_str().unwrap_or_default()));
+        span.set_attribute("order.id", input["orderId"].as_str().unwrap_or_default());

Based on learnings: "In iii-hq/iii Rust SDK docs, RegisterFunctionMessage::new("id") was added as a constructor method... All Rust doc examples that only set id should use RegisterFunctionMessage::new("X")."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/advanced/telemetry.mdx` around lines 156 - 164, The Rust example has a
stray closing parenthesis after span.set_attribute("order.id",
input["orderId"].as_str().unwrap_or_default())) — remove that extra ')' to fix
the syntax error, and replace
RegisterFunctionMessage::with_id("orders::process".into()) with
RegisterFunctionMessage::new("orders::process") to use the canonical
constructor; update the register_function call accordingly (refer to
RegisterFunctionMessage::new and with_span/validate_order/register_function in
the snippet).
docs/examples/hello-world.mdx (1)

163-164: ⚠️ Potential issue | 🟡 Minor

Rust example has a syntax error.

Line 164 has an extra closing parenthesis: let logger = Logger()); should be let logger = Logger::new(); or similar.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/hello-world.mdx` around lines 163 - 164, The Rust example has a
syntax error in the register closure: fix the logger instantiation used inside
the iii.register_function closure (the line with let logger = Logger());) by
replacing the erroneous expression with a proper constructor call (e.g., let
logger = Logger::new();) and remove the extra parenthesis so the closure
compiles; check the closure body around iii.register_function and
RegisterFunctionMessage::with_id("hello::api".into()) to ensure the logger
variable is correctly declared and used.
docs/examples/multi-trigger.mdx (1)

26-28: ⚠️ Potential issue | 🟠 Major

Migrate the Node example to the new registerFunction(functionId, handler, options?) signature.

This page still uses the old object-first call in Node while Python already uses the new signature, so the examples are inconsistent. The Node SDK's documented API (ISdk interface) expects the string function ID as the first parameter, the handler as the second, and an optional options object (containing description and other metadata) as the third parameter.

Suggested doc fix
 iii.registerFunction(
-  { id: 'orders.handle', description: 'Handles orders from API, queue, or cron' },
+  'orders.handle',
   async (input) => {
     const logger = new Logger()

@@
   },
+  { description: 'Handles orders from API, queue, or cron' },
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/multi-trigger.mdx` around lines 26 - 28, The Node example uses
the old object-first call to registerFunction; update it to the new signature
registerFunction(functionId, handler, options?) by passing the string ID as the
first argument, the async handler as the second, and move the
description/metadata into the third options object (e.g., description) so the
call matches the ISdk interface and aligns with the Python example.
docs/modules/module-cron.mdx (1)

118-124: ⚠️ Potential issue | 🟠 Major

Update the TypeScript cron sample to match the current SDK signature.

The TypeScript code at lines 118–124 uses the outdated object-first form, while Python was already migrated to string-first. Both should be consistent with the current Node SDK API.

Suggested doc fix
 const fn = iii.registerFunction(
-  { id: 'jobs::cleanupOldData' },
+  'jobs::cleanupOldData',
   async (event) => {
     console.log('Running cleanup scheduled at:', event.scheduled_time)
     return {}
   },
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/modules/module-cron.mdx` around lines 118 - 124, The TypeScript cron
example uses the old object-first registerFunction signature; update the call to
the current Node SDK string-first form by passing the function id string (e.g.,
"jobs::cleanupOldData") as the first argument to iii.registerFunction and the
async handler as the second, leaving the handler body (console.log and return
{}) intact so the example matches the Python/string-first API; locate the
example around the registerFunction usage and replace the object { id:
'jobs::cleanupOldData' } with the id string.
sdk/README.md (1)

52-52: ⚠️ Potential issue | 🟡 Minor

Python Hello World example inconsistent with API table.

The Python Hello World example still uses the old object form {"id": "greet"}, but the API table at Line 96 documents Python as iii.register_function(id, handler) (positional string form). These should be consistent.

Proposed fix
-iii.register_function({"id": "greet"}, greet)
+iii.register_function("greet", greet)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/README.md` at line 52, Update the Python example to match the documented
API by switching the old object form to the positional signature: replace
iii.register_function({"id": "greet"}, greet) with
iii.register_function("greet", greet) so the example uses register_function(id,
handler) as shown in the API table; ensure any nearby examples or explanatory
text referencing the object form are adjusted to the positional string form too.
docs/modules/module-state.mdx (2)

278-286: ⚠️ Potential issue | 🟡 Minor

Node/TS example still uses old object-based signature.

This example wasn't updated to the new positional string form. It should be consistent with the rest of the PR changes.

Proposed fix
 const fn = iii.registerFunction(
-  { id: 'state::onUserUpdated' },
+  'state::onUserUpdated',
   async (event) => {
     console.log('State changed:', event.event_type, event.key)
     console.log('Previous:', event.old_value)
     console.log('Current:', event.new_value)
     return {}
   },
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/modules/module-state.mdx` around lines 278 - 286, The example uses the
old object-based signature for iii.registerFunction; change it to the new
positional string form by passing the ID as the first argument (e.g.,
'state::onUserUpdated') instead of an object ({ id: 'state::onUserUpdated' })
while keeping the async handler (async (event) => { ... }) the same; update the
call site of iii.registerFunction accordingly so the example matches the new
API.

471-476: ⚠️ Potential issue | 🟡 Minor

Condition function registration not updated to new signature.

The conditionFn registration still uses the old object form { id: 'conditions::emailChanged' }, while the handler at Line 478 was updated. Both should use the new positional string form for consistency.

Proposed fix
 const conditionFn = iii.registerFunction(
-  { id: 'conditions::emailChanged' },
+  'conditions::emailChanged',
   async (event) =>
     event.event_type === 'state:updated' &&
     event.old_value?.email !== event.new_value?.email,
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/modules/module-state.mdx` around lines 471 - 476, The condition function
registration uses the old object form with iii.registerFunction({ id:
'conditions::emailChanged' }, ...) but the handler was updated to the new
positional string signature; update the call to use the new positional form by
passing the id string as the first argument to iii.registerFunction (i.e.,
replace the object id param with 'conditions::emailChanged') while keeping the
existing async event handler logic in conditionFn.
docs/examples/observability.mdx (3)

33-34: ⚠️ Potential issue | 🟡 Minor

Inconsistency: Node/TypeScript example still uses object-based registration.

The Python examples in this file were updated to use the new positional string form (iii.register_function("orders.create", create_order)), but the Node/TypeScript examples still use the old object form ({ id: 'orders.create', description: '...' }).

For consistency across language tabs, update this to the new signature. The description can move to the optional third parameter:

 iii.registerFunction(
-  { id: 'orders.create', description: 'Creates an order and starts the processing pipeline' },
+  'orders.create',
   async (req: ApiRequest<{ customerId: string; amount: number; items: string[] }>) => {
     // ...
   },
+  { description: 'Creates an order and starts the processing pipeline' }
 )

As per coding guidelines: "Make sure the shape of objects and arguments to functions and triggers are consistent within and between sdks."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/observability.mdx` around lines 33 - 34, The Node/TypeScript
example uses the old object-based registration for iii.registerFunction; update
it to the new positional signature used in the Python examples by calling
iii.registerFunction with the function id string as the first arg (e.g.,
"orders.create"), the handler function (e.g., createOrder) as the second arg,
and move the previous description into the optional third parameter object
(e.g., { description: "Creates an order and starts the processing pipeline" })
so the example matches the new cross-SDK convention.

322-323: ⚠️ Potential issue | 🟡 Minor

Same inconsistency: order.notify Node/TypeScript example uses old object form.

Update to match the new positional signature:

 iii.registerFunction(
-  { id: 'order.notify', description: 'Sends order notification' },
+  'order.notify',
   async (data: { orderId: string; customerId: string; status: string; amount: number }) => {
     // ...
   },
+  { description: 'Sends order notification' }
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/observability.mdx` around lines 322 - 323, Update the
Node/TypeScript example for registerFunction to use the new positional
signature: replace the object-form call to iii.registerFunction({ id:
'order.notify', description: 'Sends order notification' }) with a positional
call where the first argument is the id string 'order.notify' and the second
argument is an options object containing description (e.g., pass description in
the second parameter). Ensure you modify the example that references
iii.registerFunction and keep the description text intact.

206-207: ⚠️ Potential issue | 🟡 Minor

Same inconsistency: order.process Node/TypeScript example uses old object form.

Update to match the new positional signature for consistency with the Python tab:

 iii.registerFunction(
-  { id: 'order.process', description: 'Processes a created order' },
+  'order.process',
   async (data: { orderId: string; amount: number; customerId: string }) => {
     // ...
   },
+  { description: 'Processes a created order' }
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/observability.mdx` around lines 206 - 207, Replace the old
object-style call to iii.registerFunction({ id: 'order.process', description:
'Processes a created order' }, ...) with the new positional signature used in
the Python tab: call iii.registerFunction('order.process', 'Processes a created
order', ...) so that the first arg is the id string and the second is the
description string; update any subsequent handler/opts arguments to follow the
new positional ordering in the same call site.
docs/examples/conditions.mdx (3)

246-251: ⚠️ Potential issue | 🟡 Minor

Same inconsistency in State trigger condition section.

Suggested changes
 iii.registerFunction(
-  { id: 'conditions::is_update' },
+  'conditions::is_update',
   async (event: { event_type: string; scope: string; key: string; old_value: unknown; new_value: unknown }) => {
     return event.event_type === 'updated'
   },
 )

 iii.registerFunction(
-  { id: 'orders::on_update', description: 'Reacts to order state updates' },
+  'orders::on_update',
   async (event) => {
     // ...
   },
+  { description: 'Reacts to order state updates' }
 )

Also applies to: 253-259

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/conditions.mdx` around lines 246 - 251, The condition uses the
wrong event_type literal; update the comparison in the iii.registerFunction with
id 'conditions::is_update' so it matches the State trigger event_type used
elsewhere (e.g., use 'update' instead of 'updated'), and make the identical fix
for the other occurrence in the State trigger condition section so both
functions compare against the same event_type string.

31-36: ⚠️ Potential issue | 🟡 Minor

Inconsistency: Node/TypeScript examples still use object-based registration.

The Python examples in this file were updated to the new positional string form, but the Node/TypeScript examples still use the old object form. For consistency across language tabs, update these registrations:

Suggested changes for HTTP trigger condition section
 iii.registerFunction(
-  { id: 'conditions::is_premium' },
+  'conditions::is_premium',
   async (req: ApiRequest<{ amount: number }>) => {
     return (req.body?.amount ?? 0) > 1000
   },
 )

 iii.registerFunction(
-  { id: 'orders::premium', description: 'Processes premium orders' },
+  'orders::premium',
   async (req: ApiRequest<{ amount: number; description: string }>) => {
     // ...
   },
+  { description: 'Processes premium orders' }
 )

As per coding guidelines: "Make sure the shape of objects and arguments to functions and triggers are consistent within and between sdks."

Also applies to: 38-45

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/conditions.mdx` around lines 31 - 36, The Node/TypeScript
examples use the old object-based registration (e.g., iii.registerFunction({ id:
'conditions::is_premium' }, async (req: ApiRequest<{ amount: number }>) => ...
)) while Python examples use the new positional string form; update each Node/TS
registration (including the one for 'conditions::is_premium' and the other
registration at the 38-45 range) to the positional signature
iii.registerFunction('conditions::is_premium', async (req: ApiRequest<{ amount:
number }>) => { ... }) — keep the handler function and types intact but replace
the first argument from an object with the id string to ensure consistent shape
across SDK examples.

136-141: ⚠️ Potential issue | 🟡 Minor

Same inconsistency in Queue trigger condition section.

Suggested changes
 iii.registerFunction(
-  { id: 'conditions::is_high_value' },
+  'conditions::is_high_value',
   async (data: { amount: number }) => {
     return data.amount > 1000
   },
 )

 iii.registerFunction(
-  { id: 'orders::high_value', description: 'Processes high-value orders from queue' },
+  'orders::high_value',
   async (data: { amount: number; description: string }) => {
     // ...
   },
+  { description: 'Processes high-value orders from queue' }
 )

Also applies to: 143-155

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/conditions.mdx` around lines 136 - 141, The Queue trigger
condition examples use inconsistent formatting; update both occurrences of
iii.registerFunction with id 'conditions::is_high_value' so they match the
established example style (same async arrow function signature, typed parameter
{ amount: number }, explicit return expression, and consistent
indentation/trailing commas) used elsewhere in the docs; ensure the two examples
in the Queue trigger condition section are made identical in style to the
earlier conditions example.
docs/modules/module-stream.mdx (1)

777-780: ⚠️ Potential issue | 🟡 Minor

Condition function registration still uses old object form.

This example has the same inconsistency as in trigger-types.mdx - the condition function uses { id: 'conditions::requireContext' } while the handler at line 782 uses the new string form.

🔧 Proposed fix
 const conditionFn = iii.registerFunction(
-  { id: 'conditions::requireContext' },
+  'conditions::requireContext',
   async (input: StreamJoinLeaveEvent) => input.context?.userId != null,
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/modules/module-stream.mdx` around lines 777 - 780, The condition
function registration uses the old object form ({ id:
'conditions::requireContext' }) while the rest of the docs use the new string
form; update the call to iii.registerFunction so it uses the string identifier
'conditions::requireContext' (keeping the async handler signature using
StreamJoinLeaveEvent and the same body that checks input.context?.userId !=
null) to match the newer handler style and ensure consistency with the handler
shown elsewhere.
docs/architecture/channels.mdx (2)

295-327: ⚠️ Potential issue | 🟡 Minor

Bidirectional streaming Node/TypeScript examples also need updating.

Same issue as above - the Node/TypeScript examples for bidirectional streaming still use { id: 'stream.worker' } and { id: 'stream.coordinator' } while the Python examples at lines 452-453 use the new string form.

🔧 Proposed fix
 const worker = iii.registerFunction(
-  { id: 'stream.worker' },
+  'stream.worker',
   async (input: { reader: ChannelReader; writer: ChannelWriter }) => {
     // ...
   },
 )

 const coordinator = iii.registerFunction(
-  { id: 'stream.coordinator' },
+  'stream.coordinator',
   async (input: { text: string; chunkSize: number }) => {
     // ...
   },
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/architecture/channels.mdx` around lines 295 - 327, The examples use the
old object-id form when registering functions (iii.registerFunction({ id:
'stream.worker' }, ...) and the counterpart for 'stream.coordinator') but should
use the new string form; update the calls to iii.registerFunction so the first
argument is the function id string ('stream.worker' and 'stream.coordinator')
instead of an object, ensuring the rest of the handler code (reader/writer
handling inside the async function) remains unchanged.

123-144: ⚠️ Potential issue | 🟡 Minor

Node/TypeScript examples still use old object form while Python was updated.

The Python examples at lines 210-211 were updated to use the new string-based register_function("data.processor", handler) form, but the Node/TypeScript examples here still use the old object form { id: 'data.processor' }. This creates inconsistency within the same documentation page.

As per coding guidelines, SDKs should be symmetric and consistent between language SDKs.

🔧 Proposed fix to align Node/TypeScript with the new API
 const processor = iii.registerFunction(
-  { id: 'data.processor' },
+  'data.processor',
   async (input: { label: string; reader: ChannelReader }) => {
     // ...
   },
 )

 const sender = iii.registerFunction(
-  { id: 'data.sender' },
+  'data.sender',
   async (input: { records: { name: string; value: number }[] }) => {
     // ...
   },
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/architecture/channels.mdx` around lines 123 - 144, The Node/TypeScript
examples use the old object form for registering functions; update calls to use
the new string-based API to match Python. Replace usages of
iii.registerFunction({ id: 'data.processor' }, ...) and iii.registerFunction({
id: 'data.sender' }, ...) with the string signature
iii.registerFunction('data.processor', handler) and
iii.registerFunction('data.sender', handler), preserving the existing handler
functions (the async processor that accepts { label, reader: ChannelReader } and
the sender) and their logic, and ensure any type annotations (e.g.,
ChannelReader) remain correct for the new call form.
docs/architecture/trigger-types.mdx (1)

777-780: ⚠️ Potential issue | 🟡 Minor

Condition function registration still uses old object form.

The condition function at line 777-779 still uses { id: 'conditions::requireContext' } while the handler function at line 782 correctly uses the new string form 'onJoin'. This is inconsistent within the same example.

🔧 Proposed fix
 const conditionFn = iii.registerFunction(
-  { id: 'conditions::requireContext' },
+  'conditions::requireContext',
   async (input: StreamJoinLeaveEvent) => input.context?.userId != null,
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/architecture/trigger-types.mdx` around lines 777 - 780, The condition
registration uses the old object form { id: 'conditions::requireContext' } while
the handler uses the new string form 'onJoin'—update the condition registration
to the string form for consistency by replacing the object { id:
'conditions::requireContext' } with the string 'conditions::requireContext' in
the same example (look for the condition registration and the handler 'onJoin'
in the Rust example).
website/components/Terminal.tsx (1)

576-583: ⚠️ Potential issue | 🟠 Major

Function ID mismatch in bridge example breaks invocation routing.

iii.registerFunction("myService.greet", ...) and function_id: "myService::greet" point to different IDs, so the trigger won’t hit the registered handler.

Suggested fix
- addLog('iii.registerFunction("myService.greet", async (input) => {', "success");
+ addLog('iii.registerFunction("myService::greet", async (input) => {', "success");

As per coding guidelines for website/**, website examples must remain consistent with SDK/docs functionality.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/components/Terminal.tsx` around lines 576 - 583, The example uses
mismatched function identifiers: iii.registerFunction("myService.greet", ...)
but the trigger uses function_id: "myService::greet", so the trigger won't route
to the handler; update one side so both identifiers match (either change
iii.registerFunction to use "myService::greet" or change the trigger's
function_id to "myService.greet") ensuring the strings are identical across
iii.registerFunction and function_id to restore correct invocation routing.
docs/examples/cron.mdx (1)

75-271: ⚠️ Potential issue | 🟠 Major

Update Node and Rust SDK examples to match current API signatures.

Node tabs in this file still use the deprecated object-form registerFunction({ id: ... }, ...) pattern (lines 25–26, 124–125, 184–185). All Node examples must use positional form to stay consistent with the current SDK.

Additionally, the Rust examples have two issues:

  1. Use RegisterFunctionMessage::new() instead of ::with_id().
  2. Remove metadata: None from RegisterTriggerInput — it has exactly three required fields (trigger_type, function_id, config) with no optional fields.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/cron.mdx` around lines 75 - 271, Update the Node examples to
use the positional registerFunction signature instead of the deprecated object
form—replace calls that use registerFunction({ id: '...'}, handler) with the
positional form registerFunction('function_id', handler) for the functions
cron.periodic_job, job.handle_tick, and cron.orders_sweep; for Rust examples,
replace RegisterFunctionMessage::with_id(...) with
RegisterFunctionMessage::new(...) when registering functions and remove the
metadata: None field from RegisterTriggerInput initializers so
RegisterTriggerInput only contains trigger_type, function_id, and config.
docs/how-to/worker-rbac.mdx (2)

349-500: ⚠️ Potential issue | 🟠 Major

Don't validate the role prefix and then prepend it again.

All three on-trigger-reg examples first require function_id to already start with ${role}::, then return ${role}::${input.function_id}. That turns admin::foo into admin::admin::foo.

Suggested fix
 if (!input.function_id.startsWith(`${role}::`)) {
   throw new Error('Function ID must be prefixed with the role')
 }
-return { function_id: `${role}::${input.function_id}` }
+return {}

If the intent is auto-prefixing instead of validation, invert the condition instead of doing both.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/how-to/worker-rbac.mdx` around lines 349 - 500, The examples for the
registration hooks ('my-project::on-trigger-reg' and
'my-project::on-function-reg' in the Node/TS, Python and Rust snippets)
currently both validate that function_id starts with the role prefix and then
prepend the same prefix, causing double prefixes; fix by choosing one behavior:
for auto-prefixing, invert the condition so you only prepend when the
function_id does NOT already start with `${role}::` (i.e. if !startsWith(prefix)
then return the prefixed id, otherwise return the original id), or if you want
pure validation, keep the current check but return the original
input.function_id (do not add the prefix) — apply the same change to the
corresponding handlers in all language examples.

26-140: ⚠️ Potential issue | 🟠 Major

Update allowed_trigger_types in the RBAC examples to include 'http' instead of 'webhook'.

The examples grant allowed_trigger_types: ['cron', 'webhook'], but HTTP triggers throughout the codebase (module-http, expose-http-endpoint, all examples) register with trigger_type: 'http', not 'webhook'. Since trigger registration requires the type to be in the allowed list, an admin worker copied from this doc would be blocked from registering HTTP triggers. The 'webhook' type is a custom trigger type shown in create-custom-trigger-type.mdx, not a built-in. Change all three language tabs (TypeScript, Python, Rust) at lines 55–56, 89–90, and 129–130 to use ['cron', 'http'].

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/how-to/worker-rbac.mdx` around lines 26 - 140, Update the RBAC examples
so admins allow HTTP triggers: inside the TypeScript auth function registered
via iii.registerFunction (the async function passed to iii.registerFunction),
the Python auth_function (the function passed to iii.register_function), and the
Rust closure used with RegisterFunction::new_async, replace
allowed_trigger_types array entries from ['cron', 'webhook'] to ['cron', 'http']
(and the equivalent None/Some handling in Rust remains unchanged except for the
value). Ensure the three occurrences in allowed_trigger_types are updated so
admin users can register trigger_type: 'http'.
website/components/sections/AgentReadySection.tsx (3)

52-71: ⚠️ Potential issue | 🟠 Major

Make response mutable in the TypeScript agent example.

This snippet declares const response but then reassigns it inside the tool loop on line 67, causing a runtime error immediately when executed.

Suggested fix
-const response = await callLLM(query, { tools })
+let response = await callLLM(query, { tools })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/components/sections/AgentReadySection.tsx` around lines 52 - 71, The
example in iii.registerFunction("agent::research") declares response as const
but later reassigns it inside the while loop, causing a runtime error; change
the declaration of response to let so it is mutable (update the binding where
response is set from callLLM) and ensure subsequent reassignments inside the
loop (response = await callLLM(...)) work correctly without altering callLLM or
the loop logic.

327-350: ⚠️ Potential issue | 🟠 Major

Fix the scoping error in the streaming example code.

logger is declared inside chat::send but referenced in onFunctionsAvailable. The callback at line 349 will throw ReferenceError: logger is not defined when executed.

Move const logger = new Logger() outside both function registrations to the module scope so it's accessible to both.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/components/sections/AgentReadySection.tsx` around lines 327 - 350,
The example registers a local logger inside the chat::send handler but
references it from iii.onFunctionsAvailable, causing a ReferenceError; move the
Logger instantiation out of chat::send into module scope (declare const logger =
new Logger() at top-level of the module) so both the chat::send function and the
iii.onFunctionsAvailable callback can access the same logger instance; ensure
you remove the local const logger inside the chat::send handler to avoid
shadowing.

89-107: ⚠️ Potential issue | 🟠 Major

Remove RegisterFunctionOptions from the Rust example—it does not exist in the Rust SDK.

RegisterFunctionOptions is a Node.js/Python/Browser SDK type only. The Rust SDK provides no equivalent. Replace the example with the correct Rust SDK API:

Corrected code
rust: `use iii_sdk::{register_worker, RegisterFunctionMessage, InitOptions, Logger, TriggerRequest};

let iii = register_worker("ws://localhost:49134", InitOptions::default())?;
let logger = Logger::new();
let tools = iii.list_functions().await?;

iii.register_function(
    (RegisterFunctionMessage::with_id("agent::research".into()), |input| async move {
        let mut response = call_llm(&input.query, &tools).await?;

        while let Some(tool_call) = &response.tool_call {
            let result = iii.trigger(TriggerRequest::new(&tool_call.function, &tool_call.args)).await?;
            logger.info("Tool used", &tool_call.function);
            response = call_llm(&input.query, &tools, Some(result)).await?;
        }
        Ok(response)
    }),
)?;`

This code will not compile as written because RegisterFunctionOptions does not exist in sdk/packages/rust/iii. Rust examples elsewhere in the codebase uniformly use RegisterFunctionMessage::with_id().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/components/sections/AgentReadySection.tsx` around lines 89 - 107, The
Rust example incorrectly uses the Node/Browser/Python-only type
RegisterFunctionOptions; replace its usage with the Rust SDK pattern using
RegisterFunctionMessage (e.g., call iii.register_function with
RegisterFunctionMessage::with_id("agent::research".into()) and the async handler
closure) so the example compiles with the Rust crate that exposes
register_function and RegisterFunctionMessage::with_id; remove any mention of
RegisterFunctionOptions and update the example to use RegisterFunctionMessage
and the existing register_function, Logger, TriggerRequest, and list_functions
symbols.
docs/how-to/stream-realtime-data.mdx (1)

34-63: ⚠️ Potential issue | 🟠 Major

Remove the outer logger.info() calls or instantiate a separate logger instance for the example code after iii.trigger().

In both the chat send (lines 40, 62) and chat list (lines 167, 183) Node snippets, logger is declared inside the registered function and is not available in the outer example code that follows. The logger.info('Sent message', ...) and logger.info('Messages', ...) calls will throw a ReferenceError. Either remove these calls or create a separate top-level logger instance for the outer code block to maintain working, copy-pasteable examples.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/how-to/stream-realtime-data.mdx` around lines 34 - 63, The example
declares logger inside the registered function (new Logger() in the chat::send
handler) but then calls logger.info(...) in the outer example after invoking
iii.trigger, causing a ReferenceError; fix by either removing the outer
logger.info calls that reference the inner logger (e.g., the "Sent message" and
"Messages" calls) or instantiate a separate top-level Logger before the outer
iii.trigger calls (create a new Logger instance outside the iii.registerFunction
block) so the outer examples can log safely; update both the chat::send
(messageId) and chat::list (messages) snippets consistently.
docs/how-to/use-functions-and-triggers.mdx (1)

390-460: ⚠️ Potential issue | 🟠 Major

Remove metadata: None from all Rust RegisterTriggerInput examples in this file.

The RegisterTriggerInput struct contains only three fields: trigger_type, function_id, and config. The HTTP, Cron, State, and Unregister snippets include metadata: None, which does not exist in the struct and will cause compilation failures.

Suggested fix
 iii.register_trigger(RegisterTriggerInput {
   trigger_type: "http".into(),
   function_id: "math::multiply".into(),
   config: json!({ "api_path": "/math/multiply", "http_method": "POST" }),
-  metadata: None,
 })?;

Apply this cleanup to all Rust trigger examples at lines 454–458, 532–536, 605–609, and 746–750.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/how-to/use-functions-and-triggers.mdx` around lines 390 - 460, The Rust
documentation examples incorrectly include a non-existent metadata field in the
RegisterTriggerInput instantiations (e.g., the expressions containing "metadata:
None"); remove the "metadata: None" key-value from all RegisterTriggerInput
examples (the HTTP, Cron, State, and Unregister snippets) so each instantiation
only passes the three actual fields: trigger_type, function_id, and config,
leaving the rest of the example code unchanged.
sdk/packages/node/iii/src/iii.ts (1)

180-214: ⚠️ Potential issue | 🟠 Major

Thread RegisterFunctionOptions through the trigger-type helper.

Sdk.registerFunction() now accepts RegisterFunctionOptions (description, request_format, response_format, metadata, invocation), but TriggerTypeRef.registerFunction() calls this.registerFunction(functionId, handler) without passing an options parameter. This leaves callers unable to attach description or request/response formats when registering functions through the trigger-type helper, violating SDK consistency (coding guideline: "Make sure the shape of objects and arguments to functions and triggers are consistent within and between sdks").

Update the helper to accept and thread through options?: RegisterFunctionOptions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/packages/node/iii/src/iii.ts` around lines 180 - 214, The
TriggerTypeRef.registerFunction returned by registerTriggerType does not forward
RegisterFunctionOptions to Sdk.registerFunction; update the registerTriggerType
implementation so its registerFunction signature is (functionId: string,
handler: FunctionHandler, options?: RegisterFunctionOptions, config?, metadata?)
and call this.registerFunction(functionId, handler, options) before creating the
trigger via this.registerTrigger({ type: triggerType.id, function_id:
functionId, config, metadata }); ensure you reference the existing symbols
registerTriggerType, TriggerTypeRef.registerFunction, this.registerFunction, and
RegisterFunctionOptions when making the change so callers can supply
description, request_format, response_format, metadata, and invocation
consistently.
🧹 Nitpick comments (2)
docs/examples/hello-world.mdx (1)

149-154: LGTM on Python update, but Node.js example inconsistency.

The Python example correctly uses the new string-first register_function API. However, the Node.js example in this same file (lines 71-100) still uses the old object form { id: 'hello::api', description: '...' }. This creates an inconsistency within the same documentation page.

If the Node.js API now supports registerFunction('hello::api', handler, { description: '...' }), the TypeScript examples should be updated to match.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/hello-world.mdx` around lines 149 - 154, Update the
Node.js/TypeScript example to match the new string-first API used in Python:
replace the old object form like { id: 'hello::api', description: '...' } with
registerFunction('hello::api', handler, { description: '...' }) and use the new
trigger shape expected by the JS API (e.g., registerTrigger({ type: 'http',
functionId: 'hello::api', config: { apiPath: 'hello', httpMethod: 'GET' } })).
Locate usages of registerFunction/registerTrigger in the Node example and swap
the positional/string-first signature and camelCase trigger keys to mirror the
Python example's intent.
docs/examples/state-management.mdx (1)

89-93: Python update is correct, but cross-language inconsistency remains.

The Python example correctly uses the new string-first register_function API. However, the Node.js example in this same file (lines 27-50) still uses the object form { id: 'users.update_status', description: '...' }.

As per coding guidelines, the shape of arguments to functions should be consistent between SDKs. Consider updating the Node.js examples to use registerFunction('users.update_status', handler, { description: '...' }) if that's the new API shape.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/state-management.mdx` around lines 89 - 93, The Node.js example
is using the old object-form API; update it to the new string-first signature to
match the Python example by calling registerFunction('users.update_status',
handler, { description: '...' }) (and similarly use registerTrigger(...) with
the function id string if applicable). Locate the Node.js example that currently
passes { id: 'users.update_status', description: '...' } and replace it with the
new call shape using the 'users.update_status' string, the handler function
(e.g., updateUserStatus), and an options object for description/config so the
SDK usage is consistent across languages.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 825bcf05-fe6c-4a8e-95e7-f670bab235a1

📥 Commits

Reviewing files that changed from the base of the PR and between 009e80d and 6b448d3.

📒 Files selected for processing (95)
  • docs/advanced/telemetry.mdx
  • docs/api-reference/sdk-browser.mdx
  • docs/api-reference/sdk-node.mdx
  • docs/api-reference/sdk-python.mdx
  • docs/architecture/channels.mdx
  • docs/architecture/trigger-types.mdx
  • docs/examples/conditions.mdx
  • docs/examples/cron.mdx
  • docs/examples/hello-world.mdx
  • docs/examples/multi-trigger.mdx
  • docs/examples/observability.mdx
  • docs/examples/state-management.mdx
  • docs/examples/todo-app.mdx
  • docs/how-to/create-custom-trigger-type.mdx
  • docs/how-to/create-ephemeral-worker.mdx
  • docs/how-to/define-request-response-formats.mdx
  • docs/how-to/expose-http-endpoint.mdx
  • docs/how-to/manage-state.mdx
  • docs/how-to/react-to-state-changes.mdx
  • docs/how-to/schedule-cron-task.mdx
  • docs/how-to/stream-realtime-data.mdx
  • docs/how-to/trigger-actions.mdx
  • docs/how-to/use-channels.mdx
  • docs/how-to/use-functions-and-triggers.mdx
  • docs/how-to/use-http-middleware.mdx
  • docs/how-to/use-iii-in-the-browser.mdx
  • docs/how-to/use-queues.mdx
  • docs/how-to/use-trigger-conditions.mdx
  • docs/how-to/worker-rbac.mdx
  • docs/modules/module-cron.mdx
  • docs/modules/module-http.mdx
  • docs/modules/module-observability.mdx
  • docs/modules/module-pubsub.mdx
  • docs/modules/module-state.mdx
  • docs/modules/module-stream.mdx
  • frameworks/motia/motia-js/packages/motia/__tests__/integration/api-triggers.integration.test.ts
  • frameworks/motia/motia-js/packages/motia/__tests__/integration/bridge.integration.test.ts
  • frameworks/motia/motia-js/packages/motia/__tests__/integration/queue.integration.test.ts
  • frameworks/motia/motia-js/packages/motia/__tests__/motia-utils.test.ts
  • frameworks/motia/motia-js/packages/motia/src/new/build/utils.ts
  • frameworks/motia/motia-js/packages/motia/src/new/setup-step-endpoint.ts
  • sdk/README.md
  • sdk/packages/node/iii-browser/README.md
  • sdk/packages/node/iii-browser/src/iii.ts
  • sdk/packages/node/iii-browser/src/index.ts
  • sdk/packages/node/iii-browser/src/types.ts
  • sdk/packages/node/iii-browser/tests/bridge.test.ts
  • sdk/packages/node/iii-browser/tests/integration/bridge.test.ts
  • sdk/packages/node/iii-browser/tests/integration/channels.test.ts
  • sdk/packages/node/iii-browser/tests/integration/functions-available.test.ts
  • sdk/packages/node/iii-browser/tests/integration/trigger-types.test.ts
  • sdk/packages/node/iii-browser/tests/integration/triggers.test.ts
  • sdk/packages/node/iii-browser/tests/trigger-types.test.ts
  • sdk/packages/node/iii-example/src/hooks.ts
  • sdk/packages/node/iii-example/src/iii-zod-example.ts
  • sdk/packages/node/iii-example/src/middleware-example.ts
  • sdk/packages/node/iii-example/src/queue-basic.ts
  • sdk/packages/node/iii-example/src/queue-bulk-email.ts
  • sdk/packages/node/iii-example/src/queue-dlq.ts
  • sdk/packages/node/iii-example/src/queue-ecommerce.ts
  • sdk/packages/node/iii-example/src/queue-financial.ts
  • sdk/packages/node/iii-example/src/trigger-types.ts
  • sdk/packages/node/iii/README.md
  • sdk/packages/node/iii/src/iii.ts
  • sdk/packages/node/iii/src/index.ts
  • sdk/packages/node/iii/src/types.ts
  • sdk/packages/node/iii/src/utils.ts
  • sdk/packages/node/iii/tests/api-triggers.test.ts
  • sdk/packages/node/iii/tests/bridge.test.ts
  • sdk/packages/node/iii/tests/data-channels.test.ts
  • sdk/packages/node/iii/tests/healthcheck.test.ts
  • sdk/packages/node/iii/tests/http-external-functions.test.ts
  • sdk/packages/node/iii/tests/logger-runtime.test.ts
  • sdk/packages/node/iii/tests/middleware.test.ts
  • sdk/packages/node/iii/tests/pubsub.test.ts
  • sdk/packages/node/iii/tests/queue.test.ts
  • sdk/packages/node/iii/tests/rbac-workers.test.ts
  • sdk/packages/node/iii/tests/service-triggers.test.ts
  • sdk/packages/node/iii/tests/state.test.ts
  • website/components/Terminal.tsx
  • website/components/demo/homepage-script.ts
  • website/components/sections/AgentReadySection.tsx
  • website/components/sections/DependencyVisualization.tsx
  • website/components/sections/EngineSection.tsx
  • website/components/sections/code-examples/iii/ai-agents.ts
  • website/components/sections/code-examples/iii/api.ts
  • website/components/sections/code-examples/iii/cron.ts
  • website/components/sections/code-examples/iii/etl.ts
  • website/components/sections/code-examples/iii/feature-flags.ts
  • website/components/sections/code-examples/iii/jobs.ts
  • website/components/sections/code-examples/iii/pubsub.ts
  • website/components/sections/code-examples/iii/reactive.ts
  • website/components/sections/code-examples/iii/realtime.ts
  • website/components/sections/code-examples/iii/state.ts
  • website/components/sections/code-examples/iii/workflow.ts

Comment on lines +782 to 785
### RegisterFunctionOptions

Input for registering a function — matches Node.js RegisterFunctionInput.
Optional configuration passed as keyword arguments when using the string ID form of `register_function`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Drop the stale “string ID form” wording.

register_function is now documented with a required function_id: str, so this still implies the old object-based overload exists. Please rename this section and scrub the earlier func_or_id wording so the reference matches the new API.

Suggested wording
-Optional configuration passed as keyword arguments when using the string ID form of `register_function`.
+Optional keyword arguments accepted by `register_function`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### RegisterFunctionOptions
Input for registering a function — matches Node.js RegisterFunctionInput.
Optional configuration passed as keyword arguments when using the string ID form of `register_function`.
### RegisterFunctionOptions
Optional keyword arguments accepted by `register_function`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/api-reference/sdk-python.mdx` around lines 782 - 785, Rename the section
and remove stale "string ID form" wording: update the heading and description
for RegisterFunctionOptions to reflect the current API that register_function
requires function_id: str (remove references to "string ID form" and any
mentions of func_or_id), and ensure all earlier occurrences in this document
that mention func_or_id or the old object-based overload are scrubbed or
rewritten to reference the new required parameter name function_id and the
current usage of register_function.

const iii = registerWorker('ws://localhost:49134')
iii.registerFunction({ id: 'metrics::collect' }, async () => {
iii.registerFunction('metrics::collect', async () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Finish the API migration in this guide to avoid mixed registerFunction signatures.

Line 98 is updated, but this page still uses the old object form at Line 72, Line 127, Line 151, Line 165, and Line 198. Keeping both forms in one guide is confusing and out of sync with the SDK migration.

Suggested doc patch
 iii.registerFunction(
-  { id: 'ui::show-notification' },
+  'ui::show-notification',
   async (data: { title: string; body: string }) => {
@@
 iii.registerFunction(
-  { id: 'ui::update-dashboard' },
+  'ui::update-dashboard',
   async (metrics: { cpu: number; memory: number; requests: number }) => {
@@
 iii.registerFunction(
-  { id: 'tasks::create' },
+  'tasks::create',
   async (input: { title: string; assignee: string }) => {
@@
 iii.registerFunction(
-  { id: 'tasks::list' },
+  'tasks::list',
   async () => {
@@
 iii.registerFunction(
-  { id: 'ui::tasks-updated' },
+  'ui::tasks-updated',
   async (data: { tasks: Array<{ taskId: string; title: string; status: string }> }) => {

As per coding guidelines, docs under docs/** must be consistent with sdk/ functionality.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/how-to/use-iii-in-the-browser.mdx` at line 98, The guide mixes the old
object-form iii.registerFunction({...}) calls with the new string+function
signature; update every object-form usage of iii.registerFunction (the
occurrences using { name: ..., handler: ..., ... }) to the new API: call
iii.registerFunction('function::name', async (ctx, args) => { ... }) passing the
handler as the second argument and moving any metadata/permissions into the new
options shape or separate API that matches the SDK; specifically replace the
object key "name" with the first string argument and "handler" with the async
function argument (preserve the handler body), and ensure the function parameter
list matches the SDK's context/args signature used elsewhere in the guide so all
examples (other iii.registerFunction usages) are consistent.

export type RegisterTriggerInput = Omit<RegisterTriggerMessage, 'message_type' | 'id'>
export type RegisterServiceInput = Omit<RegisterServiceMessage, 'message_type'>
export type RegisterFunctionInput = Omit<RegisterFunctionMessage, 'message_type'>
export type RegisterFunctionOptions = Omit<RegisterFunctionMessage, 'message_type' | 'id'>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

RegisterFunctionOptions still exposes the wire-only invocation field.

RegisterFunctionMessage includes invocation, so this Omit lets callers pass options.invocation even though the second parameter already owns that data. That creates an invalid public API surface and can change registration semantics for local handlers.

Safer type shape
-export type RegisterFunctionOptions = Omit<RegisterFunctionMessage, 'message_type' | 'id'>
+export type RegisterFunctionOptions = Pick<
+  RegisterFunctionMessage,
+  'description' | 'metadata' | 'request_format' | 'response_format'
+>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/packages/node/iii-browser/src/types.ts` at line 67, The exported
RegisterFunctionOptions type currently re-exports the wire-only field invocation
from RegisterFunctionMessage; update the type so callers cannot provide
invocation. Replace the Omit to also exclude 'invocation' (i.e.,
Omit<RegisterFunctionMessage, 'message_type' | 'id' | 'invocation'>) or
otherwise redefine RegisterFunctionOptions to pick only the fields that are
valid for public registration, referencing RegisterFunctionOptions,
RegisterFunctionMessage, and the invocation field when making the change.

Comment on lines +357 to +364
* cron.registerFunction(
* 'my-fn',
* async (data) => { return { ok: true } },
* { schedule: '* * * * *' },
* { description: 'Cron-triggered function' },
* )
* ```
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

TriggerTypeRef.registerFunction is missing the new options bag.

The example above now uses a 4th { description: ... } argument, but the signature still only accepts (functionId, handler, config). More importantly, trigger-scoped registrations no longer have any way to set the function description or request/response schemas.

Suggested signature update
-  registerFunction(functionId: string, handler: RemoteFunctionHandler, config: TConfig): FunctionRef
+  registerFunction(
+    functionId: string,
+    handler: RemoteFunctionHandler,
+    config: TConfig,
+    options?: RegisterFunctionOptions,
+  ): FunctionRef

Also applies to: 379-384

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/packages/node/iii-browser/src/types.ts` around lines 357 - 364, Update
the TriggerTypeRef.registerFunction signature to accept the new options bag as a
fourth parameter (e.g., registerFunction(functionId: string, handler: Handler,
config: Config, options?: { description?: string; requestSchema?: JSONSchema;
responseSchema?: JSONSchema; [k: string]: any })), update any overloads or
related declarations (the other registerFunction occurrence) to the same shape,
and ensure types used in the options (description, requestSchema,
responseSchema) reference existing JSON schema/type aliases in this file so
trigger-scoped registrations can set description and request/response schemas.

export type RegisterTriggerInput = Omit<RegisterTriggerMessage, 'message_type' | 'id'>
export type RegisterServiceInput = Omit<RegisterServiceMessage, 'message_type'>
export type RegisterFunctionInput = Omit<RegisterFunctionMessage, 'message_type'>
export type RegisterFunctionOptions = Omit<RegisterFunctionMessage, 'message_type' | 'id'>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

RegisterFunctionOptions should not inherit invocation.

Using Omit<RegisterFunctionMessage, 'message_type' | 'id'> still leaves the transport-only invocation field on the public options bag. That overlaps with the second handler | HttpInvocationConfig parameter and exposes an invalid combination to callers.

Safer type shape
-export type RegisterFunctionOptions = Omit<RegisterFunctionMessage, 'message_type' | 'id'>
+export type RegisterFunctionOptions = Pick<
+  RegisterFunctionMessage,
+  'description' | 'metadata' | 'request_format' | 'response_format'
+>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/packages/node/iii/src/types.ts` at line 95, RegisterFunctionOptions
currently inherits the transport-only field invocation via
Omit<RegisterFunctionMessage, 'message_type' | 'id'>; update the type so
invocation is also excluded (e.g., remove 'invocation' from the Omit) so callers
can't pass the transport-only field alongside the second parameter (handler |
HttpInvocationConfig). Change the definition referencing RegisterFunctionOptions
/ RegisterFunctionMessage to explicitly omit 'invocation' as well to ensure the
public options bag doesn't expose the transport field.

Comment on lines +397 to +403
* cron.registerFunction(
* 'my-fn',
* async (data) => { return { ok: true } },
* { schedule: '* * * * *' },
* { description: 'Cron-triggered function' },
* )
* ```
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

The 4th arg here is still trigger metadata, not function options.

The updated example passes { description: 'Cron-triggered function' } as arg 4, but this signature still types that slot as trigger metadata. Users following the example will not actually set the function description, and after removing RegisterFunctionInput there is no dedicated path left for function-level options on this helper.

Also applies to: 420-426

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/packages/node/iii/src/types.ts` around lines 397 - 403, The example for
cron.registerFunction incorrectly places function-level options in the 4th
argument (which is typed as trigger metadata); change the example so the 4th arg
remains trigger metadata and pass function options (e.g., { description:
'Cron-triggered function' }) as the 5th argument to match the register signature
used by cron.registerFunction; update the other occurrences noted (around the
block at lines 420-426) so all examples show trigger metadata in arg4 and
function options in arg5, and ensure references to RegisterFunctionInput or
removed types are not used in the example.

- Changed the `registerFunction` signature to require `options` and clarify the `handler` type.
- Enhanced documentation for `registerFunction`, including examples for local and HTTP invocation.
- Removed deprecated `HttpAuthConfig` and `HttpInvocationConfig` types from the browser SDK.
- Updated type definitions for `RegisterFunctionFormat` to include `integer` and improved property types.
- Cleaned up test cases to ensure consistent error handling and expectations.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
sdk/packages/node/iii-browser/src/iii.ts (1)

145-153: TriggerTypeRef.registerFunction doesn't forward function options.

The wrapper signature accepts (functionId, handler, config) but the underlying this.registerFunction now supports an optional options parameter for description, metadata, and schemas. Users registering functions via trigger type helpers cannot set these function-level options.

Consider adding an optional options parameter to align with the full registerFunction capability:

Suggested improvement
-      registerFunction: (functionId, handler, config) => {
-        const ref = this.registerFunction(functionId, handler)
+      registerFunction: (functionId, handler, config, options) => {
+        const ref = this.registerFunction(functionId, handler, options)
         this.registerTrigger({
           type: triggerType.id,
           function_id: functionId,
           config,
         })
         return ref
       },

This would also require updating the TriggerTypeRef interface in types.ts to include the optional parameter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/packages/node/iii-browser/src/iii.ts` around lines 145 - 153, The wrapper
registerFunction on TriggerTypeRef currently accepts (functionId, handler,
config) but drops the optional function-level options; update the signature in
iii.ts to accept (functionId, handler, config, options?) and pass options
through to this.registerFunction(functionId, handler, options), while still
calling this.registerTrigger with config; also update the TriggerTypeRef
interface in types.ts to include the optional options parameter (matching the
existing registerFunction options type for description/metadata/schemas) so
callers can set function options when using trigger-type helpers.
sdk/packages/node/iii/src/types.ts (1)

431-436: TriggerTypeRef.registerFunction lacks function options parameter.

Similar to the browser SDK, this helper only accepts trigger metadata but doesn't allow passing function-level options (description, request_format, response_format, function metadata).

Consider extending the signature:

Suggested improvement
   registerFunction(
     functionId: string,
     handler: RemoteFunctionHandler,
     config: TConfig,
     metadata?: Record<string, unknown>,
+    options?: RegisterFunctionOptions,
   ): FunctionRef

As per coding guidelines, this should be symmetric with the browser SDK helper. If the browser SDK is also updated, both should support function options.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/packages/node/iii/src/types.ts` around lines 431 - 436,
TriggerTypeRef.registerFunction currently omits a function-level options
parameter (so only metadata can be passed); update its signature to accept an
optional "options" argument (e.g., functionOptions) alongside metadata to carry
description, request_format, response_format and function-specific metadata,
ensuring the types (FunctionRef, RemoteFunctionHandler, TConfig) are updated to
accept and propagate these options, and mirror the browser SDK helper's
signature so both SDKs remain symmetric. Ensure any internal callers and return
types are adjusted to forward the new options through the registration flow.
sdk/packages/node/iii-browser/src/channels.ts (1)

104-109: Error callback discards failure details.

The reject callback now logs a generic message but doesn't capture or log the actual error. When sendRaw queues a message and the WebSocket fails (triggering the error handler at lines 49-54), the specific error information is lost.

Consider capturing the error
       reject: () => {
-        console.error('Failed to send message')
+        console.error('Failed to send message', err)
       },

However, since sendRaw is synchronous and the rejection happens asynchronously in the error handler, the error object isn't available here. The current approach silently degrades error visibility compared to the actual WebSocket error event.

This is a minor observability concern for debugging channel failures.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/packages/node/iii-browser/src/channels.ts` around lines 104 - 109, The
reject callback currently logs a generic message and drops the real failure
details; update the queued promise callbacks created in sendRaw so reject
accepts an error parameter (e.g., reject(err)) and logs or forwards that error
instead of the static string, and then modify the WebSocket error handler (the
handler that iterates queued callbacks) to call each stored reject with the
actual Error/event it receives so the original WebSocket error is preserved when
the queued send promises are rejected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sdk/packages/node/iii-browser/src/iii.ts`:
- Around line 214-240: The JSDoc for registerFunction incorrectly references
HttpInvocationConfig which the browser SDK doesn't support; update the comment
above the registerFunction method (and any mention near RemoteFunctionHandler
and RegisterFunctionOptions) to remove the {`@link` HttpInvocationConfig}
reference and describe that handlerOrInvocation accepts only a
RemoteFunctionHandler for local/browser execution (no HTTP-invocation config
supported), ensuring the param and example text align with the actual signature.

---

Nitpick comments:
In `@sdk/packages/node/iii-browser/src/channels.ts`:
- Around line 104-109: The reject callback currently logs a generic message and
drops the real failure details; update the queued promise callbacks created in
sendRaw so reject accepts an error parameter (e.g., reject(err)) and logs or
forwards that error instead of the static string, and then modify the WebSocket
error handler (the handler that iterates queued callbacks) to call each stored
reject with the actual Error/event it receives so the original WebSocket error
is preserved when the queued send promises are rejected.

In `@sdk/packages/node/iii-browser/src/iii.ts`:
- Around line 145-153: The wrapper registerFunction on TriggerTypeRef currently
accepts (functionId, handler, config) but drops the optional function-level
options; update the signature in iii.ts to accept (functionId, handler, config,
options?) and pass options through to this.registerFunction(functionId, handler,
options), while still calling this.registerTrigger with config; also update the
TriggerTypeRef interface in types.ts to include the optional options parameter
(matching the existing registerFunction options type for
description/metadata/schemas) so callers can set function options when using
trigger-type helpers.

In `@sdk/packages/node/iii/src/types.ts`:
- Around line 431-436: TriggerTypeRef.registerFunction currently omits a
function-level options parameter (so only metadata can be passed); update its
signature to accept an optional "options" argument (e.g., functionOptions)
alongside metadata to carry description, request_format, response_format and
function-specific metadata, ensuring the types (FunctionRef,
RemoteFunctionHandler, TConfig) are updated to accept and propagate these
options, and mirror the browser SDK helper's signature so both SDKs remain
symmetric. Ensure any internal callers and return types are adjusted to forward
the new options through the registration flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 986488d7-bc5a-49de-98aa-83e04a8432e4

📥 Commits

Reviewing files that changed from the base of the PR and between 6b448d3 and de6338d.

📒 Files selected for processing (14)
  • docs/api-reference/sdk-browser.mdx
  • docs/api-reference/sdk-node.mdx
  • sdk/packages/node/iii-browser/src/channels.ts
  • sdk/packages/node/iii-browser/src/iii-types.ts
  • sdk/packages/node/iii-browser/src/iii.ts
  • sdk/packages/node/iii-browser/src/index.ts
  • sdk/packages/node/iii-browser/src/types.ts
  • sdk/packages/node/iii-browser/tests/bridge.test.ts
  • sdk/packages/node/iii-browser/tests/channels.test.ts
  • sdk/packages/node/iii-browser/tests/mock-websocket.ts
  • sdk/packages/node/iii-browser/tests/trigger-types.test.ts
  • sdk/packages/node/iii-browser/tests/triggers.test.ts
  • sdk/packages/node/iii/src/iii-types.ts
  • sdk/packages/node/iii/src/types.ts
✅ Files skipped from review due to trivial changes (2)
  • sdk/packages/node/iii-browser/tests/channels.test.ts
  • sdk/packages/node/iii-browser/tests/mock-websocket.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • sdk/packages/node/iii-browser/src/index.ts
  • sdk/packages/node/iii-browser/tests/bridge.test.ts
  • sdk/packages/node/iii-browser/tests/trigger-types.test.ts
  • docs/api-reference/sdk-node.mdx
  • docs/api-reference/sdk-browser.mdx
  • sdk/packages/node/iii-browser/src/types.ts

Comment on lines 214 to +240
/**
* Registers a function with the engine. The `id` is the unique identifier
* Registers a function with the engine. The `functionId` is the unique identifier
* used by triggers and invocations.
*
* Pass a handler for local execution, or an {@link HttpInvocationConfig}
* for HTTP-invoked functions (Lambda, Cloudflare Workers, etc.).
*
* @param message - Function registration input.
* @param message.id - Unique function identifier.
* @param message.description - Human-readable description.
* @param functionId - Unique function identifier.
* @param handlerOrInvocation - Async handler or HTTP invocation config.
* @param options - Optional function registration options (description, request/response formats, metadata).
* @returns A {@link FunctionRef} with `id` and `unregister()`.
*
* @example
* ```typescript
* const fn = iii.registerFunction(
* { id: 'greet', description: 'Greets a user' },
* 'greet',
* async (input: { name: string }) => {
* return { message: `Hello, ${input.name}!` }
* },
* { description: 'Greets a user' },
* )
* ```
*/
registerFunction = (
message: Omit<RegisterFunctionMessage, 'message_type'>,
handlerOrInvocation: RemoteFunctionHandler | HttpInvocationConfig,
functionId: string,
handlerOrInvocation: RemoteFunctionHandler,
options?: RegisterFunctionOptions,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

JSDoc references HttpInvocationConfig but browser SDK doesn't support it.

The JSDoc at lines 218-219 mentions "Pass a handler for local execution, or an {@link HttpInvocationConfig} for HTTP-invoked functions", but:

  1. The parameter type is RemoteFunctionHandler only (not a union with HttpInvocationConfig)
  2. Browser SDK removed HttpInvocationConfig type entirely

Update the JSDoc to reflect the browser SDK's actual capability:

Suggested fix
   /**
-   * Registers a function with the engine. The `functionId` is the unique identifier
+   * Registers a function with the engine. The `functionId` is the unique identifier
    * used by triggers and invocations.
    *
-   * Pass a handler for local execution, or an {`@link` HttpInvocationConfig}
-   * for HTTP-invoked functions (Lambda, Cloudflare Workers, etc.).
-   *
    * `@param` functionId - Unique function identifier.
-   * `@param` handlerOrInvocation - Async handler or HTTP invocation config.
+   * `@param` handler - Async handler for local execution.
    * `@param` options - Optional function registration options (description, request/response formats, metadata).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Registers a function with the engine. The `id` is the unique identifier
* Registers a function with the engine. The `functionId` is the unique identifier
* used by triggers and invocations.
*
* Pass a handler for local execution, or an {@link HttpInvocationConfig}
* for HTTP-invoked functions (Lambda, Cloudflare Workers, etc.).
*
* @param message - Function registration input.
* @param message.id - Unique function identifier.
* @param message.description - Human-readable description.
* @param functionId - Unique function identifier.
* @param handlerOrInvocation - Async handler or HTTP invocation config.
* @param options - Optional function registration options (description, request/response formats, metadata).
* @returns A {@link FunctionRef} with `id` and `unregister()`.
*
* @example
* ```typescript
* const fn = iii.registerFunction(
* { id: 'greet', description: 'Greets a user' },
* 'greet',
* async (input: { name: string }) => {
* return { message: `Hello, ${input.name}!` }
* },
* { description: 'Greets a user' },
* )
* ```
*/
registerFunction = (
message: Omit<RegisterFunctionMessage, 'message_type'>,
handlerOrInvocation: RemoteFunctionHandler | HttpInvocationConfig,
functionId: string,
handlerOrInvocation: RemoteFunctionHandler,
options?: RegisterFunctionOptions,
/**
* Registers a function with the engine. The `functionId` is the unique identifier
* used by triggers and invocations.
*
* `@param` functionId - Unique function identifier.
* `@param` handlerOrInvocation - Async handler for local execution.
* `@param` options - Optional function registration options (description, request/response formats, metadata).
* `@returns` A {`@link` FunctionRef} with `id` and `unregister()`.
*
* `@example`
*
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/packages/node/iii-browser/src/iii.ts` around lines 214 - 240, The JSDoc
for registerFunction incorrectly references HttpInvocationConfig which the
browser SDK doesn't support; update the comment above the registerFunction
method (and any mention near RemoteFunctionHandler and RegisterFunctionOptions)
to remove the {`@link` HttpInvocationConfig} reference and describe that
handlerOrInvocation accepts only a RemoteFunctionHandler for local/browser
execution (no HTTP-invocation config supported), ensuring the param and example
text align with the actual signature.

@sergiofilhowz sergiofilhowz merged commit 6a493d1 into main Apr 2, 2026
23 checks passed
@sergiofilhowz sergiofilhowz deleted the feat/register-fn-node-sdk branch April 2, 2026 19:52
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