motia 0.15.4-beta.170-677191 → 0.15.4-beta.170-888624

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.
@@ -22,6 +22,21 @@ export default config({
22
22
  })
23
23
  ```
24
24
 
25
+ ## Creating Projects Without Embedded Redis
26
+
27
+ By default, Motia includes an embedded Redis binary for easy local development. However, if you prefer to use your own external Redis instance, you can use the `--skip-redis` flag when creating a new project:
28
+
29
+ ```bash
30
+ npx motia create my-app --skip-redis
31
+ ```
32
+
33
+ This flag:
34
+ - Skips the embedded Redis binary installation
35
+ - Creates a `motia.config.ts` pre-configured for external Redis connection
36
+ - Requires you to provide your own Redis instance before running Motia
37
+
38
+ When using `--skip-redis`, you'll need to ensure Redis is running and properly configured in your `motia.config.ts` file (see Redis Configuration section below).
39
+
25
40
  ## Type Definitions
26
41
 
27
42
  ```typescript
@@ -51,6 +66,12 @@ export type Config = {
51
66
  * Use this to secure real-time stream subscriptions.
52
67
  */
53
68
  streamAuth?: StreamAuthConfig
69
+
70
+ /**
71
+ * Optional: Redis configuration.
72
+ * Configure Redis connection or use the built-in in-memory Redis server.
73
+ */
74
+ redis?: RedisConfig
54
75
  }
55
76
 
56
77
  export type AdapterConfig = {
@@ -78,6 +99,19 @@ export type StreamAuthConfig<TSchema extends z.ZodTypeAny = z.ZodTypeAny> = {
78
99
  */
79
100
  authenticate: (request: StreamAuthRequest) => Promise<z.infer<TSchema> | null> | (z.infer<TSchema> | null)
80
101
  }
102
+
103
+ export type RedisConfig =
104
+ | {
105
+ useMemoryServer?: false
106
+ host: string
107
+ port: number
108
+ password?: string
109
+ username?: string
110
+ db?: number
111
+ }
112
+ | {
113
+ useMemoryServer: true
114
+ }
81
115
  ```
82
116
 
83
117
  ## Plugins
@@ -300,6 +334,81 @@ export default config({
300
334
  })
301
335
  ```
302
336
 
337
+ ## Redis Configuration
338
+
339
+ Motia uses Redis for state management, caching, and real-time features. By default, Motia automatically starts an in-memory Redis server for local development, eliminating the need for external Redis installation.
340
+
341
+ ### Default Behavior (In-Memory Redis)
342
+
343
+ When no `redis` configuration is provided, Motia uses an embedded in-memory Redis server:
344
+
345
+ ```typescript
346
+ import { config } from 'motia'
347
+
348
+ export default config({})
349
+ ```
350
+
351
+ You can also explicitly enable the in-memory server:
352
+
353
+ ```typescript
354
+ export default config({
355
+ redis: {
356
+ useMemoryServer: true,
357
+ },
358
+ })
359
+ ```
360
+
361
+ ### Using External Redis
362
+
363
+ To connect to an external Redis instance (useful for production or when you already have Redis running), configure the connection settings:
364
+
365
+ ```typescript
366
+ import { config } from 'motia'
367
+
368
+ export default config({
369
+ redis: {
370
+ useMemoryServer: false,
371
+ host: 'localhost',
372
+ port: 6379,
373
+ },
374
+ })
375
+ ```
376
+
377
+ For production environments with authentication:
378
+
379
+ ```typescript
380
+ export default config({
381
+ redis: {
382
+ useMemoryServer: false,
383
+ host: process.env.REDIS_HOST || 'localhost',
384
+ port: parseInt(process.env.REDIS_PORT || '6379'),
385
+ password: process.env.REDIS_PASSWORD,
386
+ username: process.env.REDIS_USERNAME,
387
+ db: parseInt(process.env.REDIS_DB || '0'),
388
+ },
389
+ })
390
+ ```
391
+
392
+ The optional Redis configuration fields include:
393
+ - `password`: Redis password for authentication
394
+ - `username`: Redis username (Redis 6.0+)
395
+ - `db`: Database number to select (default: 0)
396
+
397
+ You can also use environment variables directly:
398
+ - `MOTIA_REDIS_PASSWORD`: Redis password
399
+ - `MOTIA_REDIS_USERNAME`: Redis username
400
+ - `MOTIA_REDIS_DB`: Database number
401
+
402
+ ### Creating Projects with External Redis
403
+
404
+ When creating a new project, you can skip the embedded Redis binary installation using the `--skip-redis` flag:
405
+
406
+ ```bash
407
+ npx motia create my-app --skip-redis
408
+ ```
409
+
410
+ This will create a project with `motia.config.ts` pre-configured for external Redis, and you'll need to ensure Redis is running before starting your application.
411
+
303
412
  ## Complete Example
304
413
 
305
414
  ```typescript
package/dist/dev.mjs CHANGED
@@ -8,7 +8,7 @@ import { isTutorialDisabled, workbenchBase } from "./constants.mjs";
8
8
  import { createDevWatchers } from "./dev-watchers.mjs";
9
9
  import { processPlugins } from "./plugins/process-plugins.mjs";
10
10
  import "./plugins/index.mjs";
11
- import { getRedisClient, stopRedisConnection } from "./redis/connection.mjs";
11
+ import { getRedisClient, getRedisConnectionInfo, stopRedisConnection } from "./redis/connection.mjs";
12
12
  import { createMermaidGenerator, createServer, getProjectIdentifier, trackEvent } from "@motiadev/core";
13
13
  import { flush } from "@amplitude/analytics-node";
14
14
  import { BullMQEventAdapter } from "@motiadev/adapter-bullmq-events";
@@ -43,10 +43,7 @@ const dev = async (port, hostname, disableVerbose, enableMermaid, motiaFileStora
43
43
  const redisClient = await getRedisClient(motiaFileStoragePath, appConfig);
44
44
  const adapters = {
45
45
  eventAdapter: appConfig.adapters?.events || new BullMQEventAdapter({
46
- connection: {
47
- host: redisClient.options.socket?.host || "localhost",
48
- port: redisClient.options.socket?.port || 6379
49
- },
46
+ connection: getRedisConnectionInfo(),
50
47
  prefix: "motia:events"
51
48
  }),
52
49
  cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),
package/dist/dev.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"dev.mjs","names":["redisClient: RedisClientType","plugins: MotiaPlugin[]"],"sources":["../src/dev.ts"],"sourcesContent":["import { flush } from '@amplitude/analytics-node'\nimport { BullMQEventAdapter } from '@motiadev/adapter-bullmq-events'\nimport { RedisCronAdapter } from '@motiadev/adapter-redis-cron'\nimport { RedisStateAdapter } from '@motiadev/adapter-redis-state'\nimport { RedisStreamAdapterManager } from '@motiadev/adapter-redis-streams'\nimport {\n createMermaidGenerator,\n createServer,\n getProjectIdentifier,\n type MotiaPlugin,\n trackEvent,\n} from '@motiadev/core'\nimport type { RedisClientType } from 'redis'\nimport { deployEndpoints } from './cloud/endpoints'\nimport { isTutorialDisabled, workbenchBase } from './constants'\nimport { createDevWatchers } from './dev-watchers'\nimport { generateLockedData, getStepFiles, getStreamFiles } from './generate-locked-data'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { processPlugins } from './plugins'\nimport { getRedisClient, stopRedisConnection } from './redis/connection'\nimport { activatePythonVenv } from './utils/activate-python-env'\nimport { identifyUser } from './utils/analytics'\nimport { version } from './version'\n\nexport const dev = async (\n port: number,\n hostname: string,\n disableVerbose: boolean,\n enableMermaid: boolean,\n motiaFileStorageDir?: string,\n): Promise<void> => {\n const baseDir = process.cwd()\n const isVerbose = !disableVerbose\n\n identifyUser()\n\n const stepFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)]\n const hasPythonFiles = stepFiles.some((file) => file.endsWith('.py'))\n\n trackEvent('dev_server_started', {\n port,\n verbose_mode: isVerbose,\n mermaid_enabled: enableMermaid,\n has_python_files: hasPythonFiles,\n total_step_files: stepFiles.length,\n project_name: getProjectIdentifier(baseDir),\n })\n\n if (hasPythonFiles) {\n activatePythonVenv({ baseDir, isVerbose })\n trackEvent('python_environment_activated')\n }\n\n const motiaFileStoragePath = motiaFileStorageDir || '.motia'\n\n const appConfig = await loadMotiaConfig(baseDir)\n\n const redisClient: RedisClientType = await getRedisClient(motiaFileStoragePath, appConfig)\n\n const adapters = {\n eventAdapter:\n appConfig.adapters?.events ||\n new BullMQEventAdapter({\n connection: {\n host: (redisClient.options.socket as { host?: string })?.host || 'localhost',\n port: (redisClient.options.socket as { port?: number })?.port || 6379,\n },\n prefix: 'motia:events',\n }),\n cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),\n streamAdapter: appConfig.adapters?.streams || new RedisStreamAdapterManager(redisClient),\n }\n\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: adapters.streamAdapter,\n redisClient,\n streamAuth: appConfig.streamAuth,\n })\n\n const state = appConfig.adapters?.state || new RedisStateAdapter(redisClient)\n\n const config = { isVerbose }\n\n const motiaServer = createServer(lockedData, state, config, adapters, appConfig.app)\n const watcher = createDevWatchers(lockedData, motiaServer, motiaServer.motiaEventManager, motiaServer.cronManager)\n const plugins: MotiaPlugin[] = await processPlugins(motiaServer)\n\n // Initialize mermaid generator\n if (enableMermaid) {\n const mermaidGenerator = createMermaidGenerator(baseDir)\n mermaidGenerator.initialize(lockedData)\n trackEvent('mermaid_generator_initialized')\n }\n\n deployEndpoints(motiaServer, lockedData)\n\n motiaServer.app.get('/__motia', (_, res) => {\n const meta = {\n version,\n isDev: true,\n isTutorialDisabled,\n workbenchBase,\n }\n\n res //\n .header('Access-Control-Allow-Origin', '*')\n .header('Access-Control-Allow-Private-Network', 'true')\n .status(200)\n .json(meta)\n })\n\n trackEvent('dev_server_ready', {\n port,\n flows_count: lockedData.flows?.length || 0,\n steps_count: lockedData.activeSteps?.length || 0,\n flows: Object.keys(lockedData.flows || {}),\n steps: lockedData.activeSteps.map((step) => step.config.name),\n streams: Object.keys(lockedData.getStreams() || {}),\n runtime_version: version,\n environment: process.env.NODE_ENV || 'development',\n })\n\n const { applyMiddleware } = await import('@motiadev/workbench/middleware')\n\n await applyMiddleware({\n app: motiaServer.app,\n port,\n workbenchBase,\n plugins: plugins.flatMap((item) => item.workbench),\n })\n\n motiaServer.server.listen(port, hostname)\n console.log('🚀 Server ready and listening on port', port)\n console.log(`🔗 Open http://localhost:${port}${workbenchBase} to open workbench 🛠️`)\n\n process.on('SIGTERM', async () => {\n trackEvent('dev_server_shutdown', { reason: 'SIGTERM' })\n motiaServer.server.close()\n await watcher.stop()\n await stopRedisConnection()\n await flush().promise\n process.exit(0)\n })\n\n process.on('SIGINT', async () => {\n trackEvent('dev_server_shutdown', { reason: 'SIGINT' })\n motiaServer.server.close()\n await watcher.stop()\n await stopRedisConnection()\n await flush().promise\n process.exit(0)\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"dev.mjs","names":["redisClient: RedisClientType","plugins: MotiaPlugin[]"],"sources":["../src/dev.ts"],"sourcesContent":["import { flush } from '@amplitude/analytics-node'\nimport { BullMQEventAdapter } from '@motiadev/adapter-bullmq-events'\nimport { RedisCronAdapter } from '@motiadev/adapter-redis-cron'\nimport { RedisStateAdapter } from '@motiadev/adapter-redis-state'\nimport { RedisStreamAdapterManager } from '@motiadev/adapter-redis-streams'\nimport {\n createMermaidGenerator,\n createServer,\n getProjectIdentifier,\n type MotiaPlugin,\n trackEvent,\n} from '@motiadev/core'\nimport type { RedisClientType } from 'redis'\nimport { deployEndpoints } from './cloud/endpoints'\nimport { isTutorialDisabled, workbenchBase } from './constants'\nimport { createDevWatchers } from './dev-watchers'\nimport { generateLockedData, getStepFiles, getStreamFiles } from './generate-locked-data'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { processPlugins } from './plugins'\nimport { getRedisClient, getRedisConnectionInfo, stopRedisConnection } from './redis/connection'\nimport { activatePythonVenv } from './utils/activate-python-env'\nimport { identifyUser } from './utils/analytics'\nimport { version } from './version'\n\nexport const dev = async (\n port: number,\n hostname: string,\n disableVerbose: boolean,\n enableMermaid: boolean,\n motiaFileStorageDir?: string,\n): Promise<void> => {\n const baseDir = process.cwd()\n const isVerbose = !disableVerbose\n\n identifyUser()\n\n const stepFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)]\n const hasPythonFiles = stepFiles.some((file) => file.endsWith('.py'))\n\n trackEvent('dev_server_started', {\n port,\n verbose_mode: isVerbose,\n mermaid_enabled: enableMermaid,\n has_python_files: hasPythonFiles,\n total_step_files: stepFiles.length,\n project_name: getProjectIdentifier(baseDir),\n })\n\n if (hasPythonFiles) {\n activatePythonVenv({ baseDir, isVerbose })\n trackEvent('python_environment_activated')\n }\n\n const motiaFileStoragePath = motiaFileStorageDir || '.motia'\n\n const appConfig = await loadMotiaConfig(baseDir)\n\n const redisClient: RedisClientType = await getRedisClient(motiaFileStoragePath, appConfig)\n\n const adapters = {\n eventAdapter:\n appConfig.adapters?.events ||\n new BullMQEventAdapter({\n connection: getRedisConnectionInfo(),\n prefix: 'motia:events',\n }),\n cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),\n streamAdapter: appConfig.adapters?.streams || new RedisStreamAdapterManager(redisClient),\n }\n\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: adapters.streamAdapter,\n redisClient,\n streamAuth: appConfig.streamAuth,\n })\n\n const state = appConfig.adapters?.state || new RedisStateAdapter(redisClient)\n\n const config = { isVerbose }\n\n const motiaServer = createServer(lockedData, state, config, adapters, appConfig.app)\n const watcher = createDevWatchers(lockedData, motiaServer, motiaServer.motiaEventManager, motiaServer.cronManager)\n const plugins: MotiaPlugin[] = await processPlugins(motiaServer)\n\n // Initialize mermaid generator\n if (enableMermaid) {\n const mermaidGenerator = createMermaidGenerator(baseDir)\n mermaidGenerator.initialize(lockedData)\n trackEvent('mermaid_generator_initialized')\n }\n\n deployEndpoints(motiaServer, lockedData)\n\n motiaServer.app.get('/__motia', (_, res) => {\n const meta = {\n version,\n isDev: true,\n isTutorialDisabled,\n workbenchBase,\n }\n\n res //\n .header('Access-Control-Allow-Origin', '*')\n .header('Access-Control-Allow-Private-Network', 'true')\n .status(200)\n .json(meta)\n })\n\n trackEvent('dev_server_ready', {\n port,\n flows_count: lockedData.flows?.length || 0,\n steps_count: lockedData.activeSteps?.length || 0,\n flows: Object.keys(lockedData.flows || {}),\n steps: lockedData.activeSteps.map((step) => step.config.name),\n streams: Object.keys(lockedData.getStreams() || {}),\n runtime_version: version,\n environment: process.env.NODE_ENV || 'development',\n })\n\n const { applyMiddleware } = await import('@motiadev/workbench/middleware')\n\n await applyMiddleware({\n app: motiaServer.app,\n port,\n workbenchBase,\n plugins: plugins.flatMap((item) => item.workbench),\n })\n\n motiaServer.server.listen(port, hostname)\n console.log('🚀 Server ready and listening on port', port)\n console.log(`🔗 Open http://localhost:${port}${workbenchBase} to open workbench 🛠️`)\n\n process.on('SIGTERM', async () => {\n trackEvent('dev_server_shutdown', { reason: 'SIGTERM' })\n motiaServer.server.close()\n await watcher.stop()\n await stopRedisConnection()\n await flush().promise\n process.exit(0)\n })\n\n process.on('SIGINT', async () => {\n trackEvent('dev_server_shutdown', { reason: 'SIGINT' })\n motiaServer.server.close()\n await watcher.stop()\n await stopRedisConnection()\n await flush().promise\n process.exit(0)\n })\n}\n"],"mappings":"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"}
@@ -6,37 +6,52 @@ import { createClient } from "redis";
6
6
  var RedisConnectionManager = class {
7
7
  constructor() {
8
8
  this.client = null;
9
+ this.redisConnectionInfo = null;
9
10
  }
10
11
  async getConnectionInfo(baseDir, config) {
11
12
  if (shouldUseMemoryServer(config)) return await new RedisMemoryManager().startServer(baseDir);
12
13
  if (isExternalRedisConfig(config.redis)) return {
13
14
  host: config.redis.host,
14
- port: config.redis.port
15
+ port: config.redis.port,
16
+ password: config.redis.password,
17
+ username: config.redis.username,
18
+ db: config.redis.db
15
19
  };
16
20
  return {
17
21
  host: process.env.MOTIA_REDIS_HOST || "127.0.0.1",
18
- port: parseInt(process.env.MOTIA_REDIS_PORT || "6379")
22
+ port: parseInt(process.env.MOTIA_REDIS_PORT || "6379"),
23
+ password: process.env.MOTIA_REDIS_PASSWORD,
24
+ username: process.env.MOTIA_REDIS_USERNAME,
25
+ db: parseInt(process.env.MOTIA_REDIS_DB || "0")
19
26
  };
20
27
  }
21
28
  async connect(baseDir, config) {
22
29
  if (this.client) return this.client;
23
- const { host, port } = await this.getConnectionInfo(baseDir, config);
24
- this.client = createClient({ socket: {
25
- host,
26
- port,
27
- noDelay: true,
28
- keepAlive: true,
29
- reconnectStrategy: (retries) => {
30
- if (retries > 10) return /* @__PURE__ */ new Error("Redis connection retry limit exceeded");
31
- return Math.min(retries * 100, 3e3);
32
- },
33
- connectTimeout: 1e4
34
- } });
30
+ this.redisConnectionInfo = await this.getConnectionInfo(baseDir, config);
31
+ this.client = createClient({
32
+ password: this.redisConnectionInfo.password,
33
+ username: this.redisConnectionInfo.username,
34
+ database: this.redisConnectionInfo.db,
35
+ socket: {
36
+ host: this.redisConnectionInfo.host,
37
+ port: this.redisConnectionInfo.port,
38
+ noDelay: true,
39
+ keepAlive: true,
40
+ reconnectStrategy: (retries) => {
41
+ if (retries > 10) return /* @__PURE__ */ new Error("Redis connection retry limit exceeded");
42
+ return Math.min(retries * 100, 3e3);
43
+ },
44
+ connectTimeout: 1e4
45
+ }
46
+ });
47
+ await this.client.connect();
35
48
  return this.client;
36
49
  }
37
50
  async stop() {
38
- if (this.client) {
39
- await this.client.quit();
51
+ if (this.client?.isOpen) {
52
+ await this.client.quit().catch(() => {
53
+ console.error("[Redis Connection] Redis client closed");
54
+ });
40
55
  this.client = null;
41
56
  }
42
57
  }
@@ -46,11 +61,15 @@ var RedisConnectionManager = class {
46
61
  getClient() {
47
62
  return this.client;
48
63
  }
64
+ get connectionInfo() {
65
+ return this.redisConnectionInfo;
66
+ }
49
67
  };
50
68
  const manager = new RedisConnectionManager();
51
69
  const getRedisClient = (baseDir, config) => manager.connect(baseDir, config);
52
70
  const stopRedisConnection = () => manager.stop();
71
+ const getRedisConnectionInfo = () => manager.connectionInfo;
53
72
 
54
73
  //#endregion
55
- export { getRedisClient, stopRedisConnection };
74
+ export { getRedisClient, getRedisConnectionInfo, stopRedisConnection };
56
75
  //# sourceMappingURL=connection.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection.mjs","names":[],"sources":["../../src/redis/connection.ts"],"sourcesContent":["import { createClient, type RedisClientType } from 'redis'\nimport type { LoadedMotiaConfig } from '../load-motia-config'\nimport { RedisMemoryManager } from './memory-manager'\nimport type { RedisConnectionInfo } from './types'\nimport { isExternalRedisConfig, shouldUseMemoryServer } from './utils'\n\nexport type { RedisConnectionInfo } from './types'\n\nclass RedisConnectionManager {\n private client: RedisClientType | null = null\n\n private async getConnectionInfo(baseDir: string, config: LoadedMotiaConfig): Promise<RedisConnectionInfo> {\n if (shouldUseMemoryServer(config)) {\n return await new RedisMemoryManager().startServer(baseDir)\n }\n if (isExternalRedisConfig(config.redis)) {\n return { host: config.redis.host, port: config.redis.port }\n }\n return { host: process.env.MOTIA_REDIS_HOST || '127.0.0.1', port: parseInt(process.env.MOTIA_REDIS_PORT || '6379') }\n }\n\n async connect(baseDir: string, config: LoadedMotiaConfig): Promise<RedisClientType> {\n if (this.client) {\n return this.client\n }\n\n const { host, port } = await this.getConnectionInfo(baseDir, config)\n\n this.client = createClient({\n socket: {\n host,\n port,\n noDelay: true,\n keepAlive: true,\n reconnectStrategy: (retries: number) => {\n if (retries > 10) {\n return new Error('Redis connection retry limit exceeded')\n }\n return Math.min(retries * 100, 3000)\n },\n connectTimeout: 10000,\n },\n })\n return this.client\n }\n\n async stop(): Promise<void> {\n if (this.client) {\n await this.client.quit()\n this.client = null\n }\n }\n\n isRunning(): boolean {\n return !!this.client?.isOpen\n }\n\n getClient(): RedisClientType | null {\n return this.client\n }\n}\n\nconst manager = new RedisConnectionManager()\n\nexport const getRedisClient = (baseDir: string, config: LoadedMotiaConfig): Promise<RedisClientType> =>\n manager.connect(baseDir, config)\n\nexport const stopRedisConnection = (): Promise<void> => manager.stop()\n"],"mappings":";;;;;AAQA,IAAM,yBAAN,MAA6B;;gBACc;;CAEzC,MAAc,kBAAkB,SAAiB,QAAyD;AACxG,MAAI,sBAAsB,OAAO,CAC/B,QAAO,MAAM,IAAI,oBAAoB,CAAC,YAAY,QAAQ;AAE5D,MAAI,sBAAsB,OAAO,MAAM,CACrC,QAAO;GAAE,MAAM,OAAO,MAAM;GAAM,MAAM,OAAO,MAAM;GAAM;AAE7D,SAAO;GAAE,MAAM,QAAQ,IAAI,oBAAoB;GAAa,MAAM,SAAS,QAAQ,IAAI,oBAAoB,OAAO;GAAE;;CAGtH,MAAM,QAAQ,SAAiB,QAAqD;AAClF,MAAI,KAAK,OACP,QAAO,KAAK;EAGd,MAAM,EAAE,MAAM,SAAS,MAAM,KAAK,kBAAkB,SAAS,OAAO;AAEpE,OAAK,SAAS,aAAa,EACzB,QAAQ;GACN;GACA;GACA,SAAS;GACT,WAAW;GACX,oBAAoB,YAAoB;AACtC,QAAI,UAAU,GACZ,wBAAO,IAAI,MAAM,wCAAwC;AAE3D,WAAO,KAAK,IAAI,UAAU,KAAK,IAAK;;GAEtC,gBAAgB;GACjB,EACF,CAAC;AACF,SAAO,KAAK;;CAGd,MAAM,OAAsB;AAC1B,MAAI,KAAK,QAAQ;AACf,SAAM,KAAK,OAAO,MAAM;AACxB,QAAK,SAAS;;;CAIlB,YAAqB;AACnB,SAAO,CAAC,CAAC,KAAK,QAAQ;;CAGxB,YAAoC;AAClC,SAAO,KAAK;;;AAIhB,MAAM,UAAU,IAAI,wBAAwB;AAE5C,MAAa,kBAAkB,SAAiB,WAC9C,QAAQ,QAAQ,SAAS,OAAO;AAElC,MAAa,4BAA2C,QAAQ,MAAM"}
1
+ {"version":3,"file":"connection.mjs","names":[],"sources":["../../src/redis/connection.ts"],"sourcesContent":["import { createClient, type RedisClientType } from 'redis'\nimport type { LoadedMotiaConfig } from '../load-motia-config'\nimport { RedisMemoryManager } from './memory-manager'\nimport type { RedisConnectionInfo } from './types'\nimport { isExternalRedisConfig, shouldUseMemoryServer } from './utils'\n\nexport type { RedisConnectionInfo } from './types'\n\nclass RedisConnectionManager {\n private client: RedisClientType | null = null\n private redisConnectionInfo: RedisConnectionInfo | null = null\n\n private async getConnectionInfo(baseDir: string, config: LoadedMotiaConfig): Promise<RedisConnectionInfo> {\n if (shouldUseMemoryServer(config)) {\n return await new RedisMemoryManager().startServer(baseDir)\n }\n if (isExternalRedisConfig(config.redis)) {\n return {\n host: config.redis.host,\n port: config.redis.port,\n password: config.redis.password,\n username: config.redis.username,\n db: config.redis.db,\n }\n }\n return {\n host: process.env.MOTIA_REDIS_HOST || '127.0.0.1',\n port: parseInt(process.env.MOTIA_REDIS_PORT || '6379'),\n password: process.env.MOTIA_REDIS_PASSWORD,\n username: process.env.MOTIA_REDIS_USERNAME,\n db: parseInt(process.env.MOTIA_REDIS_DB || '0'),\n }\n }\n\n async connect(baseDir: string, config: LoadedMotiaConfig): Promise<RedisClientType> {\n if (this.client) {\n return this.client\n }\n\n this.redisConnectionInfo = await this.getConnectionInfo(baseDir, config)\n\n this.client = createClient({\n password: this.redisConnectionInfo.password,\n username: this.redisConnectionInfo.username,\n database: this.redisConnectionInfo.db,\n socket: {\n host: this.redisConnectionInfo.host,\n port: this.redisConnectionInfo.port,\n noDelay: true,\n keepAlive: true,\n reconnectStrategy: (retries: number) => {\n if (retries > 10) {\n return new Error('Redis connection retry limit exceeded')\n }\n return Math.min(retries * 100, 3000)\n },\n connectTimeout: 10000,\n },\n })\n\n await this.client.connect()\n\n return this.client\n }\n\n async stop(): Promise<void> {\n if (this.client?.isOpen) {\n await this.client.quit().catch(() => {\n console.error('[Redis Connection] Redis client closed')\n })\n this.client = null\n }\n }\n\n isRunning(): boolean {\n return !!this.client?.isOpen\n }\n\n getClient(): RedisClientType | null {\n return this.client\n }\n\n get connectionInfo(): RedisConnectionInfo {\n return this.redisConnectionInfo!\n }\n}\n\nconst manager = new RedisConnectionManager()\n\nexport const getRedisClient = (baseDir: string, config: LoadedMotiaConfig): Promise<RedisClientType> =>\n manager.connect(baseDir, config)\n\nexport const stopRedisConnection = (): Promise<void> => manager.stop()\n\nexport const getRedisConnectionInfo = (): RedisConnectionInfo => manager.connectionInfo\n"],"mappings":";;;;;AAQA,IAAM,yBAAN,MAA6B;;gBACc;6BACiB;;CAE1D,MAAc,kBAAkB,SAAiB,QAAyD;AACxG,MAAI,sBAAsB,OAAO,CAC/B,QAAO,MAAM,IAAI,oBAAoB,CAAC,YAAY,QAAQ;AAE5D,MAAI,sBAAsB,OAAO,MAAM,CACrC,QAAO;GACL,MAAM,OAAO,MAAM;GACnB,MAAM,OAAO,MAAM;GACnB,UAAU,OAAO,MAAM;GACvB,UAAU,OAAO,MAAM;GACvB,IAAI,OAAO,MAAM;GAClB;AAEH,SAAO;GACL,MAAM,QAAQ,IAAI,oBAAoB;GACtC,MAAM,SAAS,QAAQ,IAAI,oBAAoB,OAAO;GACtD,UAAU,QAAQ,IAAI;GACtB,UAAU,QAAQ,IAAI;GACtB,IAAI,SAAS,QAAQ,IAAI,kBAAkB,IAAI;GAChD;;CAGH,MAAM,QAAQ,SAAiB,QAAqD;AAClF,MAAI,KAAK,OACP,QAAO,KAAK;AAGd,OAAK,sBAAsB,MAAM,KAAK,kBAAkB,SAAS,OAAO;AAExE,OAAK,SAAS,aAAa;GACzB,UAAU,KAAK,oBAAoB;GACnC,UAAU,KAAK,oBAAoB;GACnC,UAAU,KAAK,oBAAoB;GACnC,QAAQ;IACN,MAAM,KAAK,oBAAoB;IAC/B,MAAM,KAAK,oBAAoB;IAC/B,SAAS;IACT,WAAW;IACX,oBAAoB,YAAoB;AACtC,SAAI,UAAU,GACZ,wBAAO,IAAI,MAAM,wCAAwC;AAE3D,YAAO,KAAK,IAAI,UAAU,KAAK,IAAK;;IAEtC,gBAAgB;IACjB;GACF,CAAC;AAEF,QAAM,KAAK,OAAO,SAAS;AAE3B,SAAO,KAAK;;CAGd,MAAM,OAAsB;AAC1B,MAAI,KAAK,QAAQ,QAAQ;AACvB,SAAM,KAAK,OAAO,MAAM,CAAC,YAAY;AACnC,YAAQ,MAAM,yCAAyC;KACvD;AACF,QAAK,SAAS;;;CAIlB,YAAqB;AACnB,SAAO,CAAC,CAAC,KAAK,QAAQ;;CAGxB,YAAoC;AAClC,SAAO,KAAK;;CAGd,IAAI,iBAAsC;AACxC,SAAO,KAAK;;;AAIhB,MAAM,UAAU,IAAI,wBAAwB;AAE5C,MAAa,kBAAkB,SAAiB,WAC9C,QAAQ,QAAQ,SAAS,OAAO;AAElC,MAAa,4BAA2C,QAAQ,MAAM;AAEtE,MAAa,+BAAoD,QAAQ"}
@@ -34,6 +34,7 @@ var RedisMemoryManager = class {
34
34
  ] };
35
35
  if (process.env.MOTIA_REDIS_PORT) instance.port = parseInt(process.env.MOTIA_REDIS_PORT || "6379");
36
36
  this.server = new RedisMemoryServer({ instance });
37
+ console.log("Redis Memory Server started");
37
38
  this.running = true;
38
39
  this.registerCleanupHandlers();
39
40
  } catch (error) {
@@ -48,10 +49,10 @@ var RedisMemoryManager = class {
48
49
  async stop() {
49
50
  if (this.server && this.running) try {
50
51
  await this.server.stop();
51
- this.running = false;
52
52
  } catch (error) {
53
53
  console.error("[Redis Memory Server] Error stopping:", error?.message);
54
54
  } finally {
55
+ this.running = false;
55
56
  this.server = null;
56
57
  }
57
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"memory-manager.mjs","names":["instance: RedisMemoryInstancePropT","error: unknown"],"sources":["../../src/redis/memory-manager.ts"],"sourcesContent":["import { mkdirSync } from 'fs'\nimport type { RedisClientType } from 'redis'\nimport { RedisMemoryServer } from 'redis-memory-server'\nimport type { RedisMemoryInstancePropT } from 'redis-memory-server/lib/types'\nimport type { RedisConnectionInfo } from './types'\n\nexport class RedisMemoryManager {\n private server: RedisMemoryServer | null = null\n private client: RedisClientType | null = null\n private running = false\n\n private registerCleanupHandlers(): void {\n process.on('exit', async () => {\n await this.stop()\n })\n process.on('SIGTERM', async () => {\n await this.stop()\n })\n\n process.on('SIGINT', async () => {\n await this.stop()\n })\n }\n\n async startServer(baseDir: string): Promise<RedisConnectionInfo> {\n if (!this.server) {\n try {\n mkdirSync(baseDir, { recursive: true })\n\n const instance: RedisMemoryInstancePropT = {\n args: ['--appendonly', 'yes', '--appendfsync', 'everysec', '--save', '\"\"', '--dir', baseDir],\n }\n\n if (process.env.MOTIA_REDIS_PORT) {\n instance.port = parseInt(process.env.MOTIA_REDIS_PORT || '6379')\n }\n\n this.server = new RedisMemoryServer({ instance })\n this.running = true\n this.registerCleanupHandlers()\n } catch (error) {\n console.error('[Redis Memory Server] Failed to start:', error)\n throw error\n }\n }\n\n const host = await this.server.getHost()\n const port = await this.server.getPort()\n\n return { host, port }\n }\n\n async stop(): Promise<void> {\n if (this.server && this.running) {\n try {\n await this.server.stop()\n this.running = false\n } catch (error: unknown) {\n console.error('[Redis Memory Server] Error stopping:', (error as Error)?.message)\n } finally {\n this.server = null\n }\n }\n }\n\n isRunning(): boolean {\n return this.running\n }\n\n getClient(): RedisClientType | null {\n return this.client\n }\n}\n"],"mappings":";;;;AAMA,IAAa,qBAAb,MAAgC;;gBACa;gBACF;iBACvB;;CAElB,AAAQ,0BAAgC;AACtC,UAAQ,GAAG,QAAQ,YAAY;AAC7B,SAAM,KAAK,MAAM;IACjB;AACF,UAAQ,GAAG,WAAW,YAAY;AAChC,SAAM,KAAK,MAAM;IACjB;AAEF,UAAQ,GAAG,UAAU,YAAY;AAC/B,SAAM,KAAK,MAAM;IACjB;;CAGJ,MAAM,YAAY,SAA+C;AAC/D,MAAI,CAAC,KAAK,OACR,KAAI;AACF,aAAU,SAAS,EAAE,WAAW,MAAM,CAAC;GAEvC,MAAMA,WAAqC,EACzC,MAAM;IAAC;IAAgB;IAAO;IAAiB;IAAY;IAAU;IAAM;IAAS;IAAQ,EAC7F;AAED,OAAI,QAAQ,IAAI,iBACd,UAAS,OAAO,SAAS,QAAQ,IAAI,oBAAoB,OAAO;AAGlE,QAAK,SAAS,IAAI,kBAAkB,EAAE,UAAU,CAAC;AACjD,QAAK,UAAU;AACf,QAAK,yBAAyB;WACvB,OAAO;AACd,WAAQ,MAAM,0CAA0C,MAAM;AAC9D,SAAM;;AAOV,SAAO;GAAE,MAHI,MAAM,KAAK,OAAO,SAAS;GAGzB,MAFF,MAAM,KAAK,OAAO,SAAS;GAEnB;;CAGvB,MAAM,OAAsB;AAC1B,MAAI,KAAK,UAAU,KAAK,QACtB,KAAI;AACF,SAAM,KAAK,OAAO,MAAM;AACxB,QAAK,UAAU;WACRC,OAAgB;AACvB,WAAQ,MAAM,yCAA0C,OAAiB,QAAQ;YACzE;AACR,QAAK,SAAS;;;CAKpB,YAAqB;AACnB,SAAO,KAAK;;CAGd,YAAoC;AAClC,SAAO,KAAK"}
1
+ {"version":3,"file":"memory-manager.mjs","names":["instance: RedisMemoryInstancePropT","error: unknown"],"sources":["../../src/redis/memory-manager.ts"],"sourcesContent":["import { mkdirSync } from 'fs'\nimport type { RedisClientType } from 'redis'\nimport { RedisMemoryServer } from 'redis-memory-server'\nimport type { RedisMemoryInstancePropT } from 'redis-memory-server/lib/types'\nimport type { RedisConnectionInfo } from './types'\n\nexport class RedisMemoryManager {\n private server: RedisMemoryServer | null = null\n private client: RedisClientType | null = null\n private running = false\n\n private registerCleanupHandlers(): void {\n process.on('exit', async () => {\n await this.stop()\n })\n process.on('SIGTERM', async () => {\n await this.stop()\n })\n\n process.on('SIGINT', async () => {\n await this.stop()\n })\n }\n\n async startServer(baseDir: string): Promise<RedisConnectionInfo> {\n if (!this.server) {\n try {\n mkdirSync(baseDir, { recursive: true })\n\n const instance: RedisMemoryInstancePropT = {\n args: ['--appendonly', 'yes', '--appendfsync', 'everysec', '--save', '\"\"', '--dir', baseDir],\n }\n\n if (process.env.MOTIA_REDIS_PORT) {\n instance.port = parseInt(process.env.MOTIA_REDIS_PORT || '6379')\n }\n\n this.server = new RedisMemoryServer({ instance })\n console.log('Redis Memory Server started')\n this.running = true\n this.registerCleanupHandlers()\n } catch (error) {\n console.error('[Redis Memory Server] Failed to start:', error)\n throw error\n }\n }\n\n const host = await this.server.getHost()\n const port = await this.server.getPort()\n\n return { host, port }\n }\n\n async stop(): Promise<void> {\n if (this.server && this.running) {\n try {\n await this.server.stop()\n } catch (error: unknown) {\n console.error('[Redis Memory Server] Error stopping:', (error as Error)?.message)\n } finally {\n this.running = false\n this.server = null\n }\n }\n }\n\n isRunning(): boolean {\n return this.running\n }\n\n getClient(): RedisClientType | null {\n return this.client\n }\n}\n"],"mappings":";;;;AAMA,IAAa,qBAAb,MAAgC;;gBACa;gBACF;iBACvB;;CAElB,AAAQ,0BAAgC;AACtC,UAAQ,GAAG,QAAQ,YAAY;AAC7B,SAAM,KAAK,MAAM;IACjB;AACF,UAAQ,GAAG,WAAW,YAAY;AAChC,SAAM,KAAK,MAAM;IACjB;AAEF,UAAQ,GAAG,UAAU,YAAY;AAC/B,SAAM,KAAK,MAAM;IACjB;;CAGJ,MAAM,YAAY,SAA+C;AAC/D,MAAI,CAAC,KAAK,OACR,KAAI;AACF,aAAU,SAAS,EAAE,WAAW,MAAM,CAAC;GAEvC,MAAMA,WAAqC,EACzC,MAAM;IAAC;IAAgB;IAAO;IAAiB;IAAY;IAAU;IAAM;IAAS;IAAQ,EAC7F;AAED,OAAI,QAAQ,IAAI,iBACd,UAAS,OAAO,SAAS,QAAQ,IAAI,oBAAoB,OAAO;AAGlE,QAAK,SAAS,IAAI,kBAAkB,EAAE,UAAU,CAAC;AACjD,WAAQ,IAAI,8BAA8B;AAC1C,QAAK,UAAU;AACf,QAAK,yBAAyB;WACvB,OAAO;AACd,WAAQ,MAAM,0CAA0C,MAAM;AAC9D,SAAM;;AAOV,SAAO;GAAE,MAHI,MAAM,KAAK,OAAO,SAAS;GAGzB,MAFF,MAAM,KAAK,OAAO,SAAS;GAEnB;;CAGvB,MAAM,OAAsB;AAC1B,MAAI,KAAK,UAAU,KAAK,QACtB,KAAI;AACF,SAAM,KAAK,OAAO,MAAM;WACjBC,OAAgB;AACvB,WAAQ,MAAM,yCAA0C,OAAiB,QAAQ;YACzE;AACR,QAAK,UAAU;AACf,QAAK,SAAS;;;CAKpB,YAAqB;AACnB,SAAO,KAAK;;CAGd,YAAoC;AAClC,SAAO,KAAK"}
package/dist/start.mjs CHANGED
@@ -5,7 +5,7 @@ import { loadMotiaConfig } from "./load-motia-config.mjs";
5
5
  import { workbenchBase } from "./constants.mjs";
6
6
  import { processPlugins } from "./plugins/process-plugins.mjs";
7
7
  import "./plugins/index.mjs";
8
- import { getRedisClient, stopRedisConnection } from "./redis/connection.mjs";
8
+ import { getRedisClient, getRedisConnectionInfo, stopRedisConnection } from "./redis/connection.mjs";
9
9
  import { createServer } from "@motiadev/core";
10
10
  import path from "path";
11
11
  import { BullMQEventAdapter } from "@motiadev/adapter-bullmq-events";
@@ -27,12 +27,9 @@ const start = async (port, hostname, disableVerbose, motiaFileStorageDir) => {
27
27
  const motiaFileStoragePath = motiaFileStorageDir || ".motia";
28
28
  const dotMotia = path.join(baseDir, motiaFileStoragePath);
29
29
  const appConfig = await loadMotiaConfig(baseDir);
30
- const redisClient = await getRedisClient(dotMotia, appConfig, true);
30
+ const redisClient = await getRedisClient(dotMotia, appConfig);
31
31
  const adapters = {
32
- eventAdapter: appConfig.adapters?.events || new BullMQEventAdapter({ connection: {
33
- host: redisClient.options.socket?.host || "localhost",
34
- port: redisClient.options.socket?.port || 6379
35
- } }),
32
+ eventAdapter: appConfig.adapters?.events || new BullMQEventAdapter({ connection: getRedisConnectionInfo() }),
36
33
  cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),
37
34
  streamAdapter: appConfig.adapters?.streams || new RedisStreamAdapterManager(redisClient)
38
35
  };
@@ -1 +1 @@
1
- {"version":3,"file":"start.mjs","names":["redisClient: RedisClientType","plugins: MotiaPlugin[]"],"sources":["../src/start.ts"],"sourcesContent":["import { BullMQEventAdapter } from '@motiadev/adapter-bullmq-events'\nimport { RedisCronAdapter } from '@motiadev/adapter-redis-cron'\nimport { RedisStateAdapter } from '@motiadev/adapter-redis-state'\nimport { RedisStreamAdapterManager } from '@motiadev/adapter-redis-streams'\nimport { createServer, type MotiaPlugin } from '@motiadev/core'\nimport path from 'path'\nimport type { RedisClientType } from 'redis'\nimport { workbenchBase } from './constants'\nimport { generateLockedData, getStepFiles, getStreamFiles } from './generate-locked-data'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { processPlugins } from './plugins/index'\nimport { getRedisClient, stopRedisConnection } from './redis/connection'\nimport { activatePythonVenv } from './utils/activate-python-env'\nimport { version } from './version'\n\nexport const start = async (\n port: number,\n hostname: string,\n disableVerbose: boolean,\n motiaFileStorageDir?: string,\n): Promise<void> => {\n const baseDir = process.cwd()\n const isVerbose = !disableVerbose\n\n const stepFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)]\n const hasPythonFiles = stepFiles.some((file) => file.endsWith('.py'))\n\n if (hasPythonFiles) {\n console.log('⚙️ Activating Python environment...')\n activatePythonVenv({ baseDir, isVerbose })\n }\n\n const motiaFileStoragePath = motiaFileStorageDir || '.motia'\n\n const dotMotia = path.join(baseDir, motiaFileStoragePath)\n const appConfig = await loadMotiaConfig(baseDir)\n\n const redisClient: RedisClientType = await getRedisClient(dotMotia, appConfig, true)\n\n const adapters = {\n eventAdapter:\n appConfig.adapters?.events ||\n new BullMQEventAdapter({\n connection: {\n host: (redisClient.options.socket as { host?: string })?.host || 'localhost',\n port: (redisClient.options.socket as { port?: number })?.port || 6379,\n },\n }),\n cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),\n streamAdapter: appConfig.adapters?.streams || new RedisStreamAdapterManager(redisClient),\n }\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: adapters.streamAdapter,\n redisClient,\n streamAuth: appConfig.streamAuth,\n })\n\n const state = appConfig.adapters?.state || new RedisStateAdapter(redisClient)\n\n const config = { isVerbose, isDev: false, version }\n\n const motiaServer = createServer(lockedData, state, config, adapters, appConfig.app)\n const plugins: MotiaPlugin[] = await processPlugins(motiaServer)\n\n if (!process.env.MOTIA_DOCKER_DISABLE_WORKBENCH) {\n const { applyMiddleware } = await import('@motiadev/workbench/middleware')\n await applyMiddleware({\n app: motiaServer.app,\n port,\n workbenchBase,\n plugins: plugins.flatMap((item) => item.workbench),\n })\n }\n\n motiaServer.server.listen(port, hostname)\n console.log('🚀 Server ready and listening on port', port)\n console.log(`🔗 Open http://${hostname}:${port}${workbenchBase} to open workbench 🛠️`)\n\n process.on('SIGTERM', async () => {\n motiaServer.server.close()\n await stopRedisConnection()\n process.exit(0)\n })\n\n process.on('SIGINT', async () => {\n motiaServer.server.close()\n await stopRedisConnection()\n process.exit(0)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,QAAQ,OACnB,MACA,UACA,gBACA,wBACkB;CAClB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,YAAY,CAAC;AAKnB,KAHkB,CAAC,GAAG,aAAa,QAAQ,EAAE,GAAG,eAAe,QAAQ,CAAC,CACvC,MAAM,SAAS,KAAK,SAAS,MAAM,CAAC,EAEjD;AAClB,UAAQ,IAAI,sCAAsC;AAClD,qBAAmB;GAAE;GAAS;GAAW,CAAC;;CAG5C,MAAM,uBAAuB,uBAAuB;CAEpD,MAAM,WAAW,KAAK,KAAK,SAAS,qBAAqB;CACzD,MAAM,YAAY,MAAM,gBAAgB,QAAQ;CAEhD,MAAMA,cAA+B,MAAM,eAAe,UAAU,WAAW,KAAK;CAEpF,MAAM,WAAW;EACf,cACE,UAAU,UAAU,UACpB,IAAI,mBAAmB,EACrB,YAAY;GACV,MAAO,YAAY,QAAQ,QAA8B,QAAQ;GACjE,MAAO,YAAY,QAAQ,QAA8B,QAAQ;GAClE,EACF,CAAC;EACJ,aAAa,UAAU,UAAU,QAAQ,IAAI,iBAAiB,YAAY;EAC1E,eAAe,UAAU,UAAU,WAAW,IAAI,0BAA0B,YAAY;EACzF;CAYD,MAAM,cAAc,aAXD,MAAM,mBAAmB;EAC1C,YAAY;EACZ,eAAe,SAAS;EACxB;EACA,YAAY,UAAU;EACvB,CAAC,EAEY,UAAU,UAAU,SAAS,IAAI,kBAAkB,YAAY,EAE9D;EAAE;EAAW,OAAO;EAAO;EAAS,EAES,UAAU,UAAU,IAAI;CACpF,MAAMC,UAAyB,MAAM,eAAe,YAAY;AAEhE,KAAI,CAAC,QAAQ,IAAI,gCAAgC;EAC/C,MAAM,EAAE,oBAAoB,MAAM,OAAO;AACzC,QAAM,gBAAgB;GACpB,KAAK,YAAY;GACjB;GACA;GACA,SAAS,QAAQ,SAAS,SAAS,KAAK,UAAU;GACnD,CAAC;;AAGJ,aAAY,OAAO,OAAO,MAAM,SAAS;AACzC,SAAQ,IAAI,yCAAyC,KAAK;AAC1D,SAAQ,IAAI,kBAAkB,SAAS,GAAG,OAAO,cAAc,wBAAwB;AAEvF,SAAQ,GAAG,WAAW,YAAY;AAChC,cAAY,OAAO,OAAO;AAC1B,QAAM,qBAAqB;AAC3B,UAAQ,KAAK,EAAE;GACf;AAEF,SAAQ,GAAG,UAAU,YAAY;AAC/B,cAAY,OAAO,OAAO;AAC1B,QAAM,qBAAqB;AAC3B,UAAQ,KAAK,EAAE;GACf"}
1
+ {"version":3,"file":"start.mjs","names":["redisClient: RedisClientType","plugins: MotiaPlugin[]"],"sources":["../src/start.ts"],"sourcesContent":["import { BullMQEventAdapter } from '@motiadev/adapter-bullmq-events'\nimport { RedisCronAdapter } from '@motiadev/adapter-redis-cron'\nimport { RedisStateAdapter } from '@motiadev/adapter-redis-state'\nimport { RedisStreamAdapterManager } from '@motiadev/adapter-redis-streams'\nimport { createServer, type MotiaPlugin } from '@motiadev/core'\nimport path from 'path'\nimport type { RedisClientType } from 'redis'\nimport { workbenchBase } from './constants'\nimport { generateLockedData, getStepFiles, getStreamFiles } from './generate-locked-data'\nimport { loadMotiaConfig } from './load-motia-config'\nimport { processPlugins } from './plugins/index'\nimport { getRedisClient, getRedisConnectionInfo, stopRedisConnection } from './redis/connection'\nimport { activatePythonVenv } from './utils/activate-python-env'\nimport { version } from './version'\n\nexport const start = async (\n port: number,\n hostname: string,\n disableVerbose: boolean,\n motiaFileStorageDir?: string,\n): Promise<void> => {\n const baseDir = process.cwd()\n const isVerbose = !disableVerbose\n\n const stepFiles = [...getStepFiles(baseDir), ...getStreamFiles(baseDir)]\n const hasPythonFiles = stepFiles.some((file) => file.endsWith('.py'))\n\n if (hasPythonFiles) {\n console.log('⚙️ Activating Python environment...')\n activatePythonVenv({ baseDir, isVerbose })\n }\n\n const motiaFileStoragePath = motiaFileStorageDir || '.motia'\n\n const dotMotia = path.join(baseDir, motiaFileStoragePath)\n const appConfig = await loadMotiaConfig(baseDir)\n\n const redisClient: RedisClientType = await getRedisClient(dotMotia, appConfig)\n\n const adapters = {\n eventAdapter:\n appConfig.adapters?.events ||\n new BullMQEventAdapter({\n connection: getRedisConnectionInfo(),\n }),\n cronAdapter: appConfig.adapters?.cron || new RedisCronAdapter(redisClient),\n streamAdapter: appConfig.adapters?.streams || new RedisStreamAdapterManager(redisClient),\n }\n const lockedData = await generateLockedData({\n projectDir: baseDir,\n streamAdapter: adapters.streamAdapter,\n redisClient,\n streamAuth: appConfig.streamAuth,\n })\n\n const state = appConfig.adapters?.state || new RedisStateAdapter(redisClient)\n\n const config = { isVerbose, isDev: false, version }\n\n const motiaServer = createServer(lockedData, state, config, adapters, appConfig.app)\n const plugins: MotiaPlugin[] = await processPlugins(motiaServer)\n\n if (!process.env.MOTIA_DOCKER_DISABLE_WORKBENCH) {\n const { applyMiddleware } = await import('@motiadev/workbench/middleware')\n await applyMiddleware({\n app: motiaServer.app,\n port,\n workbenchBase,\n plugins: plugins.flatMap((item) => item.workbench),\n })\n }\n\n motiaServer.server.listen(port, hostname)\n console.log('🚀 Server ready and listening on port', port)\n console.log(`🔗 Open http://${hostname}:${port}${workbenchBase} to open workbench 🛠️`)\n\n process.on('SIGTERM', async () => {\n motiaServer.server.close()\n await stopRedisConnection()\n process.exit(0)\n })\n\n process.on('SIGINT', async () => {\n motiaServer.server.close()\n await stopRedisConnection()\n process.exit(0)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,QAAQ,OACnB,MACA,UACA,gBACA,wBACkB;CAClB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,YAAY,CAAC;AAKnB,KAHkB,CAAC,GAAG,aAAa,QAAQ,EAAE,GAAG,eAAe,QAAQ,CAAC,CACvC,MAAM,SAAS,KAAK,SAAS,MAAM,CAAC,EAEjD;AAClB,UAAQ,IAAI,sCAAsC;AAClD,qBAAmB;GAAE;GAAS;GAAW,CAAC;;CAG5C,MAAM,uBAAuB,uBAAuB;CAEpD,MAAM,WAAW,KAAK,KAAK,SAAS,qBAAqB;CACzD,MAAM,YAAY,MAAM,gBAAgB,QAAQ;CAEhD,MAAMA,cAA+B,MAAM,eAAe,UAAU,UAAU;CAE9E,MAAM,WAAW;EACf,cACE,UAAU,UAAU,UACpB,IAAI,mBAAmB,EACrB,YAAY,wBAAwB,EACrC,CAAC;EACJ,aAAa,UAAU,UAAU,QAAQ,IAAI,iBAAiB,YAAY;EAC1E,eAAe,UAAU,UAAU,WAAW,IAAI,0BAA0B,YAAY;EACzF;CAYD,MAAM,cAAc,aAXD,MAAM,mBAAmB;EAC1C,YAAY;EACZ,eAAe,SAAS;EACxB;EACA,YAAY,UAAU;EACvB,CAAC,EAEY,UAAU,UAAU,SAAS,IAAI,kBAAkB,YAAY,EAE9D;EAAE;EAAW,OAAO;EAAO;EAAS,EAES,UAAU,UAAU,IAAI;CACpF,MAAMC,UAAyB,MAAM,eAAe,YAAY;AAEhE,KAAI,CAAC,QAAQ,IAAI,gCAAgC;EAC/C,MAAM,EAAE,oBAAoB,MAAM,OAAO;AACzC,QAAM,gBAAgB;GACpB,KAAK,YAAY;GACjB;GACA;GACA,SAAS,QAAQ,SAAS,SAAS,KAAK,UAAU;GACnD,CAAC;;AAGJ,aAAY,OAAO,OAAO,MAAM,SAAS;AACzC,SAAQ,IAAI,yCAAyC,KAAK;AAC1D,SAAQ,IAAI,kBAAkB,SAAS,GAAG,OAAO,cAAc,wBAAwB;AAEvF,SAAQ,GAAG,WAAW,YAAY;AAChC,cAAY,OAAO,OAAO;AAC1B,QAAM,qBAAqB;AAC3B,UAAQ,KAAK,EAAE;GACf;AAEF,SAAQ,GAAG,UAAU,YAAY;AAC/B,cAAY,OAAO,OAAO;AAC1B,QAAM,qBAAqB;AAC3B,UAAQ,KAAK,EAAE;GACf"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "motia",
3
3
  "description": "Build production-grade backends with a single primitive. APIs, background jobs, Queues, Workflows, and AI agents - unified in one system with built-in State management, Streaming, and Observability.",
4
- "version": "0.15.4-beta.170-677191",
4
+ "version": "0.15.4-beta.170-888624",
5
5
  "license": "Elastic-2.0",
6
6
  "type": "module",
7
7
  "repository": {
@@ -46,13 +46,13 @@
46
46
  "table": "^6.9.0",
47
47
  "ts-node": "^10.9.2",
48
48
  "zod": "^4.1.12",
49
- "@motiadev/adapter-redis-cron": "0.15.4-beta.170-677191",
50
- "@motiadev/adapter-bullmq-events": "0.15.4-beta.170-677191",
51
- "@motiadev/adapter-redis-streams": "0.15.4-beta.170-677191",
52
- "@motiadev/adapter-redis-state": "0.15.4-beta.170-677191",
53
- "@motiadev/stream-client-node": "0.15.4-beta.170-677191",
54
- "@motiadev/core": "0.15.4-beta.170-677191",
55
- "@motiadev/workbench": "0.15.4-beta.170-677191"
49
+ "@motiadev/adapter-redis-state": "0.15.4-beta.170-888624",
50
+ "@motiadev/adapter-bullmq-events": "0.15.4-beta.170-888624",
51
+ "@motiadev/adapter-redis-streams": "0.15.4-beta.170-888624",
52
+ "@motiadev/core": "0.15.4-beta.170-888624",
53
+ "@motiadev/stream-client-node": "0.15.4-beta.170-888624",
54
+ "@motiadev/workbench": "0.15.4-beta.170-888624",
55
+ "@motiadev/adapter-redis-cron": "0.15.4-beta.170-888624"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@amplitude/analytics-types": "^2.9.2",