nvent 0.4.5 → 0.5.0

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.
Files changed (124) hide show
  1. package/dist/module.d.mts +1 -1
  2. package/dist/module.mjs +433 -175
  3. package/dist/runtime/adapters/base/index.d.ts +6 -0
  4. package/dist/runtime/adapters/base/index.js +1 -0
  5. package/dist/runtime/adapters/base/store-validator.d.ts +48 -0
  6. package/dist/runtime/adapters/base/store-validator.js +147 -0
  7. package/dist/runtime/adapters/builtin/file-queue.d.ts +15 -1
  8. package/dist/runtime/adapters/builtin/file-queue.js +70 -6
  9. package/dist/runtime/adapters/builtin/file-store.d.ts +4 -18
  10. package/dist/runtime/adapters/builtin/file-store.js +90 -109
  11. package/dist/runtime/adapters/builtin/memory-queue.js +4 -0
  12. package/dist/runtime/adapters/builtin/memory-store.d.ts +42 -31
  13. package/dist/runtime/adapters/builtin/memory-store.js +253 -183
  14. package/dist/runtime/adapters/factory.d.ts +2 -2
  15. package/dist/runtime/adapters/factory.js +54 -20
  16. package/dist/runtime/adapters/interfaces/store.d.ts +177 -113
  17. package/dist/runtime/config/index.d.ts +2 -2
  18. package/dist/runtime/config/index.js +14 -6
  19. package/dist/runtime/config/types.d.ts +32 -2
  20. package/dist/runtime/events/eventBus.d.ts +1 -1
  21. package/dist/runtime/events/types.d.ts +31 -2
  22. package/dist/runtime/events/utils/scheduleTrigger.d.ts +8 -0
  23. package/dist/runtime/events/utils/scheduleTrigger.js +69 -0
  24. package/dist/runtime/events/utils/stallDetector.d.ts +44 -3
  25. package/dist/runtime/events/utils/stallDetector.js +288 -89
  26. package/dist/runtime/events/utils/triggerRuntime.d.ts +58 -0
  27. package/dist/runtime/events/utils/triggerRuntime.js +212 -0
  28. package/dist/runtime/events/wiring/flowWiring.d.ts +11 -5
  29. package/dist/runtime/events/wiring/flowWiring.js +620 -92
  30. package/dist/runtime/events/wiring/registry.d.ts +2 -2
  31. package/dist/runtime/events/wiring/registry.js +8 -6
  32. package/dist/runtime/events/wiring/streamWiring.d.ts +15 -11
  33. package/dist/runtime/events/wiring/streamWiring.js +88 -11
  34. package/dist/runtime/events/wiring/triggerWiring.d.ts +21 -0
  35. package/dist/runtime/events/wiring/triggerWiring.js +412 -0
  36. package/dist/runtime/{server → nitro}/plugins/00.adapters.js +8 -4
  37. package/dist/runtime/{server → nitro}/plugins/02.workers.js +21 -3
  38. package/dist/runtime/nitro/plugins/03.triggers.d.ts +12 -0
  39. package/dist/runtime/nitro/plugins/03.triggers.js +55 -0
  40. package/dist/runtime/nitro/routes/webhook.await.d.ts +23 -0
  41. package/dist/runtime/nitro/routes/webhook.await.js +90 -0
  42. package/dist/runtime/nitro/routes/webhook.trigger.d.ts +69 -0
  43. package/dist/runtime/nitro/routes/webhook.trigger.js +64 -0
  44. package/dist/runtime/{utils → nitro/utils}/adapters.d.ts +6 -6
  45. package/dist/runtime/nitro/utils/awaitPatterns/event.d.ts +15 -0
  46. package/dist/runtime/nitro/utils/awaitPatterns/event.js +120 -0
  47. package/dist/runtime/nitro/utils/awaitPatterns/index.d.ts +28 -0
  48. package/dist/runtime/nitro/utils/awaitPatterns/index.js +55 -0
  49. package/dist/runtime/nitro/utils/awaitPatterns/schedule.d.ts +16 -0
  50. package/dist/runtime/nitro/utils/awaitPatterns/schedule.js +78 -0
  51. package/dist/runtime/nitro/utils/awaitPatterns/time.d.ts +15 -0
  52. package/dist/runtime/nitro/utils/awaitPatterns/time.js +67 -0
  53. package/dist/runtime/nitro/utils/awaitPatterns/webhook.d.ts +15 -0
  54. package/dist/runtime/nitro/utils/awaitPatterns/webhook.js +120 -0
  55. package/dist/runtime/{utils → nitro/utils}/defineFunction.d.ts +2 -2
  56. package/dist/runtime/{utils → nitro/utils}/defineFunction.js +3 -3
  57. package/dist/runtime/{utils → nitro/utils}/defineFunctionConfig.d.ts +156 -0
  58. package/dist/runtime/{utils → nitro/utils}/defineFunctionConfig.js +1 -0
  59. package/dist/runtime/nitro/utils/defineHooks.d.ts +41 -0
  60. package/dist/runtime/nitro/utils/defineHooks.js +6 -0
  61. package/dist/runtime/{utils → nitro/utils}/registerAdapter.d.ts +3 -3
  62. package/dist/runtime/{utils → nitro/utils}/registerAdapter.js +1 -1
  63. package/dist/runtime/nitro/utils/useAwait.d.ts +71 -0
  64. package/dist/runtime/nitro/utils/useAwait.js +139 -0
  65. package/dist/runtime/{utils → nitro/utils}/useEventManager.d.ts +2 -2
  66. package/dist/runtime/{utils → nitro/utils}/useEventManager.js +1 -1
  67. package/dist/runtime/nitro/utils/useFlow.d.ts +68 -0
  68. package/dist/runtime/nitro/utils/useFlow.js +226 -0
  69. package/dist/runtime/nitro/utils/useHookRegistry.d.ts +34 -0
  70. package/dist/runtime/nitro/utils/useHookRegistry.js +25 -0
  71. package/dist/runtime/nitro/utils/useRunContext.d.ts +6 -0
  72. package/dist/runtime/nitro/utils/useRunContext.js +102 -0
  73. package/dist/runtime/nitro/utils/useStreamTopics.d.ts +83 -0
  74. package/dist/runtime/nitro/utils/useStreamTopics.js +94 -0
  75. package/dist/runtime/nitro/utils/useTrigger.d.ts +150 -0
  76. package/dist/runtime/nitro/utils/useTrigger.js +320 -0
  77. package/dist/runtime/scheduler/index.d.ts +33 -0
  78. package/dist/runtime/scheduler/index.js +38 -0
  79. package/dist/runtime/scheduler/scheduler.d.ts +113 -0
  80. package/dist/runtime/scheduler/scheduler.js +623 -0
  81. package/dist/runtime/scheduler/types.d.ts +116 -0
  82. package/dist/runtime/scheduler/types.js +0 -0
  83. package/dist/runtime/worker/node/runner.d.ts +12 -2
  84. package/dist/runtime/worker/node/runner.js +141 -37
  85. package/package.json +6 -6
  86. package/dist/runtime/server/api/_flows/[name]/clear-history.delete.d.ts +0 -10
  87. package/dist/runtime/server/api/_flows/[name]/clear-history.delete.js +0 -55
  88. package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.d.ts +0 -2
  89. package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.js +0 -21
  90. package/dist/runtime/server/api/_flows/[name]/runs.get.d.ts +0 -17
  91. package/dist/runtime/server/api/_flows/[name]/runs.get.js +0 -64
  92. package/dist/runtime/server/api/_flows/[name]/schedule.post.d.ts +0 -2
  93. package/dist/runtime/server/api/_flows/[name]/schedule.post.js +0 -66
  94. package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.d.ts +0 -2
  95. package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.js +0 -47
  96. package/dist/runtime/server/api/_flows/[name]/schedules.get.d.ts +0 -2
  97. package/dist/runtime/server/api/_flows/[name]/schedules.get.js +0 -50
  98. package/dist/runtime/server/api/_flows/[name]/start.post.d.ts +0 -2
  99. package/dist/runtime/server/api/_flows/[name]/start.post.js +0 -9
  100. package/dist/runtime/server/api/_flows/index.get.d.ts +0 -6
  101. package/dist/runtime/server/api/_flows/index.get.js +0 -5
  102. package/dist/runtime/server/api/_flows/ws.d.ts +0 -60
  103. package/dist/runtime/server/api/_flows/ws.js +0 -209
  104. package/dist/runtime/server/api/_queues/[name]/job/[id].get.d.ts +0 -2
  105. package/dist/runtime/server/api/_queues/[name]/job/[id].get.js +0 -14
  106. package/dist/runtime/server/api/_queues/[name]/job/index.get.d.ts +0 -2
  107. package/dist/runtime/server/api/_queues/[name]/job/index.get.js +0 -27
  108. package/dist/runtime/server/api/_queues/index.get.d.ts +0 -2
  109. package/dist/runtime/server/api/_queues/index.get.js +0 -106
  110. package/dist/runtime/server/api/_queues/ws.d.ts +0 -48
  111. package/dist/runtime/server/api/_queues/ws.js +0 -215
  112. package/dist/runtime/utils/useFlowEngine.d.ts +0 -19
  113. package/dist/runtime/utils/useFlowEngine.js +0 -108
  114. package/dist/runtime/utils/useStreamTopics.d.ts +0 -72
  115. package/dist/runtime/utils/useStreamTopics.js +0 -47
  116. /package/dist/runtime/{server → nitro}/plugins/00.adapters.d.ts +0 -0
  117. /package/dist/runtime/{server → nitro}/plugins/01.ws-lifecycle.d.ts +0 -0
  118. /package/dist/runtime/{server → nitro}/plugins/01.ws-lifecycle.js +0 -0
  119. /package/dist/runtime/{server → nitro}/plugins/02.workers.d.ts +0 -0
  120. /package/dist/runtime/{utils → nitro/utils}/adapters.js +0 -0
  121. /package/dist/runtime/{utils → nitro/utils}/useNventLogger.d.ts +0 -0
  122. /package/dist/runtime/{utils → nitro/utils}/useNventLogger.js +0 -0
  123. /package/dist/runtime/{utils → nitro/utils}/wsPeerManager.d.ts +0 -0
  124. /package/dist/runtime/{utils → nitro/utils}/wsPeerManager.js +0 -0
@@ -1,4 +1,5 @@
1
1
  import { useAdapterRegistry } from "./registry.js";
2
+ import { useStreamTopics, $useAnalyzedFlows } from "#imports";
2
3
  import {
3
4
  MemoryQueueAdapter,
4
5
  MemoryStreamAdapter,
@@ -39,29 +40,62 @@ async function createStreamAdapter(config) {
39
40
  async function createStoreAdapter(config) {
40
41
  const type = config.adapter || "file";
41
42
  const registry = useAdapterRegistry();
43
+ let adapter;
42
44
  if (registry.hasStore(type)) {
43
- const adapter = registry.getStore(type);
44
- return adapter;
45
- }
46
- switch (type) {
47
- case "memory": {
48
- return new MemoryStoreAdapter();
45
+ adapter = registry.getStore(type);
46
+ } else {
47
+ switch (type) {
48
+ case "memory": {
49
+ adapter = new MemoryStoreAdapter();
50
+ break;
51
+ }
52
+ case "file": {
53
+ const dataDir = config.file?.dataDir || ".data/store";
54
+ const fileAdapter = new FileStoreAdapter({
55
+ dataDir
56
+ });
57
+ await fileAdapter.init();
58
+ adapter = fileAdapter;
59
+ break;
60
+ }
61
+ case "redis":
62
+ throw new Error("Redis store adapter not registered. Install @nvent/adapter-store-redis and add it to your nuxt.config modules.");
63
+ case "postgres":
64
+ throw new Error("Postgres store adapter not yet implemented");
65
+ default:
66
+ throw new Error(`Unknown store adapter type: ${type}`);
49
67
  }
50
- case "file": {
51
- const dataDir = config.file?.dataDir || ".data/store";
52
- const adapter = new FileStoreAdapter({
53
- dataDir
54
- });
55
- await adapter.init();
56
- return adapter;
68
+ }
69
+ try {
70
+ const { StoreSubjects } = useStreamTopics();
71
+ const flowIndexKey = StoreSubjects.flowIndex();
72
+ const existingFlows = await adapter.index.read(flowIndexKey, { limit: 1 });
73
+ if (existingFlows.length === 0) {
74
+ const analyzedFlows = $useAnalyzedFlows();
75
+ if (analyzedFlows && analyzedFlows.length > 0) {
76
+ const now = (/* @__PURE__ */ new Date()).toISOString();
77
+ for (const flow of analyzedFlows) {
78
+ await adapter.index.add(flowIndexKey, flow.id, Date.now(), {
79
+ name: flow.id,
80
+ displayName: flow.id,
81
+ registeredAt: now,
82
+ stats: {
83
+ total: 0,
84
+ success: 0,
85
+ failure: 0,
86
+ cancel: 0,
87
+ running: 0,
88
+ awaiting: 0
89
+ },
90
+ version: 1
91
+ });
92
+ }
93
+ }
57
94
  }
58
- case "redis":
59
- throw new Error("Redis store adapter not registered. Install @nvent/adapter-store-redis and add it to your nuxt.config modules.");
60
- case "postgres":
61
- throw new Error("Postgres store adapter not yet implemented");
62
- default:
63
- throw new Error(`Unknown store adapter type: ${type}`);
95
+ } catch (err) {
96
+ console.warn("[factory] Failed to initialize flow index:", err?.message);
64
97
  }
98
+ return adapter;
65
99
  }
66
100
  async function createQueueAdapter(config) {
67
101
  const type = config.adapter || "file";
@@ -86,7 +120,7 @@ async function createQueueAdapter(config) {
86
120
  case "redis":
87
121
  throw new Error("Redis queue adapter not registered. Install @nvent/adapter-queue-redis and add it to your nuxt.config modules.");
88
122
  case "postgres":
89
- throw new Error("Postgres queue adapter (PGBoss) not yet implemented");
123
+ throw new Error("Postgres queue adapter not registered. Install @nvent/adapter-queue-postgres and add it to your nuxt.config modules.");
90
124
  default:
91
125
  throw new Error(`Unknown queue adapter type: ${type}`);
92
126
  }
@@ -2,66 +2,121 @@
2
2
  * Store Adapter Interface
3
3
  *
4
4
  * Three-tier storage system:
5
- * 1. Event Stream - Append-only event log (replaces EventStore)
6
- * 2. Document Store - Generic document storage (for flow wiring, triggers, metadata)
5
+ * 1. Event Stream - Append-only event log
6
+ * 2. Sorted Index - Time-ordered metadata storage
7
7
  * 3. Key-Value Store - Fast lookups (for state, caching)
8
+ *
9
+ * ## Critical Implementation Requirements
10
+ *
11
+ * ### 1. Index Operations - add() vs update()
12
+ *
13
+ * **index.add()** - MUST completely REPLACE metadata when entry exists:
14
+ * ```typescript
15
+ * // First call
16
+ * await index.add('flows', 'my-flow', 123, { name: 'Flow', stats: {...} })
17
+ * // Second call - REPLACES entire metadata
18
+ * await index.add('flows', 'my-flow', 456, { lastRunAt: 789 })
19
+ * // Result: { lastRunAt: 789 } ← stats are LOST!
20
+ * ```
21
+ *
22
+ * **index.update()** - MUST perform DEEP MERGE of metadata:
23
+ * ```typescript
24
+ * // Initial state: { status: 'running', emittedEvents: { test: { completed: 1 } } }
25
+ * await index.update('runs', 'run-id', { emittedEvents: { another: { fired: 2 } } })
26
+ * // Result: { status: 'running', emittedEvents: { test: { completed: 1 }, another: { fired: 2 } } }
27
+ * ```
28
+ *
29
+ * ⚠️ **CRITICAL**: update() must perform DEEP merge at ALL nesting levels, not just top-level!
30
+ * - PostgreSQL `||` operator: Only shallow merge (top-level keys)
31
+ * - Redis HSET loop: Field-level merge (simulates deep merge for flat structures)
32
+ * - Memory defu(): True deep merge
33
+ *
34
+ * ### 2. Nested Metadata Structure
35
+ *
36
+ * Flow orchestration stores deeply nested metadata:
37
+ * ```typescript
38
+ * {
39
+ * emittedEvents: {
40
+ * 'step1': {
41
+ * 'completed': 1234567890,
42
+ * 'custom_event': 1234567891
43
+ * },
44
+ * 'step2': {
45
+ * 'completed': 1234567892
46
+ * }
47
+ * },
48
+ * awaitingSteps: {
49
+ * 'step_name': {
50
+ * status: 'awaiting',
51
+ * position: 'after',
52
+ * awaitType: 'event'
53
+ * }
54
+ * }
55
+ * }
56
+ * ```
57
+ *
58
+ * Multiple updates add to nested structures incrementally. If deep merge fails,
59
+ * flow orchestration will miss events and steps won't trigger.
60
+ *
61
+ * ### 3. Concurrent Updates
62
+ *
63
+ * Flow steps run in parallel and update metadata concurrently:
64
+ * - Multiple steps emit events simultaneously
65
+ * - Each emits triggers index.updateWithRetry() with partial metadata
66
+ * - Updates must NOT overwrite each other
67
+ * - Use optimistic locking (version field) + retries
68
+ *
69
+ * ### 4. Testing Deep Merge
70
+ *
71
+ * Test that your adapter correctly handles:
72
+ * ```typescript
73
+ * // Setup
74
+ * await index.add('test', 'id', 1, { a: { b: 1 }, c: 2 })
75
+ *
76
+ * // Update nested property
77
+ * await index.update('test', 'id', { a: { d: 3 } })
78
+ * const result = await index.get('test', 'id')
79
+ *
80
+ * // MUST preserve existing nested data
81
+ * expect(result.metadata).toEqual({ a: { b: 1, d: 3 }, c: 2 })
82
+ * // NOT: { a: { d: 3 }, c: 2 } ← b is lost!
83
+ * ```
84
+ *
8
85
  */
9
86
  export interface StoreAdapter {
10
87
  /**
11
88
  * Close/cleanup the adapter
12
89
  */
13
90
  close(): Promise<void>;
14
- /**
15
- * Append an event to a subject's event stream
16
- * @param subject - Event stream identifier (e.g., 'nq:flow:abc-123')
17
- * @param event - Event to append (id and ts will be auto-generated)
18
- * @returns The complete event record with generated id and timestamp
19
- */
20
- append(subject: string, event: Omit<EventRecord, 'id' | 'ts'>): Promise<EventRecord>;
21
- /**
22
- * Read events from a subject's event stream
23
- * @param subject - Event stream identifier
24
- * @param opts - Query options (filtering, pagination, etc.)
25
- * @returns Array of event records
26
- */
27
- read(subject: string, opts?: EventReadOptions): Promise<EventRecord[]>;
28
- /**
29
- * Subscribe to new events in a subject's event stream (optional, not all adapters support this)
30
- * @param subject - Event stream identifier (supports wildcards if adapter allows)
31
- * @param onEvent - Callback for new events
32
- * @returns Subscription handle for unsubscribing
33
- */
34
- subscribe?(subject: string, onEvent: (event: EventRecord) => void): Promise<EventSubscription>;
35
- /**
36
- * Save a document to a collection
37
- * @param collection - Collection name (e.g., 'flow-wiring', 'triggers', 'flow-metadata')
38
- * @param id - Document ID
39
- * @param doc - Document data
40
- */
41
- save(collection: string, id: string, doc: Record<string, any>): Promise<void>;
42
- /**
43
- * Get a document from a collection
44
- * @param collection - Collection name
45
- * @param id - Document ID
46
- * @returns Document or null if not found
47
- */
48
- get(collection: string, id: string): Promise<Record<string, any> | null>;
49
- /**
50
- * List documents in a collection (optional, not all adapters may support complex queries)
51
- * @param collection - Collection name
52
- * @param opts - Query options (filtering, pagination, sorting)
53
- * @returns Array of documents with their IDs
54
- */
55
- list?(collection: string, opts?: ListOptions): Promise<Array<{
56
- id: string;
57
- doc: any;
58
- }>>;
59
- /**
60
- * Delete a document from a collection
61
- * @param collection - Collection name
62
- * @param id - Document ID
63
- */
64
- delete(collection: string, id: string): Promise<void>;
91
+ stream: {
92
+ /**
93
+ * Append an event to a subject's event stream
94
+ * @param subject - Event stream identifier (e.g., 'nq:flow:abc-123')
95
+ * @param event - Event to append (id and ts will be auto-generated)
96
+ * @returns The complete event record with generated id and timestamp
97
+ */
98
+ append(subject: string, event: Omit<EventRecord, 'id' | 'ts'>): Promise<EventRecord>;
99
+ /**
100
+ * Read events from a subject's event stream
101
+ * @param subject - Event stream identifier
102
+ * @param opts - Query options (filtering, pagination, etc.)
103
+ * @returns Array of event records
104
+ */
105
+ read(subject: string, opts?: EventReadOptions): Promise<EventRecord[]>;
106
+ /**
107
+ * Subscribe to new events in a subject's event stream (optional, not all adapters support this)
108
+ * @param subject - Event stream identifier (supports wildcards if adapter allows)
109
+ * @param onEvent - Callback for new events
110
+ * @returns Subscription handle for unsubscribing
111
+ */
112
+ subscribe?(subject: string, onEvent: (event: EventRecord) => void): Promise<EventSubscription>;
113
+ /**
114
+ * Delete an entire event stream
115
+ * @param subject - Event stream identifier
116
+ * @returns True if stream was deleted, false if not found
117
+ */
118
+ delete?(subject: string): Promise<boolean>;
119
+ };
65
120
  kv: {
66
121
  /**
67
122
  * Get a value by key
@@ -89,66 +144,75 @@ export interface StoreAdapter {
89
144
  */
90
145
  increment?(key: string, by?: number): Promise<number>;
91
146
  };
92
- /**
93
- * Add entry to a sorted index (optional, for efficient time-ordered listings)
94
- * @param key - Index key (e.g., 'nq:flows:flowName')
95
- * @param id - Entry ID
96
- * @param score - Sort score (typically timestamp)
97
- * @param metadata - Optional metadata to store with entry
98
- */
99
- indexAdd?(key: string, id: string, score: number, metadata?: Record<string, any>): Promise<void>;
100
- /**
101
- * Get a single entry from a sorted index
102
- * @param key - Index key
103
- * @param id - Entry ID
104
- * @returns Entry with score and metadata, or null if not found
105
- */
106
- indexGet?(key: string, id: string): Promise<{
107
- id: string;
108
- score: number;
109
- metadata?: any;
110
- } | null>;
111
- /**
112
- * Read entries from a sorted index (ordered by score descending)
113
- * @param key - Index key
114
- * @param opts - Pagination options
115
- * @param opts.offset - Number of entries to skip
116
- * @param opts.limit - Maximum number of entries to return
117
- * @returns Array of entries with scores and metadata
118
- */
119
- indexRead?(key: string, opts?: {
120
- offset?: number;
121
- limit?: number;
122
- }): Promise<Array<{
123
- id: string;
124
- score: number;
125
- metadata?: any;
126
- }>>;
127
- /**
128
- * Update metadata for an entry in a sorted index
129
- * @param key - Index key
130
- * @param id - Entry ID
131
- * @param metadata - Metadata to update
132
- * @returns True if update succeeded, false if version conflict
133
- */
134
- indexUpdate?(key: string, id: string, metadata: Record<string, any>): Promise<boolean>;
135
- /**
136
- * Update with automatic retries on version conflicts
137
- * @param key - Index key
138
- * @param id - Entry ID
139
- * @param metadata - Metadata to update
140
- * @param maxRetries - Maximum retry attempts (default: 3)
141
- */
142
- indexUpdateWithRetry?(key: string, id: string, metadata: Record<string, any>, maxRetries?: number): Promise<void>;
143
- /**
144
- * Atomic increment of a metadata field in an index entry
145
- * @param key - Index key
146
- * @param id - Entry ID
147
- * @param field - Field name to increment
148
- * @param increment - Amount to increment by (default: 1)
149
- * @returns New value after increment
150
- */
151
- indexIncrement?(key: string, id: string, field: string, increment?: number): Promise<number>;
147
+ index: {
148
+ /**
149
+ * Add entry to a sorted index
150
+ * @param key - Index key (e.g., 'nq:flows:flowName')
151
+ * @param id - Entry ID
152
+ * @param score - Sort score (typically timestamp)
153
+ * @param metadata - Optional metadata to store with entry
154
+ */
155
+ add(key: string, id: string, score: number, metadata?: Record<string, any>): Promise<void>;
156
+ /**
157
+ * Get a single entry from a sorted index
158
+ * @param key - Index key
159
+ * @param id - Entry ID
160
+ * @returns Entry with score and metadata, or null if not found
161
+ */
162
+ get(key: string, id: string): Promise<{
163
+ id: string;
164
+ score: number;
165
+ metadata?: any;
166
+ } | null>;
167
+ /**
168
+ * Read entries from a sorted index (ordered by score descending)
169
+ * @param key - Index key
170
+ * @param opts - Pagination options
171
+ * @param opts.offset - Number of entries to skip
172
+ * @param opts.limit - Maximum number of entries to return
173
+ * @returns Array of entries with scores and metadata
174
+ */
175
+ read(key: string, opts?: {
176
+ offset?: number;
177
+ limit?: number;
178
+ }): Promise<Array<{
179
+ id: string;
180
+ score: number;
181
+ metadata?: any;
182
+ }>>;
183
+ /**
184
+ * Update metadata for an entry in a sorted index
185
+ * @param key - Index key
186
+ * @param id - Entry ID
187
+ * @param metadata - Metadata to update
188
+ * @returns True if update succeeded, false if version conflict
189
+ */
190
+ update(key: string, id: string, metadata: Record<string, any>): Promise<boolean>;
191
+ /**
192
+ * Update with automatic retries on version conflicts
193
+ * @param key - Index key
194
+ * @param id - Entry ID
195
+ * @param metadata - Metadata to update
196
+ * @param maxRetries - Maximum retry attempts (default: 3)
197
+ */
198
+ updateWithRetry(key: string, id: string, metadata: Record<string, any>, maxRetries?: number): Promise<void>;
199
+ /**
200
+ * Atomic increment of a metadata field in an index entry
201
+ * @param key - Index key
202
+ * @param id - Entry ID
203
+ * @param field - Field name to increment
204
+ * @param increment - Amount to increment by (default: 1)
205
+ * @returns New value after increment
206
+ */
207
+ increment(key: string, id: string, field: string, increment?: number): Promise<number>;
208
+ /**
209
+ * Delete an entry from a sorted index
210
+ * @param key - Index key
211
+ * @param id - Entry ID
212
+ * @returns True if entry was deleted, false if not found
213
+ */
214
+ delete(key: string, id: string): Promise<boolean>;
215
+ };
152
216
  }
153
217
  /**
154
218
  * Event record in the event stream
@@ -1,12 +1,12 @@
1
1
  import type { ModuleOptions, ModuleConfig } from './types.js';
2
2
  /**
3
- * Merge and normalize module options with defaults (v0.4.1).
3
+ * Merge and normalize module options with defaults.
4
4
  * Applies connection fallback: adapter-specific connections override connections.redis/postgres.
5
5
  * Only includes connection defaults for adapters that are actually used.
6
6
  */
7
7
  export declare function normalizeModuleOptions(options: ModuleOptions): Required<ModuleOptions>;
8
8
  /**
9
- * Convert normalized module options to runtime config format (v0.4.1).
9
+ * Convert normalized module options to runtime config format.
10
10
  */
11
11
  export declare function toRuntimeConfig(normalizedOptions: Required<ModuleOptions>): ModuleConfig;
12
12
  /**
@@ -7,7 +7,8 @@ export function normalizeModuleOptions(options) {
7
7
  connections: {},
8
8
  queue: {
9
9
  adapter: "file",
10
- prefix: "nq",
10
+ prefix: "nvent",
11
+ schema: "nvent_queue",
11
12
  defaultJobOptions: {},
12
13
  worker: {
13
14
  concurrency: 2,
@@ -17,11 +18,12 @@ export function normalizeModuleOptions(options) {
17
18
  },
18
19
  stream: {
19
20
  adapter: "memory",
20
- prefix: "nq"
21
+ prefix: "nvent"
21
22
  },
22
23
  store: {
23
24
  adapter: "file",
24
- prefix: "nq",
25
+ prefix: "nvent",
26
+ schema: "nvent_store",
25
27
  state: {
26
28
  autoScope: "always",
27
29
  cleanup: {
@@ -35,7 +37,7 @@ export function normalizeModuleOptions(options) {
35
37
  metadataTTL: 2592e3
36
38
  // 30 days
37
39
  },
38
- flows: {
40
+ flow: {
39
41
  stallDetection: {
40
42
  enabled: true,
41
43
  stallTimeout: 30 * 60 * 1e3,
@@ -44,6 +46,11 @@ export function normalizeModuleOptions(options) {
44
46
  // 15 minutes
45
47
  enablePeriodicCheck: true
46
48
  }
49
+ },
50
+ webhooks: {
51
+ // baseUrl will be determined at runtime from Nitro context
52
+ // Users can override via NUXT_PUBLIC_SITE_URL or explicit config
53
+ baseUrl: process.env.NUXT_PUBLIC_SITE_URL || void 0
47
54
  }
48
55
  };
49
56
  const normalized = defu(options, defaults);
@@ -83,7 +90,7 @@ export function normalizeModuleOptions(options) {
83
90
  }
84
91
  if (neededConnections.has("postgres") && !normalized.connections.postgres) {
85
92
  normalized.connections.postgres = {
86
- connectionString: process.env.DATABASE_URL || "postgresql://localhost:5432/nuxt_queue"
93
+ connectionString: process.env.DATABASE_URL || "postgresql://localhost:5432/nvent"
87
94
  };
88
95
  }
89
96
  if (neededConnections.has("rabbitmq") && !normalized.connections.rabbitmq) {
@@ -146,7 +153,8 @@ export function toRuntimeConfig(normalizedOptions) {
146
153
  stream: normalizedOptions.stream,
147
154
  store: normalizedOptions.store,
148
155
  connections: normalizedOptions.connections,
149
- flows: normalizedOptions.flows
156
+ flow: normalizedOptions.flow,
157
+ webhooks: normalizedOptions.webhooks
150
158
  };
151
159
  }
152
160
  export function getRedisStorageConfig(normalizedOptions) {
@@ -133,6 +133,12 @@ export interface QueueConfig {
133
133
  * Queue-specific options (BullMQ/PGBoss configuration)
134
134
  */
135
135
  prefix?: string;
136
+ /**
137
+ * PostgreSQL schema name for pg-boss tables
138
+ * Only applies when adapter is 'postgres'
139
+ * @default 'pgboss'
140
+ */
141
+ schema?: string;
136
142
  defaultJobOptions?: {
137
143
  attempts?: number;
138
144
  backoff?: number | {
@@ -189,6 +195,18 @@ export interface StreamConfig {
189
195
  retryAttempts?: number;
190
196
  retryDelay?: number;
191
197
  }
198
+ /**
199
+ * Webhooks configuration
200
+ */
201
+ export interface WebhooksConfig {
202
+ /**
203
+ * Base URL for webhook endpoints
204
+ * Auto-detected from Nitro context in development
205
+ * Set explicitly for production or to override auto-detection
206
+ * @default Auto-detected from NUXT_PUBLIC_SITE_URL, NITRO_URL, or dev server (http://localhost:3000 fallback)
207
+ */
208
+ baseUrl?: string;
209
+ }
192
210
  /**
193
211
  * Flow configuration
194
212
  */
@@ -281,6 +299,12 @@ export interface StoreConfig {
281
299
  * @default 'nq'
282
300
  */
283
301
  prefix?: string;
302
+ /**
303
+ * PostgreSQL schema name for store tables
304
+ * Only applies when adapter is 'postgres'
305
+ * @default 'public'
306
+ */
307
+ schema?: string;
284
308
  /**
285
309
  * State management configuration (KV store behavior)
286
310
  */
@@ -345,7 +369,12 @@ export interface ModuleOptions {
345
369
  * Flow-specific configuration
346
370
  * @since v0.4.1
347
371
  */
348
- flows?: FlowConfig;
372
+ flow?: FlowConfig;
373
+ /**
374
+ * Webhooks configuration
375
+ * @since v0.5.0
376
+ */
377
+ webhooks?: WebhooksConfig;
349
378
  /**
350
379
  * Shared connection configurations
351
380
  * Used as fallback if adapters don't specify their own connections
@@ -361,7 +390,8 @@ export interface ModuleConfig {
361
390
  queue: Required<QueueConfig>;
362
391
  stream: Required<StreamConfig>;
363
392
  store: Required<StoreConfig>;
364
- flows: Required<FlowConfig>;
393
+ flow: Required<FlowConfig>;
394
+ webhooks: Required<WebhooksConfig>;
365
395
  connections: Required<ConnectionsConfig>;
366
396
  rootDir?: string;
367
397
  }
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from 'node:events';
2
- import type { EventRecord } from '../types.js';
2
+ import type { EventRecord } from './types.js';
3
3
  type Handler = (e: EventRecord) => void;
4
4
  declare global {
5
5
  var __nq_bus_emitter: EventEmitter | undefined;
@@ -15,7 +15,7 @@ export interface PublishPayload<T = any> {
15
15
  attempt?: number;
16
16
  data?: T;
17
17
  }
18
- export type EventType = 'flow.start' | 'flow.completed' | 'flow.failed' | 'flow.cancel' | 'step.started' | 'step.completed' | 'step.failed' | 'step.retry' | 'log' | 'emit' | 'state' | 'flow.stalled';
18
+ export type EventType = 'flow.start' | 'flow.completed' | 'flow.failed' | 'flow.cancel' | 'step.started' | 'step.completed' | 'step.failed' | 'step.retry' | 'log' | 'emit' | 'state' | 'flow.stalled' | 'trigger.fired' | 'trigger.registered' | 'await.registered' | 'await.resolved' | 'await.timeout';
19
19
  export interface BaseEvent {
20
20
  id?: string;
21
21
  ts?: string;
@@ -113,4 +113,33 @@ export interface StateEvent extends StepEvent {
113
113
  value?: any;
114
114
  };
115
115
  }
116
- export type FlowEvent = FlowStartEvent | FlowCompletedEvent | FlowFailedEvent | FlowCancelEvent | FlowStalledEvent | StepStartedEvent | StepCompletedEvent | StepFailedEvent | StepRetryEvent | LogEvent | EmitEvent | StateEvent;
116
+ export interface TriggerFiredEvent extends BaseEvent {
117
+ type: 'trigger.fired';
118
+ triggerName: string;
119
+ data: any;
120
+ }
121
+ export interface TriggerRegisteredEvent {
122
+ type: 'trigger.registered';
123
+ triggerName: string;
124
+ triggerType: 'event' | 'webhook' | 'schedule' | 'manual';
125
+ scope: 'flow' | 'run';
126
+ }
127
+ export interface AwaitRegisteredEvent extends BaseEvent {
128
+ type: 'await.registered';
129
+ stepName: string;
130
+ awaitType: 'webhook' | 'event' | 'schedule' | 'time';
131
+ position: 'before' | 'after';
132
+ config: any;
133
+ }
134
+ export interface AwaitResolvedEvent extends BaseEvent {
135
+ type: 'await.resolved';
136
+ stepName: string;
137
+ triggerData: any;
138
+ position: 'before' | 'after';
139
+ }
140
+ export interface AwaitTimeoutEvent extends BaseEvent {
141
+ type: 'await.timeout';
142
+ stepName: string;
143
+ action: 'fail' | 'continue' | 'retry';
144
+ }
145
+ export type FlowEvent = FlowStartEvent | FlowCompletedEvent | FlowFailedEvent | FlowCancelEvent | FlowStalledEvent | StepStartedEvent | StepCompletedEvent | StepFailedEvent | StepRetryEvent | LogEvent | EmitEvent | StateEvent | TriggerFiredEvent | TriggerRegisteredEvent | AwaitRegisteredEvent | AwaitResolvedEvent | AwaitTimeoutEvent;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Schedule or update a schedule trigger in the scheduler
3
+ */
4
+ export declare function scheduleTrigger(triggerName: string, scheduleConfig: any, triggerStatus?: string): Promise<void>;
5
+ /**
6
+ * Unschedule a schedule trigger from the scheduler
7
+ */
8
+ export declare function unscheduleTrigger(triggerName: string): Promise<void>;