nvent 1.0.0-alpha.2 → 1.0.0-alpha.4
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 +158 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +210 -55
- package/dist/runtime/app/composables/useFunctionCall.d.ts +1 -1
- package/dist/runtime/app/composables/useIii.d.ts +24 -0
- package/dist/runtime/app/composables/useIii.js +9 -0
- package/dist/runtime/app/composables/useIiiStream.d.ts +22 -0
- package/dist/runtime/app/composables/{useNventStream.js → useIiiStream.js} +4 -9
- package/dist/runtime/app/plugins/iii.client.d.ts +13 -0
- package/dist/runtime/app/plugins/iii.client.js +9 -0
- package/dist/runtime/nitro/plugins/01.iii-worker.js +49 -0
- package/dist/runtime/nitro/routes/browser-proxy.d.ts +13 -0
- package/dist/runtime/nitro/routes/browser-proxy.js +55 -0
- package/dist/runtime/nitro/routes/stream-proxy.d.ts +1 -1
- package/dist/runtime/nitro/routes/stream-proxy.js +1 -1
- package/dist/runtime/nitro/server.d.ts +14 -0
- package/dist/runtime/nitro/server.js +3 -0
- package/dist/runtime/nitro/utils/browserAuthToken.d.ts +10 -0
- package/dist/runtime/nitro/utils/browserAuthToken.js +32 -0
- package/dist/runtime/nitro/utils/defineFunction.d.ts +63 -258
- package/dist/runtime/nitro/utils/defineFunction.js +12 -221
- package/dist/runtime/nitro/utils/engine.d.ts +11 -0
- package/dist/runtime/nitro/utils/engine.js +79 -17
- package/dist/runtime/nitro/utils/useIii.d.ts +10 -11
- package/dist/runtime/nitro/utils/useIii.js +2 -3
- package/dist/runtime/nitro/utils/workers/node.d.ts +17 -10
- package/dist/runtime/nitro/utils/workers/node.js +25 -51
- package/dist/runtime/nitro/utils/workers/python.js +13 -12
- package/dist/runtime/python/nvent.py +288 -160
- package/dist/runtime/python/worker_runtime.py +141 -44
- package/dist/runtime/virtual.d.ts +23 -5
- package/package.json +9 -8
- package/dist/runtime/app/composables/useNventStream.d.ts +0 -23
package/dist/module.d.mts
CHANGED
|
@@ -38,9 +38,13 @@ interface NventIiiOptions {
|
|
|
38
38
|
type: 'kv';
|
|
39
39
|
storeMethod?: 'file_based' | 'in_memory';
|
|
40
40
|
filePath?: string;
|
|
41
|
+
saveIntervalMs?: number;
|
|
41
42
|
} | {
|
|
42
43
|
type: 'redis';
|
|
43
44
|
redisUrl?: string;
|
|
45
|
+
} | {
|
|
46
|
+
type: 'bridge';
|
|
47
|
+
bridgeUrl: string;
|
|
44
48
|
};
|
|
45
49
|
};
|
|
46
50
|
/**
|
|
@@ -52,12 +56,26 @@ interface NventIiiOptions {
|
|
|
52
56
|
type: 'builtin';
|
|
53
57
|
storeMethod?: 'file_based' | 'in_memory';
|
|
54
58
|
filePath?: string;
|
|
59
|
+
saveIntervalMs?: number;
|
|
60
|
+
maxAttempts?: number;
|
|
61
|
+
backoffMs?: number;
|
|
62
|
+
concurrency?: number;
|
|
63
|
+
pollIntervalMs?: number;
|
|
64
|
+
/** Processing order. 'concurrent' (parallel) or 'fifo' (sequential). Default: 'concurrent' */
|
|
65
|
+
mode?: 'concurrent' | 'fifo';
|
|
55
66
|
} | {
|
|
56
67
|
type: 'redis';
|
|
57
68
|
redisUrl?: string;
|
|
58
69
|
} | {
|
|
59
70
|
type: 'rabbitmq';
|
|
60
71
|
amqpUrl?: string;
|
|
72
|
+
maxAttempts?: number;
|
|
73
|
+
prefetchCount?: number;
|
|
74
|
+
/** 'standard' or 'quorum' (HA replicated). Default: 'standard' */
|
|
75
|
+
queueMode?: 'standard' | 'quorum';
|
|
76
|
+
} | {
|
|
77
|
+
type: 'bridge';
|
|
78
|
+
bridgeUrl: string;
|
|
61
79
|
};
|
|
62
80
|
queueConfigs?: Record<string, {
|
|
63
81
|
type?: 'standard' | 'fifo';
|
|
@@ -72,6 +90,11 @@ interface NventIiiOptions {
|
|
|
72
90
|
cron?: {
|
|
73
91
|
adapter?: {
|
|
74
92
|
type: 'kv';
|
|
93
|
+
lockTtlMs?: number;
|
|
94
|
+
lockIndex?: string;
|
|
95
|
+
storeMethod?: 'file_based' | 'in_memory';
|
|
96
|
+
filePath?: string;
|
|
97
|
+
saveIntervalMs?: number;
|
|
75
98
|
} | {
|
|
76
99
|
type: 'redis';
|
|
77
100
|
redisUrl?: string;
|
|
@@ -85,9 +108,13 @@ interface NventIiiOptions {
|
|
|
85
108
|
type: 'kv';
|
|
86
109
|
storeMethod?: 'file_based' | 'in_memory';
|
|
87
110
|
filePath?: string;
|
|
111
|
+
saveIntervalMs?: number;
|
|
88
112
|
} | {
|
|
89
113
|
type: 'redis';
|
|
90
114
|
redisUrl?: string;
|
|
115
|
+
} | {
|
|
116
|
+
type: 'bridge';
|
|
117
|
+
bridgeUrl: string;
|
|
91
118
|
};
|
|
92
119
|
};
|
|
93
120
|
/** REST API module extra settings */
|
|
@@ -95,6 +122,13 @@ interface NventIiiOptions {
|
|
|
95
122
|
host?: string;
|
|
96
123
|
defaultTimeout?: number;
|
|
97
124
|
concurrencyRequestLimit?: number;
|
|
125
|
+
/** CORS configuration for browser clients */
|
|
126
|
+
cors?: {
|
|
127
|
+
/** Origins allowed to make requests. Use '*' for any, or list specific domains. */
|
|
128
|
+
allowedOrigins?: string[];
|
|
129
|
+
/** HTTP methods permitted for cross-origin requests. */
|
|
130
|
+
allowedMethods?: string[];
|
|
131
|
+
};
|
|
98
132
|
};
|
|
99
133
|
/** OtelModule (observability) configuration */
|
|
100
134
|
observability?: {
|
|
@@ -124,6 +158,36 @@ interface NventIiiOptions {
|
|
|
124
158
|
logsFlushIntervalMs?: number;
|
|
125
159
|
logsSamplingRatio?: number;
|
|
126
160
|
logsConsoleOutput?: boolean;
|
|
161
|
+
/** Advanced sampling rules — override samplingRatio for matched operations. */
|
|
162
|
+
sampling?: {
|
|
163
|
+
default?: number;
|
|
164
|
+
parentBased?: boolean;
|
|
165
|
+
rules?: Array<{
|
|
166
|
+
operation?: string;
|
|
167
|
+
service?: string;
|
|
168
|
+
rate: number;
|
|
169
|
+
}>;
|
|
170
|
+
rateLimit?: {
|
|
171
|
+
maxTracesPerSecond?: number;
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
/** Alert rules — trigger a webhook or function when a metric crosses a threshold. */
|
|
175
|
+
alerts?: Array<{
|
|
176
|
+
name: string;
|
|
177
|
+
metric: string;
|
|
178
|
+
threshold: number;
|
|
179
|
+
operator: '>' | '>=' | '<' | '<=' | '==' | '!=';
|
|
180
|
+
windowSeconds: number;
|
|
181
|
+
enabled?: boolean;
|
|
182
|
+
cooldownSeconds?: number;
|
|
183
|
+
action: {
|
|
184
|
+
type: 'webhook';
|
|
185
|
+
url: string;
|
|
186
|
+
} | {
|
|
187
|
+
type: 'function';
|
|
188
|
+
path: string;
|
|
189
|
+
};
|
|
190
|
+
}>;
|
|
127
191
|
level?: 'trace' | 'debug' | 'info' | 'warn' | 'error';
|
|
128
192
|
format?: 'default' | 'json';
|
|
129
193
|
};
|
|
@@ -147,10 +211,104 @@ interface NventIiiOptions {
|
|
|
147
211
|
/** Enable the Flow visualization page */
|
|
148
212
|
flow?: boolean;
|
|
149
213
|
};
|
|
214
|
+
/** PubSub worker — topic-based event fanout across functions. */
|
|
215
|
+
pubsub?: {
|
|
216
|
+
adapter?: {
|
|
217
|
+
type: 'local';
|
|
218
|
+
} | {
|
|
219
|
+
type: 'redis';
|
|
220
|
+
redisUrl?: string;
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* HTTP Functions worker — enables outbound HTTP calls from the engine.
|
|
225
|
+
* Required for functions registered with HttpInvocationConfig.
|
|
226
|
+
*/
|
|
227
|
+
httpFunctions?: {
|
|
228
|
+
security?: {
|
|
229
|
+
/** URL patterns allowed for outbound requests. Use '*' to allow all. */
|
|
230
|
+
urlAllowlist?: string[];
|
|
231
|
+
/** Block requests to private/internal IP ranges (SSRF prevention). Default: true */
|
|
232
|
+
blockPrivateIps?: boolean;
|
|
233
|
+
/** Require HTTPS for all outbound requests. Default: true */
|
|
234
|
+
requireHttps?: boolean;
|
|
235
|
+
};
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Additional iii-worker-manager instance with RBAC.
|
|
239
|
+
* nvent uses this automatically when browser SDK is enabled.
|
|
240
|
+
* Can also be configured manually for custom auth scenarios.
|
|
241
|
+
*/
|
|
242
|
+
workerManager?: {
|
|
243
|
+
rbac?: {
|
|
244
|
+
/** Port for the RBAC worker manager. Default: 49135 */
|
|
245
|
+
port?: number;
|
|
246
|
+
/** Function ID called on every WebSocket upgrade for auth. */
|
|
247
|
+
authFunctionId?: string;
|
|
248
|
+
/** Functions the connecting worker is allowed to invoke (patterns supported). */
|
|
249
|
+
exposeFunctions?: string[];
|
|
250
|
+
/** Function invoked before each handler — enrich or audit requests. */
|
|
251
|
+
middlewareFunctionId?: string;
|
|
252
|
+
/** Allow workers to register their own function handlers. Default: true */
|
|
253
|
+
allowFunctionRegistration?: boolean;
|
|
254
|
+
/** Allow workers to register new trigger types. Default: false */
|
|
255
|
+
allowTriggerTypeRegistration?: boolean;
|
|
256
|
+
/** Prefix prepended to every function the worker registers. */
|
|
257
|
+
functionRegistrationPrefix?: string;
|
|
258
|
+
/** TTL for signed browser auth tokens generated by the Nuxt proxy. Default: 120 */
|
|
259
|
+
tokenTtlSeconds?: number;
|
|
260
|
+
/** Allow browser connections without a custom resolver returning user context. Default: true */
|
|
261
|
+
allowAnonymous?: boolean;
|
|
262
|
+
/** Optional path (relative to project root) to a custom browser auth resolver module. */
|
|
263
|
+
authResolverPath?: string;
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Bridge client workers — connects this engine to remote iii instances.
|
|
268
|
+
* Each entry creates an `iii-bridge` worker in the config.
|
|
269
|
+
*/
|
|
270
|
+
bridge?: Array<{
|
|
271
|
+
url: string;
|
|
272
|
+
serviceId: string;
|
|
273
|
+
serviceName?: string;
|
|
274
|
+
expose?: Array<{
|
|
275
|
+
localFunction: string;
|
|
276
|
+
remoteFunction?: string;
|
|
277
|
+
}>;
|
|
278
|
+
forward?: Array<{
|
|
279
|
+
localFunction: string;
|
|
280
|
+
remoteFunction: string;
|
|
281
|
+
timeoutMs?: number;
|
|
282
|
+
}>;
|
|
283
|
+
}>;
|
|
284
|
+
/**
|
|
285
|
+
* Exec workers — spawns external processes alongside the engine.
|
|
286
|
+
* Each entry creates an `iii-exec` worker in the config.
|
|
287
|
+
*/
|
|
288
|
+
exec?: Array<{
|
|
289
|
+
watch?: string[];
|
|
290
|
+
exec: string[];
|
|
291
|
+
}>;
|
|
292
|
+
/** Anonymous usage telemetry. Set enabled: false to opt out. */
|
|
293
|
+
telemetry?: {
|
|
294
|
+
enabled?: boolean;
|
|
295
|
+
apiKey?: string;
|
|
296
|
+
sdkApiKey?: string;
|
|
297
|
+
heartbeatIntervalSecs?: number;
|
|
298
|
+
};
|
|
150
299
|
};
|
|
151
300
|
functions?: {
|
|
152
301
|
/** Directory under server/ where functions are, relative to serverDir (default: 'functions') */
|
|
153
302
|
dir?: string;
|
|
303
|
+
/**
|
|
304
|
+
* Function ID prefix for this layer's functions.
|
|
305
|
+
* Set in a layer's `nuxt.config.ts` to namespace its functions.
|
|
306
|
+
* Priority: this value → `$meta.name` → package.json name → directory name.
|
|
307
|
+
* Set to `''` (empty string) to explicitly opt out of any prefix.
|
|
308
|
+
* Has no effect in the root project (always un-prefixed).
|
|
309
|
+
* Example: 'myorg::auth'
|
|
310
|
+
*/
|
|
311
|
+
prefix?: string;
|
|
154
312
|
python?: {
|
|
155
313
|
/**
|
|
156
314
|
* Path to the Python executable used **in development only** (e.g. a virtualenv).
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { join, dirname, relative,
|
|
2
|
-
import { defineNuxtModule, createResolver, hasNuxtModule, addTemplate, addServerPlugin, addServerHandler, addServerImports, addImports, updateTemplates } from '@nuxt/kit';
|
|
1
|
+
import { join, dirname, basename, relative, parse } from 'node:path';
|
|
2
|
+
import { defineNuxtModule, createResolver, extendViteConfig, hasNuxtModule, addTemplate, addServerPlugin, addServerHandler, addServerImports, addImports, addPlugin, updateTemplates } from '@nuxt/kit';
|
|
3
3
|
import { existsSync, mkdirSync, chmodSync, createWriteStream, unlinkSync, writeFileSync, readFileSync, copyFileSync } from 'node:fs';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
4
5
|
import { exec, execFileSync, spawn } from 'node:child_process';
|
|
5
6
|
import { promisify } from 'node:util';
|
|
6
7
|
import { pipeline } from 'node:stream/promises';
|
|
@@ -844,34 +845,36 @@ function defaultIiiEngineConfig() {
|
|
|
844
845
|
}
|
|
845
846
|
function defaultStateAdapter(stateDir) {
|
|
846
847
|
return {
|
|
847
|
-
|
|
848
|
+
name: "kv",
|
|
848
849
|
config: { store_method: "file_based", file_path: "./data/state_store" }
|
|
849
850
|
};
|
|
850
851
|
}
|
|
851
852
|
function defaultQueueAdapter(queueDir) {
|
|
852
853
|
return {
|
|
853
|
-
|
|
854
|
+
name: "builtin",
|
|
854
855
|
config: { store_method: "file_based", file_path: "./data/queue_store" }
|
|
855
856
|
};
|
|
856
857
|
}
|
|
857
858
|
function defaultCronAdapter() {
|
|
858
|
-
return {
|
|
859
|
+
return { name: "kv" };
|
|
859
860
|
}
|
|
860
861
|
function defaultStreamAdapter() {
|
|
861
|
-
return {
|
|
862
|
+
return { name: "kv" };
|
|
862
863
|
}
|
|
863
864
|
function generateIiiConfigYaml(cfg) {
|
|
864
|
-
const
|
|
865
|
+
const workers = [];
|
|
866
|
+
workers.push({ name: "iii-worker-manager", config: { port: cfg.wsPort } });
|
|
865
867
|
const restApiConfig = {
|
|
866
868
|
port: cfg.restApi?.port ?? cfg.httpPort
|
|
867
869
|
};
|
|
868
870
|
if (cfg.restApi?.host) restApiConfig.host = cfg.restApi.host;
|
|
869
871
|
if (cfg.restApi?.default_timeout != null) restApiConfig.default_timeout = cfg.restApi.default_timeout;
|
|
870
872
|
if (cfg.restApi?.concurrency_request_limit != null) restApiConfig.concurrency_request_limit = cfg.restApi.concurrency_request_limit;
|
|
871
|
-
|
|
873
|
+
if (cfg.restApi?.cors) restApiConfig.cors = cfg.restApi.cors;
|
|
874
|
+
workers.push({ name: "iii-http", config: restApiConfig });
|
|
872
875
|
if (cfg.modules.state !== false) {
|
|
873
876
|
const adapter = cfg.state?.adapter ?? defaultStateAdapter();
|
|
874
|
-
|
|
877
|
+
workers.push({ name: "iii-state", config: { adapter } });
|
|
875
878
|
}
|
|
876
879
|
if (cfg.modules.queue !== false) {
|
|
877
880
|
const adapter = cfg.queue?.adapter ?? defaultQueueAdapter();
|
|
@@ -880,11 +883,11 @@ function generateIiiConfigYaml(cfg) {
|
|
|
880
883
|
if (queueConfigs && Object.keys(queueConfigs).length > 0) {
|
|
881
884
|
queueModCfg.queue_configs = queueConfigs;
|
|
882
885
|
}
|
|
883
|
-
|
|
886
|
+
workers.push({ name: "iii-queue", config: queueModCfg });
|
|
884
887
|
}
|
|
885
888
|
if (cfg.modules.cron !== false) {
|
|
886
889
|
const adapter = cfg.cron?.adapter ?? defaultCronAdapter();
|
|
887
|
-
|
|
890
|
+
workers.push({ name: "iii-cron", config: { adapter } });
|
|
888
891
|
}
|
|
889
892
|
if (cfg.modules.stream !== false) {
|
|
890
893
|
const streamCfg = {
|
|
@@ -894,7 +897,7 @@ function generateIiiConfigYaml(cfg) {
|
|
|
894
897
|
if (cfg.stream?.auth_function !== void 0) streamCfg.auth_function = cfg.stream.auth_function;
|
|
895
898
|
const streamAdapter = cfg.stream?.adapter ?? defaultStreamAdapter();
|
|
896
899
|
streamCfg.adapter = streamAdapter;
|
|
897
|
-
|
|
900
|
+
workers.push({ name: "iii-stream", config: streamCfg });
|
|
898
901
|
}
|
|
899
902
|
if (cfg.modules.observability !== false) {
|
|
900
903
|
const oCfg = cfg.observability ?? {};
|
|
@@ -922,10 +925,34 @@ function generateIiiConfigYaml(cfg) {
|
|
|
922
925
|
if (oCfg.logs_console_output != null) otelConfig.logs_console_output = oCfg.logs_console_output;
|
|
923
926
|
if (oCfg.level) otelConfig.level = oCfg.level;
|
|
924
927
|
if (oCfg.format) otelConfig.format = oCfg.format;
|
|
925
|
-
|
|
928
|
+
if (oCfg.sampling) otelConfig.sampling = oCfg.sampling;
|
|
929
|
+
if (oCfg.alerts?.length) otelConfig.alerts = oCfg.alerts;
|
|
930
|
+
workers.push({ name: "iii-observability", config: otelConfig });
|
|
931
|
+
}
|
|
932
|
+
if (cfg.modules.pubsub) {
|
|
933
|
+
const pubsubCfg = {};
|
|
934
|
+
if (cfg.pubsub?.adapter) pubsubCfg.adapter = cfg.pubsub.adapter;
|
|
935
|
+
workers.push({ name: "iii-pubsub", config: Object.keys(pubsubCfg).length ? pubsubCfg : void 0 });
|
|
936
|
+
}
|
|
937
|
+
if (cfg.modules.httpFunctions) {
|
|
938
|
+
const hfCfg = {};
|
|
939
|
+
if (cfg.httpFunctions?.security) hfCfg.security = cfg.httpFunctions.security;
|
|
940
|
+
workers.push({ name: "iii-http-functions", config: Object.keys(hfCfg).length ? hfCfg : void 0 });
|
|
941
|
+
}
|
|
942
|
+
for (const bridgeCfg of cfg.bridge ?? []) {
|
|
943
|
+
workers.push({ name: "iii-bridge", config: bridgeCfg });
|
|
944
|
+
}
|
|
945
|
+
for (const execCfg of cfg.exec ?? []) {
|
|
946
|
+
workers.push({ name: "iii-exec", config: execCfg });
|
|
947
|
+
}
|
|
948
|
+
if (cfg.workerManagerRbac) {
|
|
949
|
+
workers.push({ name: "iii-worker-manager", config: cfg.workerManagerRbac });
|
|
950
|
+
}
|
|
951
|
+
if (cfg.telemetry) {
|
|
952
|
+
workers.push({ name: "iii-telemetry", config: cfg.telemetry });
|
|
926
953
|
}
|
|
927
954
|
return `# Auto-generated by nvent \u2014 do not edit manually
|
|
928
|
-
` + stringifyYAML({
|
|
955
|
+
` + stringifyYAML({ workers });
|
|
929
956
|
}
|
|
930
957
|
function writeIiiConfig(outputPath, cfg) {
|
|
931
958
|
mkdirSync(dirname(outputPath), { recursive: true });
|
|
@@ -939,7 +966,7 @@ function buildEngineConfig(iiiOpts) {
|
|
|
939
966
|
wsPort: iiiOpts.wsPort ?? 49134,
|
|
940
967
|
httpPort: iiiOpts.httpPort ?? 3111,
|
|
941
968
|
streamPort: iiiOpts.streamPort ?? 3112,
|
|
942
|
-
modules: { state: true, queue: true, cron: true, observability: true, stream: true, ...iiiOpts.modules },
|
|
969
|
+
modules: { state: true, queue: true, cron: true, observability: true, stream: true, pubsub: false, httpFunctions: false, exec: false, telemetry: false, ...iiiOpts.modules },
|
|
943
970
|
state: iiiOpts.state ? { adapter: mapStateAdapter(iiiOpts.state) } : void 0,
|
|
944
971
|
queue: iiiOpts.queue ? {
|
|
945
972
|
adapter: mapQueueAdapter(iiiOpts.queue?.adapter),
|
|
@@ -959,7 +986,44 @@ function buildEngineConfig(iiiOpts) {
|
|
|
959
986
|
restApi: iiiOpts.restApi ? {
|
|
960
987
|
host: iiiOpts.restApi.host,
|
|
961
988
|
default_timeout: iiiOpts.restApi.defaultTimeout,
|
|
962
|
-
concurrency_request_limit: iiiOpts.restApi.concurrencyRequestLimit
|
|
989
|
+
concurrency_request_limit: iiiOpts.restApi.concurrencyRequestLimit,
|
|
990
|
+
cors: iiiOpts.restApi.cors ? {
|
|
991
|
+
allowed_origins: iiiOpts.restApi.cors.allowedOrigins,
|
|
992
|
+
allowed_methods: iiiOpts.restApi.cors.allowedMethods
|
|
993
|
+
} : void 0
|
|
994
|
+
} : void 0,
|
|
995
|
+
pubsub: iiiOpts.pubsub ? { adapter: mapPubSubAdapter(iiiOpts.pubsub) } : void 0,
|
|
996
|
+
httpFunctions: iiiOpts.httpFunctions ? {
|
|
997
|
+
security: iiiOpts.httpFunctions.security ? {
|
|
998
|
+
url_allowlist: iiiOpts.httpFunctions.security.urlAllowlist,
|
|
999
|
+
block_private_ips: iiiOpts.httpFunctions.security.blockPrivateIps,
|
|
1000
|
+
require_https: iiiOpts.httpFunctions.security.requireHttps
|
|
1001
|
+
} : void 0
|
|
1002
|
+
} : void 0,
|
|
1003
|
+
workerManagerRbac: iiiOpts.workerManager?.rbac ? {
|
|
1004
|
+
port: iiiOpts.workerManager.rbac.port ?? 49135,
|
|
1005
|
+
rbac: {
|
|
1006
|
+
auth_function_id: iiiOpts.workerManager.rbac.authFunctionId ?? "nvent::browser::auth",
|
|
1007
|
+
expose_functions: iiiOpts.workerManager.rbac.exposeFunctions,
|
|
1008
|
+
middleware_function_id: iiiOpts.workerManager.rbac.middlewareFunctionId,
|
|
1009
|
+
allow_function_registration: iiiOpts.workerManager.rbac.allowFunctionRegistration,
|
|
1010
|
+
allow_trigger_type_registration: iiiOpts.workerManager.rbac.allowTriggerTypeRegistration,
|
|
1011
|
+
function_registration_prefix: iiiOpts.workerManager.rbac.functionRegistrationPrefix
|
|
1012
|
+
}
|
|
1013
|
+
} : void 0,
|
|
1014
|
+
bridge: iiiOpts.bridge?.map((b) => ({
|
|
1015
|
+
url: b.url,
|
|
1016
|
+
service_id: b.serviceId,
|
|
1017
|
+
service_name: b.serviceName,
|
|
1018
|
+
expose: b.expose?.map((e) => ({ local_function: e.localFunction, remote_function: e.remoteFunction })),
|
|
1019
|
+
forward: b.forward?.map((f) => ({ local_function: f.localFunction, remote_function: f.remoteFunction, timeout_ms: f.timeoutMs }))
|
|
1020
|
+
})),
|
|
1021
|
+
exec: iiiOpts.exec?.map((e) => ({ watch: e.watch, exec: e.exec })),
|
|
1022
|
+
telemetry: iiiOpts.telemetry ? {
|
|
1023
|
+
enabled: iiiOpts.telemetry.enabled,
|
|
1024
|
+
api_key: iiiOpts.telemetry.apiKey,
|
|
1025
|
+
sdk_api_key: iiiOpts.telemetry.sdkApiKey,
|
|
1026
|
+
heartbeat_interval_secs: iiiOpts.telemetry.heartbeatIntervalSecs
|
|
963
1027
|
} : void 0,
|
|
964
1028
|
observability: iiiOpts.observability ? {
|
|
965
1029
|
enabled: iiiOpts.observability.enabled,
|
|
@@ -982,6 +1046,24 @@ function buildEngineConfig(iiiOpts) {
|
|
|
982
1046
|
logs_flush_interval_ms: iiiOpts.observability.logsFlushIntervalMs,
|
|
983
1047
|
logs_sampling_ratio: iiiOpts.observability.logsSamplingRatio,
|
|
984
1048
|
logs_console_output: iiiOpts.observability.logsConsoleOutput,
|
|
1049
|
+
sampling: iiiOpts.observability.sampling ? {
|
|
1050
|
+
default: iiiOpts.observability.sampling.default,
|
|
1051
|
+
parent_based: iiiOpts.observability.sampling.parentBased,
|
|
1052
|
+
rules: iiiOpts.observability.sampling.rules,
|
|
1053
|
+
rate_limit: iiiOpts.observability.sampling.rateLimit ? {
|
|
1054
|
+
max_traces_per_second: iiiOpts.observability.sampling.rateLimit.maxTracesPerSecond
|
|
1055
|
+
} : void 0
|
|
1056
|
+
} : void 0,
|
|
1057
|
+
alerts: iiiOpts.observability.alerts?.map((a) => ({
|
|
1058
|
+
name: a.name,
|
|
1059
|
+
metric: a.metric,
|
|
1060
|
+
threshold: a.threshold,
|
|
1061
|
+
operator: a.operator,
|
|
1062
|
+
window_seconds: a.windowSeconds,
|
|
1063
|
+
enabled: a.enabled,
|
|
1064
|
+
cooldown_seconds: a.cooldownSeconds,
|
|
1065
|
+
action: a.action
|
|
1066
|
+
})),
|
|
985
1067
|
level: iiiOpts.observability.level,
|
|
986
1068
|
format: iiiOpts.observability.format
|
|
987
1069
|
} : void 0
|
|
@@ -989,39 +1071,60 @@ function buildEngineConfig(iiiOpts) {
|
|
|
989
1071
|
}
|
|
990
1072
|
function mapStateAdapter(a) {
|
|
991
1073
|
if (!a?.adapter) return void 0;
|
|
992
|
-
if (a.adapter.type === "redis")
|
|
993
|
-
|
|
1074
|
+
if (a.adapter.type === "redis") return { name: "redis", config: { redis_url: a.adapter.redisUrl } };
|
|
1075
|
+
if (a.adapter.type === "bridge") return { name: "bridge", config: { bridge_url: a.adapter.bridgeUrl } };
|
|
994
1076
|
return {
|
|
995
|
-
|
|
996
|
-
config: { store_method: a.adapter.storeMethod, file_path: a.adapter.filePath }
|
|
1077
|
+
name: "kv",
|
|
1078
|
+
config: { store_method: a.adapter.storeMethod, file_path: a.adapter.filePath, save_interval_ms: a.adapter.saveIntervalMs }
|
|
997
1079
|
};
|
|
998
1080
|
}
|
|
999
1081
|
function mapQueueAdapter(a) {
|
|
1000
1082
|
if (!a) return void 0;
|
|
1001
|
-
if (a.type === "redis")
|
|
1002
|
-
|
|
1003
|
-
if (a.type === "
|
|
1004
|
-
return { class: "modules::queue::RabbitMQAdapter", config: { amqp_url: a.amqpUrl } };
|
|
1083
|
+
if (a.type === "redis") return { name: "redis", config: { redis_url: a.redisUrl } };
|
|
1084
|
+
if (a.type === "rabbitmq") return { name: "rabbitmq", config: { amqp_url: a.amqpUrl, max_attempts: a.maxAttempts, prefetch_count: a.prefetchCount, queue_mode: a.queueMode } };
|
|
1085
|
+
if (a.type === "bridge") return { name: "bridge", config: { bridge_url: a.bridgeUrl } };
|
|
1005
1086
|
return {
|
|
1006
|
-
|
|
1007
|
-
config: {
|
|
1087
|
+
name: "builtin",
|
|
1088
|
+
config: {
|
|
1089
|
+
store_method: a.storeMethod,
|
|
1090
|
+
file_path: a.filePath,
|
|
1091
|
+
save_interval_ms: a.saveIntervalMs,
|
|
1092
|
+
max_attempts: a.maxAttempts,
|
|
1093
|
+
backoff_ms: a.backoffMs,
|
|
1094
|
+
concurrency: a.concurrency,
|
|
1095
|
+
poll_interval_ms: a.pollIntervalMs,
|
|
1096
|
+
mode: a.mode
|
|
1097
|
+
}
|
|
1008
1098
|
};
|
|
1009
1099
|
}
|
|
1010
1100
|
function mapCronAdapter(a) {
|
|
1011
1101
|
if (!a?.adapter) return void 0;
|
|
1012
|
-
if (a.adapter.type === "redis")
|
|
1013
|
-
|
|
1014
|
-
|
|
1102
|
+
if (a.adapter.type === "redis") return { name: "redis", config: { redis_url: a.adapter.redisUrl } };
|
|
1103
|
+
return {
|
|
1104
|
+
name: "kv",
|
|
1105
|
+
config: {
|
|
1106
|
+
lock_ttl_ms: a.adapter.lockTtlMs,
|
|
1107
|
+
lock_index: a.adapter.lockIndex,
|
|
1108
|
+
store_method: a.adapter.storeMethod,
|
|
1109
|
+
file_path: a.adapter.filePath,
|
|
1110
|
+
save_interval_ms: a.adapter.saveIntervalMs
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1015
1113
|
}
|
|
1016
1114
|
function mapStreamAdapter(a) {
|
|
1017
1115
|
if (!a?.adapter) return void 0;
|
|
1018
|
-
if (a.adapter.type === "redis")
|
|
1019
|
-
|
|
1116
|
+
if (a.adapter.type === "redis") return { name: "redis", config: { redis_url: a.adapter.redisUrl } };
|
|
1117
|
+
if (a.adapter.type === "bridge") return { name: "bridge", config: { bridge_url: a.adapter.bridgeUrl } };
|
|
1020
1118
|
return {
|
|
1021
|
-
|
|
1022
|
-
config: { store_method: a.adapter.storeMethod, file_path: a.adapter.filePath }
|
|
1119
|
+
name: "kv",
|
|
1120
|
+
config: { store_method: a.adapter.storeMethod, file_path: a.adapter.filePath, save_interval_ms: a.adapter.saveIntervalMs }
|
|
1023
1121
|
};
|
|
1024
1122
|
}
|
|
1123
|
+
function mapPubSubAdapter(a) {
|
|
1124
|
+
if (!a?.adapter) return void 0;
|
|
1125
|
+
if (a.adapter.type === "redis") return { name: "redis", config: { redis_url: a.adapter.redisUrl } };
|
|
1126
|
+
return { name: "local" };
|
|
1127
|
+
}
|
|
1025
1128
|
|
|
1026
1129
|
function filePathToFunctionId(relPath) {
|
|
1027
1130
|
const noExt = relPath.replace(/\.[a-zA-Z]+$/, "");
|
|
@@ -1042,6 +1145,7 @@ async function scanFunctions(opts) {
|
|
|
1042
1145
|
for (const layer of layerInfos) {
|
|
1043
1146
|
const serverDir = layer.serverDir || join(layer.rootDir, "server");
|
|
1044
1147
|
const fnDir = join(serverDir, functionsDir);
|
|
1148
|
+
const prefix = layer.prefix ? `${layer.prefix}::` : "";
|
|
1045
1149
|
if (!existsSync(fnDir)) continue;
|
|
1046
1150
|
const [jsFiles, pyFiles] = await Promise.all([
|
|
1047
1151
|
globby(["**/*.{ts,js,mts,mjs}"], {
|
|
@@ -1056,34 +1160,27 @@ async function scanFunctions(opts) {
|
|
|
1056
1160
|
})
|
|
1057
1161
|
]);
|
|
1058
1162
|
for (const file of jsFiles) {
|
|
1059
|
-
functions.push({ id: filePathToFunctionId(file)
|
|
1163
|
+
functions.push({ id: `${prefix}${filePathToFunctionId(file)}`, absPath: join(fnDir, file), relativePath: file });
|
|
1060
1164
|
}
|
|
1061
1165
|
for (const file of pyFiles) {
|
|
1062
1166
|
const absPath = join(fnDir, file);
|
|
1063
1167
|
const standalone = detectPythonStandalone(absPath);
|
|
1064
|
-
pythonFunctions.push({ id: filePathToFunctionId(file)
|
|
1168
|
+
pythonFunctions.push({ id: `${prefix}${filePathToFunctionId(file)}`, absPath, relativePath: file, standalone });
|
|
1065
1169
|
}
|
|
1066
1170
|
}
|
|
1067
1171
|
return { functions, pythonFunctions };
|
|
1068
1172
|
}
|
|
1069
1173
|
function generateIiiRegistryTemplate(scanned, pythonPathRewrite) {
|
|
1070
1174
|
const lines = ["// auto-generated by nvent \u2014 do not edit", ""];
|
|
1071
|
-
lines.push(`function
|
|
1072
|
-
lines.push(` const
|
|
1073
|
-
lines.push(`
|
|
1074
|
-
lines.push(` const triggers = ns.triggers`);
|
|
1075
|
-
lines.push(` if (def?.__nventStep) {`);
|
|
1076
|
-
lines.push(` const name = def.name ?? fallbackName`);
|
|
1077
|
-
lines.push(` return { name, description: def.description, handler: def.handler, triggers: (def.triggers ?? []).map(t => ({ ...t, function_id: name })), enqueues: def.enqueues ?? [], flows: def.flows ?? [], stream: def.stream, filePath: absPath }`);
|
|
1078
|
-
lines.push(` }`);
|
|
1079
|
-
lines.push(` const name = meta?.name ?? fallbackName`);
|
|
1080
|
-
lines.push(` return { name, description: meta?.description, handler: def, triggers: (triggers ?? []).map(t => ({ ...t, function_id: name })), enqueues: [], flows: [], stream: undefined, filePath: absPath }`);
|
|
1175
|
+
lines.push(`function _entry(ns, id, absPath) {`);
|
|
1176
|
+
lines.push(` const fn = ns.default`);
|
|
1177
|
+
lines.push(` return { id, description: fn.description, handler: fn.handler, triggers: (fn.triggers ?? []).map(t => ({ ...t, function_id: id })), request_format: fn.request_format, response_format: fn.response_format, filePath: absPath }`);
|
|
1081
1178
|
lines.push(`}`);
|
|
1082
1179
|
lines.push("");
|
|
1083
1180
|
const entries = scanned.functions.map((fn, i) => {
|
|
1084
1181
|
const ns = `fn${i}`;
|
|
1085
1182
|
lines.push(`import * as ${ns} from ${genString(fn.absPath)}`);
|
|
1086
|
-
return `
|
|
1183
|
+
return `_entry(${ns}, ${genString(fn.id)}, ${genString(fn.absPath)})`;
|
|
1087
1184
|
});
|
|
1088
1185
|
lines.push("");
|
|
1089
1186
|
lines.push(`export const registry = {`);
|
|
@@ -1102,11 +1199,29 @@ function generateIiiRegistryTemplate(scanned, pythonPathRewrite) {
|
|
|
1102
1199
|
return lines.join("\n");
|
|
1103
1200
|
}
|
|
1104
1201
|
|
|
1202
|
+
function writePyrightConfig(options) {
|
|
1203
|
+
try {
|
|
1204
|
+
const { rootDir, devPath, includePaths } = options;
|
|
1205
|
+
const binDir = dirname(devPath);
|
|
1206
|
+
const venvDir = dirname(binDir);
|
|
1207
|
+
const venv = basename(venvDir);
|
|
1208
|
+
const venvPath = dirname(venvDir) || ".";
|
|
1209
|
+
const include = includePaths.map((p) => relative(rootDir, p)).filter((p) => !p.startsWith(".."));
|
|
1210
|
+
const config = { venvPath, venv };
|
|
1211
|
+
if (include.length > 0) config.include = include;
|
|
1212
|
+
writeFileSync(
|
|
1213
|
+
join(rootDir, "pyrightconfig.json"),
|
|
1214
|
+
JSON.stringify(config, null, 2) + "\n",
|
|
1215
|
+
"utf-8"
|
|
1216
|
+
);
|
|
1217
|
+
} catch {
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1105
1220
|
async function installPythonRequirements(requirementsPath, pythonBin, logLevel) {
|
|
1106
1221
|
if (!existsSync(requirementsPath)) return;
|
|
1107
1222
|
if (logLevel !== "none") console.log(`[nvent] Installing Python requirements from ${requirementsPath}`);
|
|
1108
1223
|
return new Promise((resolve) => {
|
|
1109
|
-
const proc = spawn(pythonBin, ["-m", "pip", "install", "-r", requirementsPath, "--quiet"], {
|
|
1224
|
+
const proc = spawn(pythonBin, ["-m", "pip", "install", "-r", requirementsPath, "--upgrade", "--quiet"], {
|
|
1110
1225
|
stdio: ["ignore", "pipe", "pipe"]
|
|
1111
1226
|
});
|
|
1112
1227
|
let stderr = "";
|
|
@@ -1156,6 +1271,11 @@ const module$1 = defineNuxtModule({
|
|
|
1156
1271
|
const { resolve } = createResolver(import.meta.url);
|
|
1157
1272
|
const PYTHON_RUNTIME_SRC = resolve("./runtime/python/worker_runtime.py");
|
|
1158
1273
|
const PYTHON_NVENT_HELPER_SRC = resolve("./runtime/python/nvent.py");
|
|
1274
|
+
extendViteConfig((config) => {
|
|
1275
|
+
config.optimizeDeps ||= {};
|
|
1276
|
+
config.optimizeDeps.include ||= [];
|
|
1277
|
+
config.optimizeDeps.include.push("iii-browser-sdk");
|
|
1278
|
+
});
|
|
1159
1279
|
const userConfig = nuxt.options[meta.configKey] ?? {};
|
|
1160
1280
|
const opts = { ...userConfig, ...options };
|
|
1161
1281
|
const iiiOpts = opts.iii ?? {};
|
|
@@ -1188,11 +1308,20 @@ const module$1 = defineNuxtModule({
|
|
|
1188
1308
|
httpHost: iiiOpts.httpHost ?? "localhost",
|
|
1189
1309
|
wsPort: engineCfg.wsPort,
|
|
1190
1310
|
streamPort: engineCfg.streamPort,
|
|
1311
|
+
browserPort: engineCfg.workerManagerRbac?.port ?? iiiOpts.workerManager?.rbac?.port ?? 49135,
|
|
1191
1312
|
managed,
|
|
1192
1313
|
mode,
|
|
1193
1314
|
version,
|
|
1194
1315
|
modules: engineCfg.modules,
|
|
1195
1316
|
logLevel,
|
|
1317
|
+
browserAuthFunctionId: iiiOpts.workerManager?.rbac?.authFunctionId ?? "nvent::browser::auth",
|
|
1318
|
+
browserAuth: {
|
|
1319
|
+
// Signed, short-lived token is minted by /_iii/browser and validated by nvent::browser::auth.
|
|
1320
|
+
secret: process.env.NVENT_BROWSER_AUTH_SECRET ?? randomUUID(),
|
|
1321
|
+
tokenTtlSeconds: iiiOpts.workerManager?.rbac?.tokenTtlSeconds ?? 120,
|
|
1322
|
+
allowAnonymous: iiiOpts.workerManager?.rbac?.allowAnonymous ?? true,
|
|
1323
|
+
authResolverPath: iiiOpts.workerManager?.rbac?.authResolverPath
|
|
1324
|
+
},
|
|
1196
1325
|
// YAML config embedded at build time so the production lifecycle plugin can
|
|
1197
1326
|
// write iii-config.yaml without needing confbox or rebuilding from options.
|
|
1198
1327
|
engineConfigYaml
|
|
@@ -1210,9 +1339,27 @@ const module$1 = defineNuxtModule({
|
|
|
1210
1339
|
flow: consoleCfg.flow ?? true
|
|
1211
1340
|
}
|
|
1212
1341
|
};
|
|
1213
|
-
|
|
1342
|
+
function resolveLayerPrefix(layer, isRoot) {
|
|
1343
|
+
if (isRoot) return void 0;
|
|
1344
|
+
const layerCfg = layer.config;
|
|
1345
|
+
const explicit = layerCfg?.nvent?.functions?.prefix;
|
|
1346
|
+
if (typeof explicit === "string") return explicit || void 0;
|
|
1347
|
+
const metaName = layerCfg?.$meta?.name;
|
|
1348
|
+
if (metaName) return metaName;
|
|
1349
|
+
const pkgPath = join(layer.config.rootDir, "package.json");
|
|
1350
|
+
if (existsSync(pkgPath)) {
|
|
1351
|
+
try {
|
|
1352
|
+
const pkgName = JSON.parse(readFileSync(pkgPath, "utf-8")).name ?? "";
|
|
1353
|
+
if (pkgName) return pkgName.split("/").pop().replace(/^nuxt-/, "");
|
|
1354
|
+
} catch {
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
return parse(layer.config.rootDir).name;
|
|
1358
|
+
}
|
|
1359
|
+
const layerInfos = nuxt.options._layers.map((l, i) => ({
|
|
1214
1360
|
rootDir: l.config.rootDir,
|
|
1215
|
-
serverDir: l.config?.serverDir ?? join(l.config.rootDir, "server")
|
|
1361
|
+
serverDir: l.config?.serverDir ?? join(l.config.rootDir, "server"),
|
|
1362
|
+
prefix: resolveLayerPrefix(l, i === 0)
|
|
1216
1363
|
}));
|
|
1217
1364
|
let lastScanned = await scanFunctions({ layerInfos, functionsDir });
|
|
1218
1365
|
let pythonPathRewrite;
|
|
@@ -1245,19 +1392,27 @@ const module$1 = defineNuxtModule({
|
|
|
1245
1392
|
};
|
|
1246
1393
|
nitroOpts.experimental ??= {};
|
|
1247
1394
|
nitroOpts.experimental.websocket = true;
|
|
1248
|
-
addServerHandler({ route: "/stream/**", handler: resolve("./runtime/nitro/routes/stream-proxy") });
|
|
1395
|
+
addServerHandler({ route: "/_iii/stream/**", handler: resolve("./runtime/nitro/routes/stream-proxy") });
|
|
1396
|
+
addServerHandler({ route: "/_iii/browser", handler: resolve("./runtime/nitro/routes/browser-proxy") });
|
|
1249
1397
|
addServerImports([
|
|
1250
1398
|
{ from: resolve("./runtime/nitro/utils/useIii"), name: "useIii" },
|
|
1251
1399
|
{ from: resolve("./runtime/nitro/utils/useIii"), name: "useIiiHealth" },
|
|
1252
|
-
{ from: resolve("./runtime/nitro/utils/
|
|
1253
|
-
{ from: resolve("./runtime/nitro/utils/defineFunction"), name: "defineFunction" },
|
|
1254
|
-
{ from: resolve("./runtime/nitro/utils/defineFunction"), name: "FunctionContext" }
|
|
1400
|
+
{ from: resolve("./runtime/nitro/utils/defineFunction"), name: "defineFunction" }
|
|
1255
1401
|
]);
|
|
1402
|
+
nuxt.options.alias["#nvent/server"] = resolve("./runtime/nitro/server");
|
|
1256
1403
|
addImports([
|
|
1257
|
-
{ from: resolve("./runtime/app/composables/
|
|
1258
|
-
{ from: resolve("./runtime/app/composables/
|
|
1404
|
+
{ from: resolve("./runtime/app/composables/useIiiStream"), name: "useIiiStream" },
|
|
1405
|
+
{ from: resolve("./runtime/app/composables/useIii"), name: "useIii" }
|
|
1259
1406
|
]);
|
|
1407
|
+
addPlugin({ src: resolve("./runtime/app/plugins/iii.client"), mode: "client" });
|
|
1260
1408
|
if (nuxt.options.dev) {
|
|
1409
|
+
if (!skipPython && opts.functions?.python?.devPath) {
|
|
1410
|
+
writePyrightConfig({
|
|
1411
|
+
rootDir: nuxt.options.rootDir,
|
|
1412
|
+
devPath: opts.functions.python.devPath,
|
|
1413
|
+
includePaths: layerInfos.map((l) => join(l.serverDir, functionsDir))
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1261
1416
|
const nventDir = join(nuxt.options.rootDir, "node_modules", ".nvent");
|
|
1262
1417
|
const binDir = join(nventDir, "bin");
|
|
1263
1418
|
if (managed && mode === "local") {
|