@motiadev/core 0.2.1-beta.74 → 0.2.1-beta.75

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 (32) hide show
  1. package/README.md +4 -22
  2. package/dist/index.d.ts +2 -3
  3. package/dist/index.js +1 -4
  4. package/dist/src/get-step-config.d.ts +2 -2
  5. package/dist/src/locked-data.d.ts +9 -8
  6. package/dist/src/locked-data.js +15 -10
  7. package/dist/src/logger-factory.d.ts +2 -2
  8. package/dist/src/logger.d.ts +2 -2
  9. package/dist/src/process-communication/process-manager.js +1 -1
  10. package/dist/src/python/python-runner.py +0 -48
  11. package/dist/src/server.d.ts +2 -2
  12. package/dist/src/server.js +53 -46
  13. package/dist/src/streams/adapters/file-stream-adapter.d.ts +20 -0
  14. package/dist/src/streams/adapters/file-stream-adapter.js +124 -0
  15. package/dist/src/streams/adapters/memory-stream-adapter.d.ts +12 -0
  16. package/dist/src/streams/adapters/memory-stream-adapter.js +39 -0
  17. package/dist/src/streams/adapters/stream-adapter.d.ts +11 -0
  18. package/dist/src/streams/adapters/stream-adapter.js +11 -0
  19. package/dist/src/streams/api-endpoints.js +2 -2
  20. package/dist/src/streams/flows-stream.d.ts +2 -2
  21. package/dist/src/streams/flows-stream.js +2 -2
  22. package/dist/src/streams/logs-stream.d.ts +2 -2
  23. package/dist/src/streams/logs-stream.js +2 -2
  24. package/dist/src/streams/stream-factory.d.ts +2 -0
  25. package/dist/src/streams/stream-factory.js +2 -0
  26. package/dist/src/types/generate-type-from-schema.js +5 -2
  27. package/dist/src/types/generate-types.js +2 -2
  28. package/dist/src/types/schema.types.d.ts +7 -2
  29. package/dist/src/types-stream.d.ts +8 -8
  30. package/package.json +1 -1
  31. package/dist/src/state-stream.d.ts +0 -19
  32. package/dist/src/state-stream.js +0 -28
package/README.md CHANGED
@@ -51,7 +51,7 @@ eventManager.subscribe({
51
51
  filePath: '/path/to/handler.ts',
52
52
  handler: (event) => {
53
53
  // Handle the event
54
- }
54
+ },
55
55
  })
56
56
 
57
57
  // Emit events
@@ -59,7 +59,7 @@ eventManager.emit({
59
59
  topic: 'user.created',
60
60
  data: { userId: '123' },
61
61
  traceId: 'trace-123',
62
- logger: logger
62
+ logger: logger,
63
63
  })
64
64
  ```
65
65
 
@@ -83,7 +83,7 @@ import { createStateAdapter } from '@motiadev/core'
83
83
  const stateAdapter = createStateAdapter({
84
84
  adapter: 'redis',
85
85
  host: 'localhost',
86
- port: 6379
86
+ port: 6379,
87
87
  })
88
88
 
89
89
  // Use state in your handlers
@@ -101,17 +101,6 @@ import { setupCronHandlers } from '@motiadev/core'
101
101
  const cronManager = setupCronHandlers(lockedData, eventManager, state, loggerFactory)
102
102
  ```
103
103
 
104
- ### Logging
105
-
106
- Use the built-in logging system:
107
-
108
- ```typescript
109
- import { globalLogger } from '@motiadev/core'
110
-
111
- globalLogger.info('Application started')
112
- globalLogger.error('Something went wrong', { error: err })
113
- ```
114
-
115
104
  ## Multi-language Support
116
105
 
117
106
  Motia supports writing step handlers in multiple languages:
@@ -127,16 +116,9 @@ Each language has its own runner that communicates with the core framework.
127
116
  The package exports TypeScript types for all components:
128
117
 
129
118
  ```typescript
130
- import {
131
- Event,
132
- FlowContext,
133
- ApiRouteConfig,
134
- EventConfig,
135
- CronConfig
136
- } from '@motiadev/core'
119
+ import { Event, FlowContext, ApiRouteConfig, EventConfig, CronConfig } from '@motiadev/core'
137
120
  ```
138
121
 
139
122
  ## License
140
123
 
141
124
  This package is part of the Motia framework and is licensed under the same terms.
142
- ```
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export * from './src/types';
2
2
  export { createServer, MotiaServer } from './src/server';
3
3
  export { createStepHandlers, MotiaEventManager } from './src/step-handlers';
4
4
  export { createEventManager } from './src/event-manager';
5
- export { globalLogger, Logger } from './src/logger';
5
+ export { Logger } from './src/logger';
6
6
  export { createStateAdapter } from './src/state/create-state-adapter';
7
7
  export { setupCronHandlers, CronManager } from './src/cron-handler';
8
8
  export { isApiStep, isCronStep, isEventStep, isNoopStep } from './src/guards';
@@ -10,6 +10,5 @@ export { LockedData } from './src/locked-data';
10
10
  export { getStepConfig, getStreamConfig } from './src/get-step-config';
11
11
  export { StateAdapter } from './src/state/state-adapter';
12
12
  export { createMermaidGenerator } from './src/mermaid-generator';
13
- export { StateStream } from './src/state-stream';
14
- export { StateStreamConfig, IStateStream } from './src/types-stream';
13
+ export { StreamConfig, MotiaStream } from './src/types-stream';
15
14
  export { getProjectIdentifier, getUserIdentifier, isAnalyticsEnabled, trackEvent } from './src/analytics/utils';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.trackEvent = exports.isAnalyticsEnabled = exports.getUserIdentifier = exports.getProjectIdentifier = exports.StateStream = exports.createMermaidGenerator = exports.getStreamConfig = exports.getStepConfig = exports.LockedData = exports.isNoopStep = exports.isEventStep = exports.isCronStep = exports.isApiStep = exports.setupCronHandlers = exports.createStateAdapter = exports.Logger = exports.globalLogger = exports.createEventManager = exports.createStepHandlers = exports.createServer = void 0;
17
+ exports.trackEvent = exports.isAnalyticsEnabled = exports.getUserIdentifier = exports.getProjectIdentifier = exports.createMermaidGenerator = exports.getStreamConfig = exports.getStepConfig = exports.LockedData = exports.isNoopStep = exports.isEventStep = exports.isCronStep = exports.isApiStep = exports.setupCronHandlers = exports.createStateAdapter = exports.Logger = exports.createEventManager = exports.createStepHandlers = exports.createServer = void 0;
18
18
  __exportStar(require("./src/types"), exports);
19
19
  var server_1 = require("./src/server");
20
20
  Object.defineProperty(exports, "createServer", { enumerable: true, get: function () { return server_1.createServer; } });
@@ -23,7 +23,6 @@ Object.defineProperty(exports, "createStepHandlers", { enumerable: true, get: fu
23
23
  var event_manager_1 = require("./src/event-manager");
24
24
  Object.defineProperty(exports, "createEventManager", { enumerable: true, get: function () { return event_manager_1.createEventManager; } });
25
25
  var logger_1 = require("./src/logger");
26
- Object.defineProperty(exports, "globalLogger", { enumerable: true, get: function () { return logger_1.globalLogger; } });
27
26
  Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return logger_1.Logger; } });
28
27
  var create_state_adapter_1 = require("./src/state/create-state-adapter");
29
28
  Object.defineProperty(exports, "createStateAdapter", { enumerable: true, get: function () { return create_state_adapter_1.createStateAdapter; } });
@@ -41,8 +40,6 @@ Object.defineProperty(exports, "getStepConfig", { enumerable: true, get: functio
41
40
  Object.defineProperty(exports, "getStreamConfig", { enumerable: true, get: function () { return get_step_config_1.getStreamConfig; } });
42
41
  var mermaid_generator_1 = require("./src/mermaid-generator");
43
42
  Object.defineProperty(exports, "createMermaidGenerator", { enumerable: true, get: function () { return mermaid_generator_1.createMermaidGenerator; } });
44
- var state_stream_1 = require("./src/state-stream");
45
- Object.defineProperty(exports, "StateStream", { enumerable: true, get: function () { return state_stream_1.StateStream; } });
46
43
  var utils_1 = require("./src/analytics/utils");
47
44
  Object.defineProperty(exports, "getProjectIdentifier", { enumerable: true, get: function () { return utils_1.getProjectIdentifier; } });
48
45
  Object.defineProperty(exports, "getUserIdentifier", { enumerable: true, get: function () { return utils_1.getUserIdentifier; } });
@@ -1,4 +1,4 @@
1
1
  import { StepConfig } from './types';
2
- import { StateStreamConfig } from './types-stream';
2
+ import { StreamConfig } from './types-stream';
3
3
  export declare const getStepConfig: (file: string) => Promise<StepConfig | null>;
4
- export declare const getStreamConfig: (file: string) => Promise<StateStreamConfig | null>;
4
+ export declare const getStreamConfig: (file: string) => Promise<StreamConfig | null>;
@@ -1,13 +1,14 @@
1
1
  import { Printer } from './printer';
2
- import { StateStreamFactory } from './state-stream';
3
- import { ApiRouteConfig, CronConfig, EventConfig, Flow, InternalStateManager, Step } from './types';
2
+ import { StreamFactory } from './streams/stream-factory';
3
+ import { ApiRouteConfig, CronConfig, EventConfig, Flow, Step } from './types';
4
4
  import { Stream } from './types-stream';
5
5
  type FlowEvent = 'flow-created' | 'flow-removed' | 'flow-updated';
6
6
  type StepEvent = 'step-created' | 'step-removed' | 'step-updated';
7
7
  type StreamEvent = 'stream-created' | 'stream-removed' | 'stream-updated';
8
- type StreamWrapper<TData> = (streamName: string, factory: StateStreamFactory<TData>) => StateStreamFactory<TData>;
8
+ type StreamWrapper<TData> = (streamName: string, factory: StreamFactory<TData>) => StreamFactory<TData>;
9
9
  export declare class LockedData {
10
10
  readonly baseDir: string;
11
+ private readonly streamAdapter;
11
12
  flows: Record<string, Flow>;
12
13
  activeSteps: Step[];
13
14
  devSteps: Step[];
@@ -17,11 +18,10 @@ export declare class LockedData {
17
18
  private stepHandlers;
18
19
  private streamHandlers;
19
20
  private streams;
20
- private state;
21
21
  private streamWrapper?;
22
- constructor(baseDir: string);
22
+ constructor(baseDir: string, streamAdapter?: 'file' | 'memory');
23
23
  disablePrinter(): void;
24
- applyStreamWrapper<TData>(state: InternalStateManager, streamWrapper: StreamWrapper<TData>): void;
24
+ applyStreamWrapper<TData>(streamWrapper: StreamWrapper<TData>): void;
25
25
  saveTypes(): void;
26
26
  on(event: FlowEvent, handler: (flowName: string) => void): void;
27
27
  onStep(event: StepEvent, handler: (step: Step) => void): void;
@@ -31,7 +31,7 @@ export declare class LockedData {
31
31
  cronSteps(): Step<CronConfig>[];
32
32
  pythonSteps(): Step[];
33
33
  tsSteps(): Step[];
34
- getStreams(): Record<string, StateStreamFactory<any>>;
34
+ getStreams(): Record<string, StreamFactory<any>>;
35
35
  listStreams(): Stream[];
36
36
  findStream(path: string): Stream | undefined;
37
37
  updateStep(oldStep: Step, newStep: Step, options?: {
@@ -46,7 +46,7 @@ export declare class LockedData {
46
46
  private createFactoryWrapper;
47
47
  createStream<TData>(baseStream: Omit<Stream, 'factory'>, options?: {
48
48
  disableTypeCreation?: boolean;
49
- }): StateStreamFactory<TData>;
49
+ }): StreamFactory<TData>;
50
50
  deleteStream(stream: Stream, options?: {
51
51
  disableTypeCreation?: boolean;
52
52
  }): void;
@@ -57,5 +57,6 @@ export declare class LockedData {
57
57
  private removeFlow;
58
58
  private onFlowUpdated;
59
59
  private isValidStep;
60
+ private createStreamAdapter;
60
61
  }
61
62
  export {};
@@ -8,13 +8,14 @@ const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const guards_1 = require("./guards");
10
10
  const printer_1 = require("./printer");
11
- const state_stream_1 = require("./state-stream");
12
11
  const step_validator_1 = require("./step-validator");
12
+ const file_stream_adapter_1 = require("./streams/adapters/file-stream-adapter");
13
+ const memory_stream_adapter_1 = require("./streams/adapters/memory-stream-adapter");
13
14
  const generate_types_1 = require("./types/generate-types");
14
15
  class LockedData {
15
- constructor(baseDir) {
16
+ constructor(baseDir, streamAdapter = 'file') {
16
17
  this.baseDir = baseDir;
17
- this.state = null;
18
+ this.streamAdapter = streamAdapter;
18
19
  this.flows = {};
19
20
  this.activeSteps = [];
20
21
  this.devSteps = [];
@@ -40,9 +41,8 @@ class LockedData {
40
41
  disablePrinter() {
41
42
  this.printer = new printer_1.NoPrinter(this.baseDir);
42
43
  }
43
- applyStreamWrapper(state, streamWrapper) {
44
+ applyStreamWrapper(streamWrapper) {
44
45
  this.streamWrapper = streamWrapper;
45
- this.state = state;
46
46
  }
47
47
  saveTypes() {
48
48
  const types = (0, generate_types_1.generateTypesFromSteps)(this.activeSteps, this.printer);
@@ -76,7 +76,6 @@ class LockedData {
76
76
  }
77
77
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
78
  getStreams() {
79
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
80
79
  const streams = {};
81
80
  for (const [key, value] of Object.entries(this.streams)) {
82
81
  streams[key] = value.factory;
@@ -200,8 +199,8 @@ class LockedData {
200
199
  const stream = baseStream;
201
200
  this.streams[stream.config.name] = stream;
202
201
  this.streamHandlers['stream-created'].forEach((handler) => handler(stream));
203
- if (stream.config.baseConfig.storageType === 'state') {
204
- stream.factory = this.createFactoryWrapper(stream, () => new state_stream_1.InternalStateStream(this.state));
202
+ if (stream.config.baseConfig.storageType === 'default') {
203
+ stream.factory = this.createFactoryWrapper(stream, () => this.createStreamAdapter(stream.config.name));
205
204
  }
206
205
  else {
207
206
  stream.factory = this.createFactoryWrapper(stream, stream.config.baseConfig.factory);
@@ -232,8 +231,8 @@ class LockedData {
232
231
  if (oldStream.config.name !== stream.config.name) {
233
232
  delete this.streams[oldStream.config.name];
234
233
  }
235
- if (stream.config.baseConfig.storageType === 'state') {
236
- stream.factory = this.createFactoryWrapper(stream, () => new state_stream_1.InternalStateStream(this.state));
234
+ if (stream.config.baseConfig.storageType === 'default') {
235
+ stream.factory = this.createFactoryWrapper(stream, () => this.createStreamAdapter(stream.config.name));
237
236
  }
238
237
  else {
239
238
  stream.factory = this.createFactoryWrapper(stream, stream.config.baseConfig.factory);
@@ -269,5 +268,11 @@ class LockedData {
269
268
  }
270
269
  return validationResult.success;
271
270
  }
271
+ createStreamAdapter(streamName) {
272
+ if (this.streamAdapter === 'file') {
273
+ return new file_stream_adapter_1.FileStreamAdapter(this.baseDir, streamName);
274
+ }
275
+ return new memory_stream_adapter_1.MemoryStreamAdapter();
276
+ }
272
277
  }
273
278
  exports.LockedData = LockedData;
@@ -1,5 +1,5 @@
1
1
  import { Logger } from './logger';
2
- import { StateStream } from './state-stream';
2
+ import { StreamAdapter } from './streams/adapters/stream-adapter';
3
3
  import { Log } from './streams/logs-stream';
4
4
  type CreateLogger = {
5
5
  traceId: string;
@@ -9,7 +9,7 @@ type CreateLogger = {
9
9
  export declare class LoggerFactory {
10
10
  private readonly isVerbose;
11
11
  private readonly logStream;
12
- constructor(isVerbose: boolean, logStream: StateStream<Log>);
12
+ constructor(isVerbose: boolean, logStream: StreamAdapter<Log>);
13
13
  create({ stepName, traceId, flows }: CreateLogger): Logger;
14
14
  }
15
15
  export {};
@@ -1,5 +1,5 @@
1
1
  import { Log } from './streams/logs-stream';
2
- import { StateStream } from './state-stream';
2
+ import { StreamAdapter } from './streams/adapters/stream-adapter';
3
3
  export declare class BaseLogger {
4
4
  readonly isVerbose: boolean;
5
5
  private readonly meta;
@@ -18,7 +18,7 @@ export declare class Logger extends BaseLogger {
18
18
  private readonly step;
19
19
  private readonly logStream?;
20
20
  private emitLog;
21
- constructor(traceId: string, flows: string[] | undefined, step: string, isVerbose: boolean, logStream?: StateStream<Log> | undefined);
21
+ constructor(traceId: string, flows: string[] | undefined, step: string, isVerbose: boolean, logStream?: StreamAdapter<Log> | undefined);
22
22
  child(meta?: Record<string, unknown>): this;
23
23
  log(message: any): void;
24
24
  info: (message: string, args?: unknown) => void;
@@ -68,7 +68,7 @@ class ProcessManager {
68
68
  }
69
69
  kill() {
70
70
  if (this.child) {
71
- this.child.kill();
71
+ this.child.kill('SIGKILL');
72
72
  }
73
73
  }
74
74
  close() {
@@ -8,7 +8,6 @@ from typing import Optional, Any, Callable, List, Dict
8
8
  from rpc import RpcSender
9
9
  from type_definitions import FlowConfig, ApiResponse
10
10
  from context import Context
11
- from validation import validate_with_jsonschema
12
11
  from middleware import compose_middleware
13
12
  from rpc_stream_manager import RpcStreamManager
14
13
  from dot_dict import DotDict
@@ -21,42 +20,6 @@ def parse_args(arg: str) -> Dict:
21
20
  print('Error parsing args:', arg)
22
21
  return arg
23
22
 
24
- async def validate_handler_input(
25
- module: Any,
26
- args: Dict,
27
- context: Context,
28
- is_api_handler: bool
29
- ) -> Optional[ApiResponse]:
30
- """Validate handler input based on module configuration"""
31
- if not hasattr(args, "contextInFirstArg") or hasattr(module, "config"):
32
- return None
33
-
34
- config: FlowConfig = module.config
35
- input_data = args.get("data")
36
-
37
- if is_api_handler and hasattr(input_data, "body") and hasattr(config, "bodySchema"):
38
- body = input_data.get("body", {})
39
- body_schema = config.get("bodySchema", {})
40
- validation_result = validate_with_jsonschema(body, body_schema)
41
-
42
- if not validation_result["success"]:
43
- return ApiResponse(
44
- status=400,
45
- body={"message": f'Input validation error: {validation_result["error"]}'}
46
- )
47
- input_data.body = validation_result['data']
48
-
49
- elif not is_api_handler and config.input is not None:
50
- validation_result = validate_with_jsonschema(input_data, config.get("input", {}))
51
-
52
- if not validation_result["success"]:
53
- context.logger.info(f'Input Validation Error: {validation_result["error"]}', validation_result['details'])
54
- return None
55
-
56
- input_data = validation_result["data"]
57
-
58
- return None
59
-
60
23
  async def run_python_module(file_path: str, rpc: RpcSender, args: Dict) -> None:
61
24
  """Execute a Python module with the given arguments"""
62
25
  try:
@@ -94,12 +57,6 @@ async def run_python_module(file_path: str, rpc: RpcSender, args: Dict) -> None:
94
57
 
95
58
  context = Context(trace_id, flows, rpc, streams)
96
59
 
97
- validation_result = await validate_handler_input(module, args, context, is_api_handler)
98
- if validation_result:
99
- await rpc.send('result', validation_result)
100
- return
101
-
102
-
103
60
  middlewares: List[Callable] = config.get("middleware", [])
104
61
  composed_middleware = compose_middleware(*middlewares)
105
62
 
@@ -111,11 +68,6 @@ async def run_python_module(file_path: str, rpc: RpcSender, args: Dict) -> None:
111
68
 
112
69
  result = await composed_middleware(data, context, handler_fn)
113
70
 
114
- if not is_api_handler:
115
- pending = asyncio.all_tasks() - {asyncio.current_task()}
116
- if pending:
117
- await asyncio.gather(*pending)
118
-
119
71
  if result:
120
72
  await rpc.send('result', result)
121
73
 
@@ -1,9 +1,9 @@
1
- import { CronManager } from './cron-handler';
2
1
  import { Express } from 'express';
3
2
  import http from 'http';
4
3
  import { Server as WsServer } from 'ws';
5
- import { ApiRouteConfig, EventManager, InternalStateManager, Step } from './types';
4
+ import { CronManager } from './cron-handler';
6
5
  import { LockedData } from './locked-data';
6
+ import { ApiRouteConfig, EventManager, InternalStateManager, Step } from './types';
7
7
  export type MotiaServer = {
8
8
  app: Express;
9
9
  server: http.Server;
@@ -4,24 +4,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createServer = void 0;
7
- const cron_handler_1 = require("./cron-handler");
8
7
  const body_parser_1 = __importDefault(require("body-parser"));
8
+ const cors_1 = __importDefault(require("cors"));
9
9
  const express_1 = __importDefault(require("express"));
10
10
  const http_1 = __importDefault(require("http"));
11
- const cors_1 = __importDefault(require("cors"));
11
+ const analytics_endpoint_1 = require("./analytics-endpoint");
12
+ const utils_1 = require("./analytics/utils");
13
+ const call_step_file_1 = require("./call-step-file");
14
+ const cron_handler_1 = require("./cron-handler");
15
+ const flows_config_endpoint_1 = require("./flows-config-endpoint");
12
16
  const flows_endpoint_1 = require("./flows-endpoint");
17
+ const generate_trace_id_1 = require("./generate-trace-id");
13
18
  const guards_1 = require("./guards");
14
19
  const logger_1 = require("./logger");
15
- const steps_1 = require("./steps");
16
- const call_step_file_1 = require("./call-step-file");
17
20
  const logger_factory_1 = require("./logger-factory");
18
- const generate_trace_id_1 = require("./generate-trace-id");
19
- const flows_config_endpoint_1 = require("./flows-config-endpoint");
20
- const api_endpoints_1 = require("./streams/api-endpoints");
21
21
  const socket_server_1 = require("./socket-server");
22
+ const steps_1 = require("./steps");
23
+ const api_endpoints_1 = require("./streams/api-endpoints");
22
24
  const logs_stream_1 = require("./streams/logs-stream");
23
- const analytics_endpoint_1 = require("./analytics-endpoint");
24
- const utils_1 = require("./analytics/utils");
25
25
  const createServer = async (lockedData, eventManager, state, config) => {
26
26
  const printer = lockedData.printer;
27
27
  const app = (0, express_1.default)();
@@ -47,46 +47,52 @@ const createServer = async (lockedData, eventManager, state, config) => {
47
47
  }
48
48
  },
49
49
  });
50
- lockedData.applyStreamWrapper(state, (streamName, stream) => {
50
+ lockedData.applyStreamWrapper((streamName, stream) => {
51
51
  return () => {
52
- const suuper = stream();
52
+ const main = stream();
53
53
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
- const wrapObject = (groupId, id, object) => ({
55
- ...object,
56
- __motia: { type: 'state-stream', streamName, groupId, id },
57
- });
58
- const wrapper = {
59
- ...suuper,
60
- async send(channel, event) {
61
- pushEvent({ streamName, ...channel, event: { type: 'event', event } });
62
- },
63
- async get(groupId, id) {
64
- const result = await suuper.get.apply(wrapper, [groupId, id]);
65
- return wrapObject(groupId, id, result);
66
- },
67
- async set(groupId, id, data) {
68
- if (!data) {
69
- return null;
70
- }
71
- const exists = await suuper.get(groupId, id);
72
- const updated = await suuper.set.apply(wrapper, [groupId, id, data]);
73
- const result = updated ?? data;
74
- const wrappedResult = wrapObject(groupId, id, result);
75
- const type = exists ? 'update' : 'create';
76
- pushEvent({ streamName, groupId, id, event: { type, data: result } });
77
- return wrappedResult;
78
- },
79
- async delete(groupId, id) {
80
- const result = await suuper.delete.apply(wrapper, [groupId, id]);
81
- pushEvent({ streamName, groupId, id, event: { type: 'delete', data: result } });
82
- return wrapObject(groupId, id, result);
83
- },
84
- async getGroup(groupId) {
85
- const list = await suuper.getGroup.apply(wrapper, [groupId]);
86
- return list.map((object) => wrapObject(groupId, object.id, object));
87
- },
54
+ const wrapObject = (groupId, id, object) => {
55
+ if (!object) {
56
+ return null;
57
+ }
58
+ return {
59
+ ...object,
60
+ __motia: { type: 'state-stream', streamName, groupId, id },
61
+ };
62
+ };
63
+ const mainGetGroup = main.getGroup;
64
+ const mainGet = main.get;
65
+ const mainSet = main.set;
66
+ const mainDelete = main.delete;
67
+ main.send = async (channel, event) => {
68
+ pushEvent({ streamName, ...channel, event: { type: 'event', event } });
69
+ };
70
+ main.getGroup = async (groupId) => {
71
+ const result = await mainGetGroup.apply(main, [groupId]);
72
+ return result.map((object) => wrapObject(groupId, object.id, object));
73
+ };
74
+ main.get = async (groupId, id) => {
75
+ const result = await mainGet.apply(main, [groupId, id]);
76
+ return wrapObject(groupId, id, result);
77
+ };
78
+ main.set = async (groupId, id, data) => {
79
+ if (!data) {
80
+ return null;
81
+ }
82
+ const exists = await main.get(groupId, id);
83
+ const updated = await mainSet.apply(main, [groupId, id, data]);
84
+ const result = updated ?? data;
85
+ const wrappedResult = wrapObject(groupId, id, result);
86
+ const type = exists ? 'update' : 'create';
87
+ pushEvent({ streamName, groupId, id, event: { type, data: result } });
88
+ return wrappedResult;
89
+ };
90
+ main.delete = async (groupId, id) => {
91
+ const result = await mainDelete.apply(main, [groupId, id]);
92
+ pushEvent({ streamName, groupId, id, event: { type: 'delete', data: result } });
93
+ return wrapObject(groupId, id, result);
88
94
  };
89
- return wrapper;
95
+ return main;
90
96
  };
91
97
  });
92
98
  const logStream = lockedData.createStream({
@@ -127,6 +133,7 @@ const createServer = async (lockedData, eventManager, state, config) => {
127
133
  traceId,
128
134
  });
129
135
  if (!result) {
136
+ console.log('no result');
130
137
  res.status(500).json({ error: 'Internal server error' });
131
138
  return;
132
139
  }
@@ -0,0 +1,20 @@
1
+ import { StreamAdapter } from './stream-adapter';
2
+ export type FileAdapterConfig = {
3
+ filePath: string;
4
+ };
5
+ export declare class FileStreamAdapter<TData> extends StreamAdapter<TData> {
6
+ private readonly filePath;
7
+ private readonly streamsDir;
8
+ constructor(filePath: string, streamName: string);
9
+ init(): void;
10
+ getGroup<T>(groupId: string): Promise<T[]>;
11
+ get<T>(groupId: string, key: string): Promise<T | null>;
12
+ set<T>(groupId: string, id: string, value: T): Promise<T & {
13
+ id: string;
14
+ }>;
15
+ delete<T>(groupId: string, id: string): Promise<T | null>;
16
+ clear(groupId: string): Promise<void>;
17
+ private _makeKey;
18
+ private _readFile;
19
+ private _writeFile;
20
+ }
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.FileStreamAdapter = void 0;
40
+ const fs_1 = __importDefault(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const stream_adapter_1 = require("./stream-adapter");
43
+ class FileStreamAdapter extends stream_adapter_1.StreamAdapter {
44
+ constructor(filePath, streamName) {
45
+ super();
46
+ this.streamsDir = path.join(filePath, '.motia', 'streams');
47
+ this.filePath = path.join(this.streamsDir, `${streamName}.stream.json`);
48
+ }
49
+ init() {
50
+ try {
51
+ fs_1.default.realpathSync(this.streamsDir);
52
+ }
53
+ catch {
54
+ fs_1.default.mkdirSync(this.streamsDir, { recursive: true });
55
+ }
56
+ try {
57
+ fs_1.default.readFileSync(this.filePath, 'utf-8');
58
+ }
59
+ catch {
60
+ fs_1.default.writeFileSync(this.filePath, JSON.stringify({}), 'utf-8');
61
+ }
62
+ }
63
+ async getGroup(groupId) {
64
+ const data = this._readFile();
65
+ return Object.entries(data)
66
+ .filter(([key]) => key.startsWith(groupId))
67
+ .map(([, value]) => JSON.parse(value));
68
+ }
69
+ async get(groupId, key) {
70
+ const data = this._readFile();
71
+ const fullKey = this._makeKey(groupId, key);
72
+ return data[fullKey] ? JSON.parse(data[fullKey]) : null;
73
+ }
74
+ async set(groupId, id, value) {
75
+ const data = this._readFile();
76
+ const key = this._makeKey(groupId, id);
77
+ data[key] = JSON.stringify(value);
78
+ this._writeFile(data);
79
+ return { ...value, id };
80
+ }
81
+ async delete(groupId, id) {
82
+ const data = this._readFile();
83
+ const key = this._makeKey(groupId, id);
84
+ const value = await this.get(groupId, id);
85
+ if (value) {
86
+ delete data[key];
87
+ this._writeFile(data);
88
+ }
89
+ return value;
90
+ }
91
+ async clear(groupId) {
92
+ const data = this._readFile();
93
+ const pattern = this._makeKey(groupId, '');
94
+ for (const key in data) {
95
+ if (key.startsWith(pattern)) {
96
+ delete data[key];
97
+ }
98
+ }
99
+ this._writeFile(data);
100
+ }
101
+ _makeKey(groupId, id) {
102
+ return `${groupId}:${id}`;
103
+ }
104
+ _readFile() {
105
+ try {
106
+ const content = fs_1.default.readFileSync(this.filePath, 'utf-8');
107
+ return JSON.parse(content);
108
+ }
109
+ catch (error) {
110
+ this.init();
111
+ return {};
112
+ }
113
+ }
114
+ _writeFile(data) {
115
+ try {
116
+ fs_1.default.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');
117
+ }
118
+ catch (error) {
119
+ this.init();
120
+ fs_1.default.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');
121
+ }
122
+ }
123
+ }
124
+ exports.FileStreamAdapter = FileStreamAdapter;
@@ -0,0 +1,12 @@
1
+ import { StreamAdapter } from './stream-adapter';
2
+ export declare class MemoryStreamAdapter<TData> extends StreamAdapter<TData> {
3
+ private state;
4
+ init(): Promise<void>;
5
+ getGroup<T>(groupId: string): Promise<T[]>;
6
+ get<T>(groupId: string, id: string): Promise<T | null>;
7
+ set<T>(groupId: string, id: string, value: T): Promise<T & {
8
+ id: string;
9
+ }>;
10
+ delete<T>(groupId: string, id: string): Promise<T | null>;
11
+ private _makeKey;
12
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryStreamAdapter = void 0;
4
+ const stream_adapter_1 = require("./stream-adapter");
5
+ class MemoryStreamAdapter extends stream_adapter_1.StreamAdapter {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.state = {};
9
+ }
10
+ async init() {
11
+ this.state = {};
12
+ }
13
+ async getGroup(groupId) {
14
+ return Object.entries(this.state)
15
+ .filter(([key]) => key.startsWith(groupId))
16
+ .map(([, value]) => value);
17
+ }
18
+ async get(groupId, id) {
19
+ const key = this._makeKey(groupId, id);
20
+ return this.state[key] ? this.state[key] : null;
21
+ }
22
+ async set(groupId, id, value) {
23
+ const key = this._makeKey(groupId, id);
24
+ this.state[key] = value;
25
+ return { ...value, id };
26
+ }
27
+ async delete(groupId, id) {
28
+ const key = this._makeKey(groupId, id);
29
+ const value = await this.get(groupId, id);
30
+ if (value) {
31
+ delete this.state[key];
32
+ }
33
+ return value;
34
+ }
35
+ _makeKey(groupId, id) {
36
+ return `${groupId}:${id}`;
37
+ }
38
+ }
39
+ exports.MemoryStreamAdapter = MemoryStreamAdapter;
@@ -0,0 +1,11 @@
1
+ import { BaseStreamItem, MotiaStream, StateStreamEvent, StateStreamEventChannel } from '../../types-stream';
2
+ /**
3
+ * Interface for stream management adapters
4
+ */
5
+ export declare abstract class StreamAdapter<TData> implements MotiaStream<TData> {
6
+ abstract get(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
7
+ abstract set(groupId: string, id: string, data: TData): Promise<BaseStreamItem<TData>>;
8
+ abstract delete(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
9
+ abstract getGroup(groupId: string): Promise<BaseStreamItem<TData>[]>;
10
+ send<T>(channel: StateStreamEventChannel, event: StateStreamEvent<T>): Promise<void>;
11
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StreamAdapter = void 0;
4
+ /**
5
+ * Interface for stream management adapters
6
+ */
7
+ class StreamAdapter {
8
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
9
+ async send(channel, event) { }
10
+ }
11
+ exports.StreamAdapter = StreamAdapter;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.apiEndpoints = void 0;
4
4
  const guards_1 = require("../guards");
5
- const state_stream_1 = require("../state-stream");
5
+ const stream_adapter_1 = require("./adapters/stream-adapter");
6
6
  const mapEndpoint = (step) => {
7
7
  return {
8
8
  id: step.filePath,
@@ -14,7 +14,7 @@ const mapEndpoint = (step) => {
14
14
  bodySchema: step.config.bodySchema,
15
15
  };
16
16
  };
17
- class ApiEndpointsStream extends state_stream_1.StateStream {
17
+ class ApiEndpointsStream extends stream_adapter_1.StreamAdapter {
18
18
  constructor(lockedData) {
19
19
  super();
20
20
  this.lockedData = lockedData;
@@ -1,10 +1,10 @@
1
1
  import { LockedData } from '../locked-data';
2
- import { StateStream } from '../state-stream';
2
+ import { StreamAdapter } from './adapters/stream-adapter';
3
3
  export type Flow = {
4
4
  id: string;
5
5
  name: string;
6
6
  };
7
- export declare class FlowsStream extends StateStream<Flow> {
7
+ export declare class FlowsStream extends StreamAdapter<Flow> {
8
8
  private readonly lockedData;
9
9
  constructor(lockedData: LockedData);
10
10
  get(id: string): Promise<Flow | null>;
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FlowsStream = void 0;
4
- const state_stream_1 = require("../state-stream");
5
- class FlowsStream extends state_stream_1.StateStream {
4
+ const stream_adapter_1 = require("./adapters/stream-adapter");
5
+ class FlowsStream extends stream_adapter_1.StreamAdapter {
6
6
  constructor(lockedData) {
7
7
  super();
8
8
  this.lockedData = lockedData;
@@ -1,4 +1,4 @@
1
- import { StateStream } from '../state-stream';
1
+ import { StreamAdapter } from './adapters/stream-adapter';
2
2
  export type Log = {
3
3
  id: string;
4
4
  level: string;
@@ -8,7 +8,7 @@ export type Log = {
8
8
  flows: string[];
9
9
  [key: string]: any;
10
10
  };
11
- export declare class LogsStream extends StateStream<Log> {
11
+ export declare class LogsStream extends StreamAdapter<Log> {
12
12
  get: () => Promise<null>;
13
13
  delete: () => Promise<null>;
14
14
  getGroup: () => Promise<never[]>;
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LogsStream = void 0;
4
- const state_stream_1 = require("../state-stream");
4
+ const stream_adapter_1 = require("./adapters/stream-adapter");
5
5
  /*
6
6
  * We're not storing logs in the state because of size of data
7
7
  * if process stays for to long it would consume too much memory
8
8
  * in this case, we're just streaming through events.
9
9
  */
10
- class LogsStream extends state_stream_1.StateStream {
10
+ class LogsStream extends stream_adapter_1.StreamAdapter {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  this.get = async () => null;
@@ -0,0 +1,2 @@
1
+ import { MotiaStream } from '../types-stream';
2
+ export type StreamFactory<TData> = () => MotiaStream<TData>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -14,9 +14,12 @@ const generateTypeFromSchema = (schema) => {
14
14
  });
15
15
  return props.length > 0 ? `{ ${props.join('; ')} }` : '{}';
16
16
  }
17
+ if (schema.type === 'string') {
18
+ return schema.enum && schema.enum.length > 0 // must have at least one enum value
19
+ ? schema.enum.map((value) => `'${value}'`).join(' | ')
20
+ : 'string';
21
+ }
17
22
  switch (schema.type) {
18
- case 'string':
19
- return 'string';
20
23
  case 'number':
21
24
  return 'number';
22
25
  case 'boolean':
@@ -13,12 +13,12 @@ const generateTypesString = (handlers, streams) => {
13
13
  *
14
14
  * Consider adding this file to .prettierignore and eslint ignore.
15
15
  */
16
- import { EventHandler, ApiRouteHandler, ApiResponse, IStateStream } from 'motia'
16
+ import { EventHandler, ApiRouteHandler, ApiResponse, MotiaStream } from 'motia'
17
17
 
18
18
  declare module 'motia' {
19
19
  interface FlowContextStateStreams {
20
20
  ${Object.entries(streams)
21
- .map(([key, value]) => `'${key}': IStateStream<${value}>`)
21
+ .map(([key, value]) => `'${key}': MotiaStream<${value}>`)
22
22
  .join('\n ')
23
23
  .trim()}
24
24
  }
@@ -1,4 +1,4 @@
1
- export type JsonSchemaType = 'string' | 'number' | 'boolean';
1
+ export type JsonSchemaType = 'number' | 'boolean';
2
2
  export type JsonArray = {
3
3
  type: 'array';
4
4
  description?: string;
@@ -10,11 +10,16 @@ export type JsonObject = {
10
10
  properties: Record<string, JsonSchema>;
11
11
  required?: string[];
12
12
  };
13
+ export type JsonString = {
14
+ type: 'string';
15
+ description?: string;
16
+ enum?: string[];
17
+ };
13
18
  export type JsonProperty = {
14
19
  type: JsonSchemaType;
15
20
  description?: string;
16
21
  };
17
- export type JsonSchema = JsonArray | JsonObject | JsonProperty;
22
+ export type JsonSchema = JsonArray | JsonObject | JsonString | JsonProperty;
18
23
  export declare class JsonSchemaError extends Error {
19
24
  constructor(message: string);
20
25
  }
@@ -1,13 +1,13 @@
1
1
  import { ZodObject } from 'zod';
2
- import { StateStreamFactory } from './state-stream';
3
- export interface StateStreamConfig {
2
+ import { StreamFactory } from './streams/stream-factory';
3
+ export interface StreamConfig {
4
4
  name: string;
5
5
  schema: ZodObject<any>;
6
6
  baseConfig: {
7
- storageType: 'state';
7
+ storageType: 'default';
8
8
  } | {
9
9
  storageType: 'custom';
10
- factory: () => IStateStream<any>;
10
+ factory: () => MotiaStream<any>;
11
11
  };
12
12
  }
13
13
  export type StateStreamEventChannel = {
@@ -21,15 +21,15 @@ export type StateStreamEvent<TData> = {
21
21
  export type BaseStreamItem<TData = unknown> = TData & {
22
22
  id: string;
23
23
  };
24
- export type Stream<TConfig extends StateStreamConfig = StateStreamConfig> = {
24
+ export type Stream<TConfig extends StreamConfig = StreamConfig> = {
25
25
  filePath: string;
26
26
  config: TConfig;
27
27
  hidden?: boolean;
28
- factory: StateStreamFactory<unknown>;
28
+ factory: StreamFactory<unknown>;
29
29
  };
30
- export interface IStateStream<TData> {
30
+ export interface MotiaStream<TData> {
31
31
  get(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
32
- set(groupId: string, id: string, data: TData): Promise<BaseStreamItem<TData> | null>;
32
+ set(groupId: string, id: string, data: TData): Promise<BaseStreamItem<TData>>;
33
33
  delete(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
34
34
  getGroup(groupId: string): Promise<BaseStreamItem<TData>[]>;
35
35
  send<T>(channel: StateStreamEventChannel, event: StateStreamEvent<T>): Promise<void>;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@motiadev/core",
3
3
  "description": "Core functionality for the Motia framework, providing the foundation for building event-driven workflows.",
4
4
  "main": "dist/index.js",
5
- "version": "0.2.1-beta.74",
5
+ "version": "0.2.1-beta.75",
6
6
  "dependencies": {
7
7
  "@amplitude/analytics-node": "^1.3.8",
8
8
  "body-parser": "^1.20.3",
@@ -1,19 +0,0 @@
1
- import type { InternalStateManager } from './types';
2
- import type { BaseStreamItem, IStateStream, StateStreamEvent, StateStreamEventChannel } from './types-stream';
3
- export type StateStreamFactory<TData> = () => IStateStream<TData>;
4
- export declare abstract class StateStream<TData> implements IStateStream<TData> {
5
- abstract get(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
6
- abstract set(groupId: string, id: string, data: TData): Promise<BaseStreamItem<TData> | null>;
7
- abstract delete(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
8
- abstract getGroup(groupId: string): Promise<BaseStreamItem<TData>[]>;
9
- send<T>(channel: StateStreamEventChannel, event: StateStreamEvent<T>): Promise<void>;
10
- }
11
- export declare class InternalStateStream<TData> extends StateStream<TData> {
12
- private readonly state;
13
- constructor(state: InternalStateManager);
14
- get(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
15
- set(groupId: string, id: string, data: TData): Promise<BaseStreamItem<TData> | null>;
16
- delete(groupId: string, id: string): Promise<BaseStreamItem<TData> | null>;
17
- getGroup(groupId: string): Promise<BaseStreamItem<TData>[]>;
18
- send(): Promise<void>;
19
- }
@@ -1,28 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InternalStateStream = exports.StateStream = void 0;
4
- class StateStream {
5
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
- async send(channel, event) { }
7
- }
8
- exports.StateStream = StateStream;
9
- class InternalStateStream extends StateStream {
10
- constructor(state) {
11
- super();
12
- this.state = state;
13
- }
14
- async get(groupId, id) {
15
- return this.state.get(groupId, id);
16
- }
17
- async set(groupId, id, data) {
18
- return this.state.set(groupId, id, { id, ...data });
19
- }
20
- async delete(groupId, id) {
21
- return this.state.delete(groupId, id);
22
- }
23
- async getGroup(groupId) {
24
- return this.state.getGroup(groupId);
25
- }
26
- async send() { }
27
- }
28
- exports.InternalStateStream = InternalStateStream;