hypha-rpc 0.21.35 → 0.21.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -1
- package/coverage/html/index.html +1 -1
- package/dist/hypha-rpc-websocket.js +49 -1
- package/dist/hypha-rpc-websocket.js.map +1 -1
- package/dist/hypha-rpc-websocket.min.js +1 -1
- package/dist/hypha-rpc-websocket.min.js.map +1 -1
- package/dist/hypha-rpc-websocket.min.mjs +1 -1
- package/dist/hypha-rpc-websocket.min.mjs.map +1 -1
- package/dist/hypha-rpc-websocket.mjs +49 -1
- package/dist/hypha-rpc-websocket.mjs.map +1 -1
- package/package.json +1 -1
- package/src/rpc.js +48 -1
package/README.md
CHANGED
|
@@ -24,4 +24,75 @@ hyphaWebsocketClient.connectToServer({
|
|
|
24
24
|
}
|
|
25
25
|
)
|
|
26
26
|
})
|
|
27
|
-
```
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Keyword Arguments (kwargs)
|
|
30
|
+
|
|
31
|
+
Hypha RPC supports Python-style keyword arguments when calling JavaScript services. This works seamlessly across Python→JS and JS→JS calls.
|
|
32
|
+
|
|
33
|
+
#### Calling from Python to JavaScript
|
|
34
|
+
|
|
35
|
+
When a Python client calls a JS service using keyword arguments, they are automatically unpacked into the matching positional parameters:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
# Python caller
|
|
39
|
+
svc = await server.get_service("my-js-service")
|
|
40
|
+
result = await svc.greet(name="Alice", greeting="Hello")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
// JavaScript service — params are matched by name
|
|
45
|
+
await api.registerService({
|
|
46
|
+
id: "my-js-service",
|
|
47
|
+
greet(name, greeting) {
|
|
48
|
+
return `${greeting}, ${name}!`; // "Hello, Alice!"
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### Calling from JavaScript to JavaScript
|
|
54
|
+
|
|
55
|
+
Use the `_rkwargs: true` flag to send keyword arguments from JS:
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const svc = await api.getService("my-js-service");
|
|
59
|
+
|
|
60
|
+
// Positional (traditional)
|
|
61
|
+
await svc.greet("Alice", "Hello");
|
|
62
|
+
|
|
63
|
+
// Keyword arguments — params matched by name, order doesn't matter
|
|
64
|
+
await svc.greet({ greeting: "Hello", name: "Alice", _rkwargs: true });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### With `require_context`
|
|
68
|
+
|
|
69
|
+
When a service uses `require_context: true`, the `context` parameter is automatically injected by the server and cannot be overridden via kwargs:
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
await api.registerService({
|
|
73
|
+
id: "secure-svc",
|
|
74
|
+
config: { require_context: true },
|
|
75
|
+
greet(name, greeting, context) {
|
|
76
|
+
console.log("Called by:", context.user);
|
|
77
|
+
return `${greeting}, ${name}!`;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Caller — context is injected automatically, not passed by the caller
|
|
82
|
+
await svc.greet({ name: "Alice", greeting: "Hello", _rkwargs: true });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### With `kwargs_expansion`
|
|
86
|
+
|
|
87
|
+
For convenience when calling server APIs, connect with `kwargs_expansion: true` to automatically convert the last object argument to kwargs:
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
const api = await connectToServer({
|
|
91
|
+
server_url: "https://ai.imjoy.io",
|
|
92
|
+
kwargs_expansion: true,
|
|
93
|
+
});
|
|
94
|
+
// The last object arg is automatically sent as kwargs
|
|
95
|
+
const token = await api.generateToken({ config: { workspace: "my-ws" } });
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
> **Note:** Kwargs unpacking relies on parsing function parameter names from source code. This works with regular functions, arrow functions, and async functions, but will not work with minified/bundled code where parameter names are mangled.
|
package/coverage/html/index.html
CHANGED
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
87
87
|
Code coverage generated by
|
|
88
88
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
89
|
-
at 2026-03-
|
|
89
|
+
at 2026-03-11T17:52:10.251Z
|
|
90
90
|
</div>
|
|
91
91
|
<script src="prettify.js"></script>
|
|
92
92
|
<script>
|
|
@@ -3439,7 +3439,8 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
3439
3439
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
3440
3440
|
/* harmony export */ API_VERSION: () => (/* binding */ API_VERSION),
|
|
3441
3441
|
/* harmony export */ RPC: () => (/* binding */ RPC),
|
|
3442
|
-
/* harmony export */ _applyEncryptionKeyToService: () => (/* binding */ _applyEncryptionKeyToService)
|
|
3442
|
+
/* harmony export */ _applyEncryptionKeyToService: () => (/* binding */ _applyEncryptionKeyToService),
|
|
3443
|
+
/* harmony export */ getParamNames: () => (/* binding */ getParamNames)
|
|
3443
3444
|
/* harmony export */ });
|
|
3444
3445
|
/* harmony import */ var _utils_index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/index.js */ "./src/utils/index.js");
|
|
3445
3446
|
/* harmony import */ var _utils_schema_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils/schema.js */ "./src/utils/schema.js");
|
|
@@ -3456,6 +3457,35 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
3456
3457
|
|
|
3457
3458
|
|
|
3458
3459
|
|
|
3460
|
+
/**
|
|
3461
|
+
* Extract parameter names from a function's source text.
|
|
3462
|
+
* Works with regular functions, arrow functions, async functions,
|
|
3463
|
+
* destructured params, default values, and rest params.
|
|
3464
|
+
* Note: will not work with minified/bundled code where param names are mangled.
|
|
3465
|
+
* @param {Function} fn - The function to inspect.
|
|
3466
|
+
* @returns {string[]} Array of parameter names.
|
|
3467
|
+
*/
|
|
3468
|
+
function getParamNames(fn) {
|
|
3469
|
+
const src = fn.toString();
|
|
3470
|
+
// Match: function(a, b), async function name(a, b), (a, b) =>, async (a, b) =>
|
|
3471
|
+
// Also handles single param arrow without parens: a =>
|
|
3472
|
+
const match = src.match(
|
|
3473
|
+
/^(?:async\s+)?(?:function\s*\w*)?\s*\(([^)]*)\)|^(?:async\s+)?(\w+)\s*=>/,
|
|
3474
|
+
);
|
|
3475
|
+
if (!match) return [];
|
|
3476
|
+
const paramStr = match[1] !== undefined ? match[1] : match[2];
|
|
3477
|
+
if (!paramStr || !paramStr.trim()) return [];
|
|
3478
|
+
return paramStr
|
|
3479
|
+
.split(",")
|
|
3480
|
+
.map((p) =>
|
|
3481
|
+
p
|
|
3482
|
+
.trim()
|
|
3483
|
+
.replace(/\s*=.*$/, "") // strip default values
|
|
3484
|
+
.replace(/^\.\.\.\s*/, ""), // strip rest operator
|
|
3485
|
+
)
|
|
3486
|
+
.filter(Boolean);
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3459
3489
|
/**
|
|
3460
3490
|
* Apply an out-of-band encryption public key to all remote methods in a service.
|
|
3461
3491
|
* @param {Object} svc - The decoded service object.
|
|
@@ -6404,6 +6434,24 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
|
|
|
6404
6434
|
} else {
|
|
6405
6435
|
args = [];
|
|
6406
6436
|
}
|
|
6437
|
+
|
|
6438
|
+
// Unpack kwargs into positional arguments when with_kwargs is set.
|
|
6439
|
+
// This mirrors Python's _handle_method which pops the last arg as
|
|
6440
|
+
// a kwargs dict and passes it via **kwargs. Since JS doesn't have
|
|
6441
|
+
// **kwargs, we map the dict keys to the function's parameter names.
|
|
6442
|
+
if (data.with_kwargs && args.length > 0) {
|
|
6443
|
+
const kwargs = args.pop();
|
|
6444
|
+
if (typeof kwargs === "object" && kwargs !== null) {
|
|
6445
|
+
const paramNames = getParamNames(method);
|
|
6446
|
+
// Filter out 'context' — it's handled separately by require_context
|
|
6447
|
+
const mappableParams = paramNames.filter((n) => n !== "context");
|
|
6448
|
+
args = mappableParams.map((name) => kwargs[name]);
|
|
6449
|
+
} else {
|
|
6450
|
+
// Not a dict — push it back (shouldn't happen, but be safe)
|
|
6451
|
+
args.push(kwargs);
|
|
6452
|
+
}
|
|
6453
|
+
}
|
|
6454
|
+
|
|
6407
6455
|
if (
|
|
6408
6456
|
this._method_annotations.has(method) &&
|
|
6409
6457
|
this._method_annotations.get(method).require_context
|