nvent 0.5.15 → 1.0.0-alpha.2
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/dist/module.d.mts +181 -8
- package/dist/module.json +1 -1
- package/dist/module.mjs +1257 -1196
- package/dist/runtime/app/composables/useFunctionCall.d.ts +17 -0
- package/dist/runtime/app/composables/useFunctionCall.js +25 -0
- package/dist/runtime/app/composables/useNventStream.d.ts +23 -0
- package/dist/runtime/app/composables/useNventStream.js +58 -0
- package/dist/runtime/nitro/plugins/00.iii-lifecycle.d.ts +19 -0
- package/dist/runtime/nitro/plugins/00.iii-lifecycle.js +62 -0
- package/dist/runtime/nitro/plugins/01.iii-worker.d.ts +15 -0
- package/dist/runtime/nitro/plugins/01.iii-worker.js +91 -0
- package/dist/runtime/nitro/routes/stream-proxy.d.ts +17 -0
- package/dist/runtime/nitro/routes/stream-proxy.js +45 -0
- package/dist/runtime/nitro/utils/console.d.ts +32 -0
- package/dist/runtime/nitro/utils/console.js +95 -0
- package/dist/runtime/nitro/utils/defineFunction.d.ts +378 -3
- package/dist/runtime/nitro/utils/defineFunction.js +224 -4
- package/dist/runtime/nitro/utils/engine.d.ts +25 -0
- package/dist/runtime/nitro/utils/engine.js +130 -0
- package/dist/runtime/nitro/utils/nventDir.d.ts +1 -0
- package/dist/runtime/nitro/utils/nventDir.js +20 -0
- package/dist/runtime/nitro/utils/useIii.d.ts +23 -0
- package/dist/runtime/nitro/utils/useIii.js +14 -0
- package/dist/runtime/nitro/utils/workers/node.d.ts +24 -0
- package/dist/runtime/nitro/utils/workers/node.js +57 -0
- package/dist/runtime/nitro/utils/workers/python.d.ts +67 -0
- package/dist/runtime/nitro/utils/workers/python.js +220 -0
- package/dist/runtime/python/nvent.py +208 -0
- package/dist/runtime/python/worker_runtime.py +659 -0
- package/dist/runtime/virtual.d.ts +17 -0
- package/dist/types.d.mts +5 -1
- package/package.json +11 -14
- package/dist/runtime/adapters/base/index.d.ts +0 -6
- package/dist/runtime/adapters/base/index.js +0 -1
- package/dist/runtime/adapters/base/store-validator.d.ts +0 -48
- package/dist/runtime/adapters/base/store-validator.js +0 -147
- package/dist/runtime/adapters/builtin/file-queue.d.ts +0 -67
- package/dist/runtime/adapters/builtin/file-queue.js +0 -499
- package/dist/runtime/adapters/builtin/file-store.d.ts +0 -32
- package/dist/runtime/adapters/builtin/file-store.js +0 -206
- package/dist/runtime/adapters/builtin/file-stream.d.ts +0 -39
- package/dist/runtime/adapters/builtin/file-stream.js +0 -56
- package/dist/runtime/adapters/builtin/index.d.ts +0 -10
- package/dist/runtime/adapters/builtin/index.js +0 -5
- package/dist/runtime/adapters/builtin/memory-queue.d.ts +0 -52
- package/dist/runtime/adapters/builtin/memory-queue.js +0 -243
- package/dist/runtime/adapters/builtin/memory-store.d.ts +0 -69
- package/dist/runtime/adapters/builtin/memory-store.js +0 -357
- package/dist/runtime/adapters/builtin/memory-stream.d.ts +0 -21
- package/dist/runtime/adapters/builtin/memory-stream.js +0 -56
- package/dist/runtime/adapters/factory.d.ts +0 -31
- package/dist/runtime/adapters/factory.js +0 -135
- package/dist/runtime/adapters/index.d.ts +0 -8
- package/dist/runtime/adapters/index.js +0 -3
- package/dist/runtime/adapters/interfaces/index.d.ts +0 -11
- package/dist/runtime/adapters/interfaces/index.js +0 -3
- package/dist/runtime/adapters/interfaces/queue.d.ts +0 -155
- package/dist/runtime/adapters/interfaces/queue.js +0 -0
- package/dist/runtime/adapters/interfaces/store.d.ts +0 -299
- package/dist/runtime/adapters/interfaces/store.js +0 -0
- package/dist/runtime/adapters/interfaces/stream.d.ts +0 -62
- package/dist/runtime/adapters/interfaces/stream.js +0 -0
- package/dist/runtime/adapters/registry.d.ts +0 -85
- package/dist/runtime/adapters/registry.js +0 -161
- package/dist/runtime/config/index.d.ts +0 -23
- package/dist/runtime/config/index.js +0 -200
- package/dist/runtime/config/types.d.ts +0 -439
- package/dist/runtime/config/types.js +0 -0
- package/dist/runtime/events/eventBus.d.ts +0 -20
- package/dist/runtime/events/eventBus.js +0 -35
- package/dist/runtime/events/types.d.ts +0 -144
- package/dist/runtime/events/types.js +0 -0
- package/dist/runtime/events/utils/scheduleTrigger.d.ts +0 -8
- package/dist/runtime/events/utils/scheduleTrigger.js +0 -71
- package/dist/runtime/events/utils/stallDetector.d.ts +0 -83
- package/dist/runtime/events/utils/stallDetector.js +0 -318
- package/dist/runtime/events/utils/triggerRuntime.d.ts +0 -58
- package/dist/runtime/events/utils/triggerRuntime.js +0 -212
- package/dist/runtime/events/wiring/flowWiring.d.ts +0 -34
- package/dist/runtime/events/wiring/flowWiring.js +0 -1258
- package/dist/runtime/events/wiring/registry.d.ts +0 -19
- package/dist/runtime/events/wiring/registry.js +0 -43
- package/dist/runtime/events/wiring/stateWiring.d.ts +0 -37
- package/dist/runtime/events/wiring/stateWiring.js +0 -92
- package/dist/runtime/events/wiring/streamWiring.d.ts +0 -36
- package/dist/runtime/events/wiring/streamWiring.js +0 -156
- package/dist/runtime/events/wiring/triggerWiring.d.ts +0 -21
- package/dist/runtime/events/wiring/triggerWiring.js +0 -422
- package/dist/runtime/nitro/plugins/00.adapters.d.ts +0 -14
- package/dist/runtime/nitro/plugins/00.adapters.js +0 -73
- package/dist/runtime/nitro/plugins/01.ws-lifecycle.d.ts +0 -5
- package/dist/runtime/nitro/plugins/01.ws-lifecycle.js +0 -69
- package/dist/runtime/nitro/plugins/02.workers.d.ts +0 -2
- package/dist/runtime/nitro/plugins/02.workers.js +0 -92
- package/dist/runtime/nitro/plugins/03.triggers.d.ts +0 -12
- package/dist/runtime/nitro/plugins/03.triggers.js +0 -55
- package/dist/runtime/nitro/routes/webhook.await.d.ts +0 -23
- package/dist/runtime/nitro/routes/webhook.await.js +0 -112
- package/dist/runtime/nitro/routes/webhook.trigger.d.ts +0 -86
- package/dist/runtime/nitro/routes/webhook.trigger.js +0 -73
- package/dist/runtime/nitro/utils/adapters.d.ts +0 -66
- package/dist/runtime/nitro/utils/adapters.js +0 -51
- package/dist/runtime/nitro/utils/awaitPatterns/event.d.ts +0 -15
- package/dist/runtime/nitro/utils/awaitPatterns/event.js +0 -128
- package/dist/runtime/nitro/utils/awaitPatterns/index.d.ts +0 -28
- package/dist/runtime/nitro/utils/awaitPatterns/index.js +0 -55
- package/dist/runtime/nitro/utils/awaitPatterns/schedule.d.ts +0 -16
- package/dist/runtime/nitro/utils/awaitPatterns/schedule.js +0 -83
- package/dist/runtime/nitro/utils/awaitPatterns/time.d.ts +0 -15
- package/dist/runtime/nitro/utils/awaitPatterns/time.js +0 -71
- package/dist/runtime/nitro/utils/awaitPatterns/webhook.d.ts +0 -15
- package/dist/runtime/nitro/utils/awaitPatterns/webhook.js +0 -128
- package/dist/runtime/nitro/utils/defineFunctionConfig.d.ts +0 -378
- package/dist/runtime/nitro/utils/defineFunctionConfig.js +0 -3
- package/dist/runtime/nitro/utils/defineHooks.d.ts +0 -95
- package/dist/runtime/nitro/utils/defineHooks.js +0 -9
- package/dist/runtime/nitro/utils/registerAdapter.d.ts +0 -59
- package/dist/runtime/nitro/utils/registerAdapter.js +0 -13
- package/dist/runtime/nitro/utils/useAwait.d.ts +0 -83
- package/dist/runtime/nitro/utils/useAwait.js +0 -169
- package/dist/runtime/nitro/utils/useEventManager.d.ts +0 -15
- package/dist/runtime/nitro/utils/useEventManager.js +0 -26
- package/dist/runtime/nitro/utils/useFlow.d.ts +0 -66
- package/dist/runtime/nitro/utils/useFlow.js +0 -310
- package/dist/runtime/nitro/utils/useHookRegistry.d.ts +0 -40
- package/dist/runtime/nitro/utils/useHookRegistry.js +0 -25
- package/dist/runtime/nitro/utils/useNventLogger.d.ts +0 -42
- package/dist/runtime/nitro/utils/useNventLogger.js +0 -54
- package/dist/runtime/nitro/utils/useRunContext.d.ts +0 -6
- package/dist/runtime/nitro/utils/useRunContext.js +0 -102
- package/dist/runtime/nitro/utils/useStreamTopics.d.ts +0 -83
- package/dist/runtime/nitro/utils/useStreamTopics.js +0 -94
- package/dist/runtime/nitro/utils/useTrigger.d.ts +0 -150
- package/dist/runtime/nitro/utils/useTrigger.js +0 -311
- package/dist/runtime/nitro/utils/wsPeerManager.d.ts +0 -44
- package/dist/runtime/nitro/utils/wsPeerManager.js +0 -32
- package/dist/runtime/scheduler/index.d.ts +0 -33
- package/dist/runtime/scheduler/index.js +0 -42
- package/dist/runtime/scheduler/scheduler.d.ts +0 -132
- package/dist/runtime/scheduler/scheduler.js +0 -799
- package/dist/runtime/scheduler/types.d.ts +0 -122
- package/dist/runtime/scheduler/types.js +0 -0
- package/dist/runtime/worker/node/runner.d.ts +0 -95
- package/dist/runtime/worker/node/runner.js +0 -272
- package/dist/runtime/worker/python/get_config.py +0 -64
- package/dist/runtime/worker/system/awaitHandlers.d.ts +0 -27
- package/dist/runtime/worker/system/awaitHandlers.js +0 -230
- package/dist/runtime/worker/system/index.d.ts +0 -24
- package/dist/runtime/worker/system/index.js +0 -39
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
# nvent Python worker runtime
|
|
2
|
+
#
|
|
3
|
+
# This file is copied to .nuxt/iii-workers/_runtime.py at dev startup.
|
|
4
|
+
# Generated worker entry scripts (e.g. __shared__.py, <fn-id>.py) import from it
|
|
5
|
+
# so all shared logic lives here as real, editable Python — not embedded strings.
|
|
6
|
+
#
|
|
7
|
+
# Use in your step files:
|
|
8
|
+
# from nvent import http, queue, cron, FlowContext, ApiRequest, ApiResponse
|
|
9
|
+
#
|
|
10
|
+
# Responsibilities:
|
|
11
|
+
# http/queue/cron — trigger config helpers (same API as motia)
|
|
12
|
+
# FlowContext — ctx object passed to handlers (ctx.logger, ctx.state, ctx.enqueue, ctx.match)
|
|
13
|
+
# _load(path, name) — load a .py module from an absolute path
|
|
14
|
+
# _register(client, mod, default_id) — register a module's handler + triggers
|
|
15
|
+
# _iii_sdk — the iii Python SDK (re-exported for entry scripts)
|
|
16
|
+
|
|
17
|
+
import sys
|
|
18
|
+
import re
|
|
19
|
+
import inspect
|
|
20
|
+
import importlib.util
|
|
21
|
+
import logging as _logging
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
import iii as _iii_sdk
|
|
25
|
+
except ImportError:
|
|
26
|
+
print("[nvent] iii package not found — install it: pip install iii-sdk[otel]", flush=True)
|
|
27
|
+
sys.exit(1)
|
|
28
|
+
|
|
29
|
+
# Direct Python logging to stdout so nvent captures it alongside other output.
|
|
30
|
+
# DEBUG and above are collected; the JS side filters by logLevel.
|
|
31
|
+
_logging.basicConfig(
|
|
32
|
+
level=_logging.DEBUG,
|
|
33
|
+
stream=sys.stdout,
|
|
34
|
+
format="[%(levelname)s] %(name)s: %(message)s",
|
|
35
|
+
force=True,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
# OpenTelemetry tracing helpers — gracefully disabled when otel is not available
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
from opentelemetry import trace as _otel_trace
|
|
44
|
+
from opentelemetry.trace import SpanKind as _SpanKind, StatusCode as _StatusCode
|
|
45
|
+
_HAS_OTEL = True
|
|
46
|
+
except ImportError:
|
|
47
|
+
_HAS_OTEL = False
|
|
48
|
+
|
|
49
|
+
import contextlib
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _get_tracer():
|
|
53
|
+
"""Return the nvent OTel tracer, or None when OTel is not available."""
|
|
54
|
+
if not _HAS_OTEL:
|
|
55
|
+
return None
|
|
56
|
+
return _otel_trace.get_tracer("nvent")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@contextlib.contextmanager
|
|
60
|
+
def operation_span(operation: str, **attributes):
|
|
61
|
+
"""Context manager that creates an OTel child span for an operation.
|
|
62
|
+
|
|
63
|
+
When OTel is not installed (``opentelemetry-api`` not on sys.path),
|
|
64
|
+
this is a no-op — ``span`` is ``None`` inside the block.
|
|
65
|
+
|
|
66
|
+
Usage::
|
|
67
|
+
|
|
68
|
+
with operation_span("state::get", **{"nvent.state.scope": scope, "nvent.state.key": key}) as span:
|
|
69
|
+
try:
|
|
70
|
+
result = await client._async_trigger(...)
|
|
71
|
+
set_span_ok(span)
|
|
72
|
+
return result
|
|
73
|
+
except Exception as exc:
|
|
74
|
+
record_exception(span, exc)
|
|
75
|
+
raise
|
|
76
|
+
"""
|
|
77
|
+
tracer = _get_tracer()
|
|
78
|
+
if not tracer:
|
|
79
|
+
yield None
|
|
80
|
+
return
|
|
81
|
+
with tracer.start_as_current_span(
|
|
82
|
+
operation,
|
|
83
|
+
kind=_SpanKind.CLIENT,
|
|
84
|
+
attributes={k: v for k, v in attributes.items() if v is not None},
|
|
85
|
+
) as span:
|
|
86
|
+
yield span
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def record_exception(span, exc: Exception) -> None:
|
|
90
|
+
"""Record an exception on a span and mark it as errored."""
|
|
91
|
+
if _HAS_OTEL and span is not None:
|
|
92
|
+
span.set_status(_StatusCode.ERROR, str(exc))
|
|
93
|
+
span.record_exception(exc)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def set_span_ok(span) -> None:
|
|
97
|
+
"""Mark a span as successfully completed."""
|
|
98
|
+
if _HAS_OTEL and span is not None:
|
|
99
|
+
span.set_status(_StatusCode.OK)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Internal key used to propagate the stream channel through queue messages.
|
|
103
|
+
_NVENT_STREAM_KEY = '__nventStream'
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# ---------------------------------------------------------------------------
|
|
107
|
+
# Trigger config helpers — use these in config["triggers"]
|
|
108
|
+
# ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
def http(method: str, path: str) -> dict:
|
|
111
|
+
"""HTTP trigger: http("POST", "/my-endpoint")"""
|
|
112
|
+
return {"type": "http", "method": method.upper(), "path": path}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def queue(topic: str) -> dict:
|
|
116
|
+
"""Queue trigger: queue("order.created")"""
|
|
117
|
+
return {"type": "queue", "topic": topic}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def cron(expression: str) -> dict:
|
|
121
|
+
"""Cron trigger: cron("0 0 * * * * *") (7-field: sec min hour dom month dow year)"""
|
|
122
|
+
return {"type": "cron", "expression": expression}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class _Stream:
|
|
126
|
+
"""Access to the iii Stream module.
|
|
127
|
+
|
|
128
|
+
**Implicit API** (recommended): ``set(item_id, data)`` automatically uses
|
|
129
|
+
the function's flow/stream name and the current OTel trace ID as the group
|
|
130
|
+
ID. All steps that run in the same request share the same trace → same
|
|
131
|
+
group, so they write to a consistent WebSocket channel without manual
|
|
132
|
+
coordination.
|
|
133
|
+
|
|
134
|
+
**Explicit API**: ``set_in(name, group, item_id, data)`` targets any
|
|
135
|
+
specific stream and group.
|
|
136
|
+
|
|
137
|
+
Available as ``ctx.stream``.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
def __init__(self, client, stream_name: str, get_group_id):
|
|
141
|
+
self._client = client
|
|
142
|
+
self._stream_name = stream_name
|
|
143
|
+
self._get_group_id = get_group_id
|
|
144
|
+
|
|
145
|
+
# ------------------------------------------------------------------
|
|
146
|
+
# Implicit helpers — use flow stream + trace ID automatically
|
|
147
|
+
# ------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
async def set(self, item_id: str, data: dict) -> None:
|
|
150
|
+
"""Set (create/update) an item in the implicit stream channel."""
|
|
151
|
+
group = self._get_group_id()
|
|
152
|
+
with operation_span("stream::set", **{
|
|
153
|
+
"nvent.stream.name": self._stream_name,
|
|
154
|
+
"nvent.stream.group_id": group,
|
|
155
|
+
"nvent.stream.item_id": item_id,
|
|
156
|
+
}) as span:
|
|
157
|
+
try:
|
|
158
|
+
await self._client._async_trigger({"function_id": "stream::set", "payload": {
|
|
159
|
+
"stream_name": self._stream_name,
|
|
160
|
+
"group_id": group,
|
|
161
|
+
"item_id": item_id,
|
|
162
|
+
"data": data,
|
|
163
|
+
}})
|
|
164
|
+
set_span_ok(span)
|
|
165
|
+
except Exception as exc:
|
|
166
|
+
record_exception(span, exc)
|
|
167
|
+
raise
|
|
168
|
+
|
|
169
|
+
async def send(self, data: dict) -> None:
|
|
170
|
+
"""Send a custom event to all subscribers of the implicit stream channel."""
|
|
171
|
+
group = self._get_group_id()
|
|
172
|
+
with operation_span("stream::send", **{
|
|
173
|
+
"nvent.stream.name": self._stream_name,
|
|
174
|
+
"nvent.stream.group_id": group,
|
|
175
|
+
}) as span:
|
|
176
|
+
try:
|
|
177
|
+
await self._client._async_trigger({"function_id": "stream::send", "payload": {
|
|
178
|
+
"stream_name": self._stream_name,
|
|
179
|
+
"group_id": group,
|
|
180
|
+
"data": data,
|
|
181
|
+
}})
|
|
182
|
+
set_span_ok(span)
|
|
183
|
+
except Exception as exc:
|
|
184
|
+
record_exception(span, exc)
|
|
185
|
+
raise
|
|
186
|
+
|
|
187
|
+
def subscription(self) -> dict:
|
|
188
|
+
"""Return ``{"streamName": ..., "groupId": ...}`` for the implicit channel.
|
|
189
|
+
|
|
190
|
+
Return this dict from an HTTP handler so the client knows where to subscribe::
|
|
191
|
+
|
|
192
|
+
return ApiResponse(statusCode=200, body=ctx.stream.subscription())
|
|
193
|
+
"""
|
|
194
|
+
return {"streamName": self._stream_name, "groupId": self._get_group_id()}
|
|
195
|
+
|
|
196
|
+
# ------------------------------------------------------------------
|
|
197
|
+
# Explicit helpers — target any stream + group
|
|
198
|
+
# ------------------------------------------------------------------
|
|
199
|
+
|
|
200
|
+
async def set_in(self, name: str, group: str, item_id: str, data: dict) -> None:
|
|
201
|
+
"""Set (create/update) an item in an explicit stream group."""
|
|
202
|
+
with operation_span("stream::set", **{
|
|
203
|
+
"nvent.stream.name": name,
|
|
204
|
+
"nvent.stream.group_id": group,
|
|
205
|
+
"nvent.stream.item_id": item_id,
|
|
206
|
+
}) as span:
|
|
207
|
+
try:
|
|
208
|
+
await self._client._async_trigger({"function_id": "stream::set", "payload": {
|
|
209
|
+
"stream_name": name, "group_id": group, "item_id": item_id, "data": data,
|
|
210
|
+
}})
|
|
211
|
+
set_span_ok(span)
|
|
212
|
+
except Exception as exc:
|
|
213
|
+
record_exception(span, exc)
|
|
214
|
+
raise
|
|
215
|
+
|
|
216
|
+
async def get_item(self, name: str, group: str, item_id: str) -> dict:
|
|
217
|
+
"""Get a single item from a stream group."""
|
|
218
|
+
with operation_span("stream::get", **{
|
|
219
|
+
"nvent.stream.name": name,
|
|
220
|
+
"nvent.stream.group_id": group,
|
|
221
|
+
"nvent.stream.item_id": item_id,
|
|
222
|
+
}) as span:
|
|
223
|
+
try:
|
|
224
|
+
result = await self._client._async_trigger({"function_id": "stream::get", "payload": {
|
|
225
|
+
"stream_name": name, "group_id": group, "item_id": item_id,
|
|
226
|
+
}})
|
|
227
|
+
set_span_ok(span)
|
|
228
|
+
return result
|
|
229
|
+
except Exception as exc:
|
|
230
|
+
record_exception(span, exc)
|
|
231
|
+
raise
|
|
232
|
+
|
|
233
|
+
async def delete_item(self, name: str, group: str, item_id: str) -> None:
|
|
234
|
+
"""Delete an item from a stream group."""
|
|
235
|
+
with operation_span("stream::delete", **{
|
|
236
|
+
"nvent.stream.name": name,
|
|
237
|
+
"nvent.stream.group_id": group,
|
|
238
|
+
"nvent.stream.item_id": item_id,
|
|
239
|
+
}) as span:
|
|
240
|
+
try:
|
|
241
|
+
await self._client._async_trigger({"function_id": "stream::delete", "payload": {
|
|
242
|
+
"stream_name": name, "group_id": group, "item_id": item_id,
|
|
243
|
+
}})
|
|
244
|
+
set_span_ok(span)
|
|
245
|
+
except Exception as exc:
|
|
246
|
+
record_exception(span, exc)
|
|
247
|
+
raise
|
|
248
|
+
|
|
249
|
+
async def list_items(self, name: str, group: str) -> list:
|
|
250
|
+
"""List all items in a stream group."""
|
|
251
|
+
with operation_span("stream::list", **{
|
|
252
|
+
"nvent.stream.name": name,
|
|
253
|
+
"nvent.stream.group_id": group,
|
|
254
|
+
}) as span:
|
|
255
|
+
try:
|
|
256
|
+
result = await self._client._async_trigger({"function_id": "stream::list", "payload": {"stream_name": name, "group_id": group}})
|
|
257
|
+
set_span_ok(span)
|
|
258
|
+
return result
|
|
259
|
+
except Exception as exc:
|
|
260
|
+
record_exception(span, exc)
|
|
261
|
+
raise
|
|
262
|
+
|
|
263
|
+
async def send_to(self, name: str, group: str, data: dict) -> None:
|
|
264
|
+
"""Send a custom event to all subscribers of an explicit stream group."""
|
|
265
|
+
with operation_span("stream::send", **{
|
|
266
|
+
"nvent.stream.name": name,
|
|
267
|
+
"nvent.stream.group_id": group,
|
|
268
|
+
}) as span:
|
|
269
|
+
try:
|
|
270
|
+
await self._client._async_trigger({"function_id": "stream::send", "payload": {
|
|
271
|
+
"stream_name": name, "group_id": group, "data": data,
|
|
272
|
+
}})
|
|
273
|
+
set_span_ok(span)
|
|
274
|
+
except Exception as exc:
|
|
275
|
+
record_exception(span, exc)
|
|
276
|
+
raise
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
# ---------------------------------------------------------------------------
|
|
280
|
+
# State manager sub-object — accessible as ctx.state
|
|
281
|
+
# ---------------------------------------------------------------------------
|
|
282
|
+
|
|
283
|
+
class _State:
|
|
284
|
+
"""Provides ctx.state.get/set/delete/list — scope is auto-bound to the function ID."""
|
|
285
|
+
|
|
286
|
+
def __init__(self, client, fn_id: str):
|
|
287
|
+
self._client = client
|
|
288
|
+
self._fn_id = fn_id
|
|
289
|
+
|
|
290
|
+
async def get(self, key: str):
|
|
291
|
+
with operation_span("state::get", **{"nvent.state.scope": self._fn_id, "nvent.state.key": key}) as span:
|
|
292
|
+
try:
|
|
293
|
+
result = await self._client._async_trigger({"function_id": "state::get", "payload": {"scope": self._fn_id, "key": key}})
|
|
294
|
+
set_span_ok(span)
|
|
295
|
+
return result
|
|
296
|
+
except Exception as exc:
|
|
297
|
+
record_exception(span, exc)
|
|
298
|
+
raise
|
|
299
|
+
|
|
300
|
+
async def set(self, key: str, value) -> None:
|
|
301
|
+
with operation_span("state::set", **{"nvent.state.scope": self._fn_id, "nvent.state.key": key}) as span:
|
|
302
|
+
try:
|
|
303
|
+
result = await self._client._async_trigger({"function_id": "state::set", "payload": {"scope": self._fn_id, "key": key, "value": value}})
|
|
304
|
+
set_span_ok(span)
|
|
305
|
+
return result
|
|
306
|
+
except Exception as exc:
|
|
307
|
+
record_exception(span, exc)
|
|
308
|
+
raise
|
|
309
|
+
|
|
310
|
+
async def delete(self, key: str) -> None:
|
|
311
|
+
with operation_span("state::delete", **{"nvent.state.scope": self._fn_id, "nvent.state.key": key}) as span:
|
|
312
|
+
try:
|
|
313
|
+
await self._client._async_trigger({"function_id": "state::delete", "payload": {"scope": self._fn_id, "key": key}})
|
|
314
|
+
set_span_ok(span)
|
|
315
|
+
except Exception as exc:
|
|
316
|
+
record_exception(span, exc)
|
|
317
|
+
raise
|
|
318
|
+
|
|
319
|
+
async def list(self):
|
|
320
|
+
with operation_span("state::list", **{"nvent.state.scope": self._fn_id}) as span:
|
|
321
|
+
try:
|
|
322
|
+
result = await self._client._async_trigger({"function_id": "state::list", "payload": {"scope": self._fn_id}})
|
|
323
|
+
set_span_ok(span)
|
|
324
|
+
return result
|
|
325
|
+
except Exception as exc:
|
|
326
|
+
record_exception(span, exc)
|
|
327
|
+
raise
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
# ---------------------------------------------------------------------------
|
|
331
|
+
# FlowContext — execution context passed to handler(input, ctx)
|
|
332
|
+
# ---------------------------------------------------------------------------
|
|
333
|
+
|
|
334
|
+
class FlowContext:
|
|
335
|
+
"""Execution context passed as the second argument to Python step handlers.
|
|
336
|
+
|
|
337
|
+
ctx.logger — structured logger (OTel-backed when available, else stdout)
|
|
338
|
+
ctx.state — key-value store (ctx.state.get / .set / .delete / .list)
|
|
339
|
+
ctx.stream — stream channel (ctx.stream.set / .send / .subscription)
|
|
340
|
+
ctx.trace_id — current OTel trace ID (shared across all steps in the same request)
|
|
341
|
+
ctx.stream_name — stream name used by implicit ctx.stream ops
|
|
342
|
+
ctx.enqueue() — emit a message to a topic
|
|
343
|
+
ctx.match() — route to a trigger-type-specific sub-handler
|
|
344
|
+
|
|
345
|
+
Implicit stream usage (recommended)::
|
|
346
|
+
|
|
347
|
+
# All steps in the same trace write to the same channel automatically:
|
|
348
|
+
await ctx.stream.set("step-1", {"label": "Tokenizing", "step": 1})
|
|
349
|
+
|
|
350
|
+
# HTTP handler: return subscription info for the client
|
|
351
|
+
return ApiResponse(statusCode=200, body=ctx.stream.subscription())
|
|
352
|
+
|
|
353
|
+
Explicit stream (cross-flow or specific group)::
|
|
354
|
+
|
|
355
|
+
await ctx.stream.set_in("other-flow", "group-123", "item", data)
|
|
356
|
+
"""
|
|
357
|
+
|
|
358
|
+
def __init__(self, client, fn_id: str, trigger_type: str, input_data, stream_name: str = "", inherited_group_id: str = None):
|
|
359
|
+
self._client = client
|
|
360
|
+
self._fn_id = fn_id
|
|
361
|
+
self._trigger_type = trigger_type
|
|
362
|
+
self._input = input_data
|
|
363
|
+
self._stream_name = stream_name or fn_id.split("::")[0]
|
|
364
|
+
self._stream_group_id = inherited_group_id
|
|
365
|
+
self.logger = _iii_sdk.Logger(fn_id)
|
|
366
|
+
self.state = _State(client, fn_id)
|
|
367
|
+
self.stream = _Stream(client, self._stream_name, self._get_or_create_group_id)
|
|
368
|
+
|
|
369
|
+
def _get_or_create_group_id(self) -> str:
|
|
370
|
+
"""Return stable group ID for this invocation, generating one lazily if needed."""
|
|
371
|
+
if not self._stream_group_id:
|
|
372
|
+
import uuid
|
|
373
|
+
self._stream_group_id = str(uuid.uuid4())
|
|
374
|
+
return self._stream_group_id
|
|
375
|
+
|
|
376
|
+
@property
|
|
377
|
+
def stream_name(self) -> str:
|
|
378
|
+
"""The stream name used by implicit ``ctx.stream.set()`` / ``ctx.stream.send()``."""
|
|
379
|
+
return self._stream_name
|
|
380
|
+
|
|
381
|
+
async def enqueue(self, payload: dict) -> None:
|
|
382
|
+
"""Emit a message to a queue topic.
|
|
383
|
+
If a stream channel is active, its context is propagated automatically.
|
|
384
|
+
Usage: await ctx.enqueue({"topic": "order.created", "data": {"id": "x"}})
|
|
385
|
+
"""
|
|
386
|
+
topic = payload.get("topic")
|
|
387
|
+
data = dict(payload.get("data") or {})
|
|
388
|
+
if self._stream_group_id:
|
|
389
|
+
data[_NVENT_STREAM_KEY] = {"name": self._stream_name, "groupId": self._stream_group_id}
|
|
390
|
+
await self._client._async_trigger({
|
|
391
|
+
"function_id": "enqueue",
|
|
392
|
+
"payload": {"topic": topic, "data": data},
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
async def enqueue_named(self, payload: dict) -> dict:
|
|
396
|
+
"""Dispatch directly to a function via a named queue.
|
|
397
|
+
|
|
398
|
+
Unlike ``enqueue()``, which publishes to a topic, this targets a
|
|
399
|
+
specific function and routes the call through the named queue for
|
|
400
|
+
FIFO ordering, concurrency control, or custom retry behaviour.
|
|
401
|
+
Requires the queue to be declared in nvent's ``queue_configs``.
|
|
402
|
+
|
|
403
|
+
Returns ``{"messageReceiptId": "..."}`` immediately — the function
|
|
404
|
+
runs asynchronously.
|
|
405
|
+
|
|
406
|
+
Usage::
|
|
407
|
+
|
|
408
|
+
result = await ctx.enqueue_named({
|
|
409
|
+
"queue": "orders",
|
|
410
|
+
"function_id": "orders::process",
|
|
411
|
+
"data": {"orderId": "123"},
|
|
412
|
+
})
|
|
413
|
+
"""
|
|
414
|
+
queue = payload["queue"]
|
|
415
|
+
function_id = payload["function_id"]
|
|
416
|
+
data = payload.get("data")
|
|
417
|
+
return await self._client._async_trigger({
|
|
418
|
+
"function_id": function_id,
|
|
419
|
+
"payload": data,
|
|
420
|
+
"action": {"type": "enqueue", "queue": queue},
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
async def match(self, handlers: dict):
|
|
424
|
+
"""Route to a sub-handler based on the trigger type that activated this step.
|
|
425
|
+
|
|
426
|
+
Each value in the dict is an async callable:
|
|
427
|
+
"http" → receives ApiRequest
|
|
428
|
+
"queue" → receives the queue data dict
|
|
429
|
+
"cron" → receives no arguments
|
|
430
|
+
"default" → fallback for unmatched trigger types
|
|
431
|
+
"""
|
|
432
|
+
handler = handlers.get(self._trigger_type) or handlers.get("default")
|
|
433
|
+
if handler is None:
|
|
434
|
+
raise ValueError(
|
|
435
|
+
f"[nvent] ctx.match(): no handler for trigger type '{self._trigger_type}'. "
|
|
436
|
+
f"Available: {list(handlers)}"
|
|
437
|
+
)
|
|
438
|
+
sig = inspect.signature(handler)
|
|
439
|
+
# Count required positional params (ignores *args, **kwargs, params with defaults)
|
|
440
|
+
required = sum(
|
|
441
|
+
1 for p in sig.parameters.values()
|
|
442
|
+
if p.default is inspect.Parameter.empty
|
|
443
|
+
and p.kind not in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)
|
|
444
|
+
)
|
|
445
|
+
if required == 0:
|
|
446
|
+
return await handler()
|
|
447
|
+
return await handler(self._input)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
# ---------------------------------------------------------------------------
|
|
451
|
+
# Module loader
|
|
452
|
+
# ---------------------------------------------------------------------------
|
|
453
|
+
|
|
454
|
+
def _load(path: str, name: str):
|
|
455
|
+
"""Load a Python module from an absolute file path."""
|
|
456
|
+
spec = importlib.util.spec_from_file_location(name, path)
|
|
457
|
+
mod = importlib.util.module_from_spec(spec)
|
|
458
|
+
spec.loader.exec_module(mod)
|
|
459
|
+
return mod
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
# ---------------------------------------------------------------------------
|
|
463
|
+
# Registration — reads config dict (motia-style) or meta+triggers (legacy)
|
|
464
|
+
# ---------------------------------------------------------------------------
|
|
465
|
+
|
|
466
|
+
def _normalize_trigger_meta(t: dict) -> dict:
|
|
467
|
+
"""Return a flat {type, path/topic/expression} dict for console metadata."""
|
|
468
|
+
t_type = t.get("type", "")
|
|
469
|
+
if t_type == "http":
|
|
470
|
+
path = t.get("path") or (t.get("config") or {}).get("api_path")
|
|
471
|
+
method = t.get("method") or (t.get("config") or {}).get("http_method")
|
|
472
|
+
return {"type": "http", "path": path, "method": method}
|
|
473
|
+
if t_type == "queue":
|
|
474
|
+
topic = t.get("topic") or (t.get("config") or {}).get("topic")
|
|
475
|
+
return {"type": "queue", "topic": topic}
|
|
476
|
+
if t_type == "cron":
|
|
477
|
+
expr = t.get("expression") or (t.get("config") or {}).get("expression")
|
|
478
|
+
return {"type": "cron", "expression": expr}
|
|
479
|
+
cfg = dict(t.get("config") or {})
|
|
480
|
+
return {"type": t_type, **cfg}
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def _trigger_to_iii_cfg(t: dict) -> dict:
|
|
484
|
+
"""Convert a trigger dict to the engine-facing config (api_path/http_method for HTTP)."""
|
|
485
|
+
t_type = t.get("type", "")
|
|
486
|
+
if t_type == "http":
|
|
487
|
+
path = t.get("path") or (t.get("config") or {}).get("api_path") or ""
|
|
488
|
+
method = t.get("method") or (t.get("config") or {}).get("http_method") or "GET"
|
|
489
|
+
return {"api_path": path, "http_method": method}
|
|
490
|
+
if t_type == "queue":
|
|
491
|
+
topic = t.get("topic") or (t.get("config") or {}).get("topic") or ""
|
|
492
|
+
return {"topic": topic}
|
|
493
|
+
if t_type == "cron":
|
|
494
|
+
expr = t.get("expression") or (t.get("config") or {}).get("expression") or ""
|
|
495
|
+
return {"expression": expr}
|
|
496
|
+
return dict(t.get("config") or {k: v for k, v in t.items() if k != "type"})
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def _trigger_suffix(trigger: dict) -> str:
|
|
500
|
+
"""Build a descriptive trigger suffix (no whitespace for valid function_id)."""
|
|
501
|
+
t_type = trigger.get("type", "")
|
|
502
|
+
if t_type == "http":
|
|
503
|
+
method = trigger.get("method") or (trigger.get("config") or {}).get("http_method", "GET")
|
|
504
|
+
path = trigger.get("path") or (trigger.get("config") or {}).get("api_path", "/")
|
|
505
|
+
return f"http({method}_{path})"
|
|
506
|
+
if t_type == "queue":
|
|
507
|
+
topic = trigger.get("topic") or (trigger.get("config") or {}).get("topic", "")
|
|
508
|
+
return f"queue({topic})"
|
|
509
|
+
if t_type == "cron":
|
|
510
|
+
expr = trigger.get("expression") or (trigger.get("config") or {}).get("expression", "")
|
|
511
|
+
return f"cron({expr})"
|
|
512
|
+
return t_type
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def _register(client, mod, default_id: str) -> None:
|
|
516
|
+
"""Register a loaded module's handler and triggers with the iii client.
|
|
517
|
+
|
|
518
|
+
Supports two step file formats:
|
|
519
|
+
|
|
520
|
+
**New motia-compatible format** (preferred):
|
|
521
|
+
config = {
|
|
522
|
+
"name": "my-step",
|
|
523
|
+
"description": "...",
|
|
524
|
+
"triggers": [http("POST", "/path"), queue("topic"), cron("0 * * * * * *")],
|
|
525
|
+
"enqueues": ["topic.done"],
|
|
526
|
+
"flows": ["my-flow"],
|
|
527
|
+
}
|
|
528
|
+
async def handler(input, ctx: FlowContext): ...
|
|
529
|
+
|
|
530
|
+
**Legacy nvent format** (still supported):
|
|
531
|
+
meta = {"id": "my-step", "description": "...", "flows": [...]}
|
|
532
|
+
triggers = [{"type": "http", "config": {"api_path": "path", "http_method": "POST"}}]
|
|
533
|
+
async def handler(input, ctx): ...
|
|
534
|
+
|
|
535
|
+
One function per trigger is registered (mirrors JS worker pattern).
|
|
536
|
+
"""
|
|
537
|
+
config_dict = getattr(mod, "config", None)
|
|
538
|
+
|
|
539
|
+
if config_dict is not None:
|
|
540
|
+
# New motia-compatible format: config = { name, description, triggers, flows, enqueues, stream }
|
|
541
|
+
fn_id = config_dict.get("name") or default_id
|
|
542
|
+
if not config_dict.get("name"):
|
|
543
|
+
print(f"[nvent] WARNING: Python step at {getattr(mod, '__file__', '?')} has no 'name' in config — "
|
|
544
|
+
f"falling back to file-path-derived name {fn_id!r}. "
|
|
545
|
+
"Add `config['name'] = '<your-step-name>'` to fix this.", flush=True)
|
|
546
|
+
description = config_dict.get("description")
|
|
547
|
+
triggers = list(config_dict.get("triggers") or [])
|
|
548
|
+
flows = list(config_dict.get("flows") or [])
|
|
549
|
+
enqueues = list(config_dict.get("enqueues") or [])
|
|
550
|
+
stream_name = config_dict.get("stream") or (flows[0] if flows else fn_id.split("::")[0])
|
|
551
|
+
else:
|
|
552
|
+
# Legacy format: meta = {...}, triggers = [...]
|
|
553
|
+
meta = dict(getattr(mod, "meta", {}) or {})
|
|
554
|
+
fn_id = meta.get("name") or default_id
|
|
555
|
+
if not meta.get("name"):
|
|
556
|
+
print(f"[nvent] WARNING: Python step at {getattr(mod, '__file__', '?')} has no 'name' in meta — "
|
|
557
|
+
f"falling back to file-path-derived name {fn_id!r}. "
|
|
558
|
+
"Add `meta['name'] = '<your-step-name>'` to fix this.", flush=True)
|
|
559
|
+
description = meta.get("description")
|
|
560
|
+
triggers = list(getattr(mod, "triggers", []) or [])
|
|
561
|
+
flows = list(meta.get("flows") or [])
|
|
562
|
+
enqueues = list(meta.get("enqueues") or [])
|
|
563
|
+
stream_name = meta.get("stream") or (flows[0] if flows else fn_id.split("::")[0])
|
|
564
|
+
|
|
565
|
+
handler_fn = getattr(mod, "handler", None)
|
|
566
|
+
file_path = getattr(mod, "__file__", None)
|
|
567
|
+
|
|
568
|
+
if not handler_fn:
|
|
569
|
+
print(f"[nvent] Python function {fn_id!r} has no handler — skipping", flush=True)
|
|
570
|
+
return
|
|
571
|
+
|
|
572
|
+
sig = inspect.signature(handler_fn)
|
|
573
|
+
has_ctx = len(list(sig.parameters)) >= 2
|
|
574
|
+
|
|
575
|
+
metadata = {
|
|
576
|
+
"name": fn_id,
|
|
577
|
+
"description": description,
|
|
578
|
+
"filePath": file_path,
|
|
579
|
+
"triggers": [_normalize_trigger_meta(t) for t in triggers],
|
|
580
|
+
"flows": flows,
|
|
581
|
+
"enqueues": enqueues,
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
seen_suffixes: set = set()
|
|
585
|
+
for i, trigger in enumerate(triggers):
|
|
586
|
+
t_type = trigger.get("type", "")
|
|
587
|
+
suffix = _trigger_suffix(trigger)
|
|
588
|
+
if suffix in seen_suffixes:
|
|
589
|
+
suffix = f"{suffix}::{i}"
|
|
590
|
+
seen_suffixes.add(suffix)
|
|
591
|
+
|
|
592
|
+
# Motia-style function_id: steps::<name>::trigger::<descriptive-suffix>
|
|
593
|
+
function_id = f"steps::{fn_id}::trigger::{suffix}"
|
|
594
|
+
iii_cfg = _trigger_to_iii_cfg(trigger)
|
|
595
|
+
is_http = t_type == "http"
|
|
596
|
+
|
|
597
|
+
# Create a per-trigger wrapper that captures trigger type for ctx.match()
|
|
598
|
+
def _make_wrapper(_h, _is_http, _t_type, _fn_id, _hc, _stream_name):
|
|
599
|
+
async def _wrapped(data):
|
|
600
|
+
# Extract and strip inherited stream context from queue messages
|
|
601
|
+
inherited_group = None
|
|
602
|
+
effective_stream = _stream_name
|
|
603
|
+
clean_data = data
|
|
604
|
+
if isinstance(data, dict) and _NVENT_STREAM_KEY in data:
|
|
605
|
+
nvent_stream = data[_NVENT_STREAM_KEY]
|
|
606
|
+
if isinstance(nvent_stream, dict):
|
|
607
|
+
inherited_group = nvent_stream.get('groupId')
|
|
608
|
+
effective_stream = nvent_stream.get('name') or _stream_name
|
|
609
|
+
clean_data = {k: v for k, v in data.items() if k != _NVENT_STREAM_KEY}
|
|
610
|
+
input_data = _iii_sdk.ApiRequest(**clean_data) if (_is_http and isinstance(clean_data, dict)) else clean_data
|
|
611
|
+
if not _hc:
|
|
612
|
+
return await _h(input_data)
|
|
613
|
+
ctx = FlowContext(client, _fn_id, _t_type, input_data, effective_stream, inherited_group)
|
|
614
|
+
return await _h(input_data, ctx)
|
|
615
|
+
return _wrapped
|
|
616
|
+
|
|
617
|
+
wrapped = _make_wrapper(handler_fn, is_http, t_type, fn_id, has_ctx, stream_name)
|
|
618
|
+
client.register_function(
|
|
619
|
+
{"id": function_id, "description": description, "metadata": metadata},
|
|
620
|
+
wrapped,
|
|
621
|
+
)
|
|
622
|
+
client.register_trigger({
|
|
623
|
+
"type": t_type,
|
|
624
|
+
"function_id": function_id,
|
|
625
|
+
"config": {**iii_cfg, "metadata": metadata},
|
|
626
|
+
})
|
|
627
|
+
|
|
628
|
+
print(f"[nvent] registered {fn_id!r} ({len(triggers)} trigger(s))", flush=True)
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
# ---------------------------------------------------------------------------
|
|
632
|
+
# CLI entry point — invoked by the TypeScript worker manager:
|
|
633
|
+
# python3 _runtime.py <ws_url> <worker_name> <path1> <id1> [<path2> <id2> ...]
|
|
634
|
+
# ---------------------------------------------------------------------------
|
|
635
|
+
|
|
636
|
+
if __name__ == "__main__":
|
|
637
|
+
if len(sys.argv) < 4 or (len(sys.argv) - 3) % 2 != 0:
|
|
638
|
+
print(
|
|
639
|
+
"Usage: _runtime.py <ws_url> <worker_name> <path1> <id1> [<path2> <id2> ...]",
|
|
640
|
+
file=sys.stderr,
|
|
641
|
+
)
|
|
642
|
+
sys.exit(1)
|
|
643
|
+
|
|
644
|
+
_ws_url = sys.argv[1]
|
|
645
|
+
_worker_name = sys.argv[2]
|
|
646
|
+
_fn_pairs = [(sys.argv[i], sys.argv[i + 1]) for i in range(3, len(sys.argv), 2)]
|
|
647
|
+
|
|
648
|
+
options = _iii_sdk.InitOptions(
|
|
649
|
+
worker_name=_worker_name,
|
|
650
|
+
otel={"enabled": True, "service_name": "nvent", "metrics_enabled": False},
|
|
651
|
+
telemetry=_iii_sdk.TelemetryOptions(framework="nvent", project_name=_worker_name),
|
|
652
|
+
)
|
|
653
|
+
client = _iii_sdk.register_worker(_ws_url, options)
|
|
654
|
+
for _path, _fn_id in _fn_pairs:
|
|
655
|
+
_mod = _load(_path, _fn_id)
|
|
656
|
+
_register(client, _mod, _fn_id)
|
|
657
|
+
# Keep process alive — the SDK's background thread is daemon=True so we must
|
|
658
|
+
# block the main thread until the process is externally killed.
|
|
659
|
+
client._thread.join()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
declare module '#nvent/iii-registry' {
|
|
2
|
+
interface NodeFnInfo {
|
|
3
|
+
name: string
|
|
4
|
+
description?: string
|
|
5
|
+
handler: (input: unknown, ctx: unknown) => Promise<unknown>
|
|
6
|
+
triggers: Array<{ type: string; function_id: string; config?: Record<string, unknown> }>
|
|
7
|
+
enqueues: string[]
|
|
8
|
+
flows: string[]
|
|
9
|
+
stream?: string
|
|
10
|
+
filePath?: string
|
|
11
|
+
}
|
|
12
|
+
export const registry: {
|
|
13
|
+
functions: NodeFnInfo[]
|
|
14
|
+
triggers: Array<{ type: string; function_id: string; config?: Record<string, unknown> }>
|
|
15
|
+
}
|
|
16
|
+
export const pythonFunctions: Array<{ id: string; absPath: string; standalone: boolean }>
|
|
17
|
+
}
|
package/dist/types.d.mts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import type { NuxtModule } from '@nuxt/schema'
|
|
2
|
+
|
|
3
|
+
import type { default as Module } from './module.mjs'
|
|
4
|
+
|
|
5
|
+
export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
|
|
2
6
|
|
|
3
7
|
export { default } from './module.mjs'
|