@walkeros/server-destination-redis 3.4.0-next-1776749829492
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -0
- package/dist/dev.d.mts +196 -0
- package/dist/dev.d.ts +196 -0
- package/dist/dev.js +1 -0
- package/dist/dev.js.map +1 -0
- package/dist/dev.mjs +1 -0
- package/dist/dev.mjs.map +1 -0
- package/dist/examples/index.d.mts +144 -0
- package/dist/examples/index.d.ts +144 -0
- package/dist/examples/index.js +146 -0
- package/dist/examples/index.mjs +124 -0
- package/dist/index.d.mts +133 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -0
- package/dist/walkerOS.json +611 -0
- package/package.json +76 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type {\n Destination,\n Settings,\n Env,\n RedisClientMock,\n RedisClientConstructor,\n RedisClientOptions,\n} from './types';\nimport { getConfig, isRedisEnv } from './config';\nimport { push } from './push';\n\n// Types re-export\nexport * as DestinationRedis from './types';\n\nexport const destinationRedis: Destination = {\n type: 'redis',\n\n config: {},\n\n async init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n const redis = settings.redis;\n\n // Skip creation if a client has already been wired in (testing).\n if (redis._client) return config;\n\n let Constructor: RedisClientConstructor | undefined;\n\n // Prefer env-injected constructor (testing, dependency injection).\n if (isRedisEnv(env)) {\n const envTyped = env as Env;\n Constructor = envTyped.Redis?.Client;\n }\n\n // Production path: load real ioredis SDK.\n if (!Constructor) {\n try {\n // Use dynamic require to allow tests to mock via jest.mock('ioredis').\n const ioredis = require('ioredis') as {\n default?: RedisClientConstructor;\n Redis?: RedisClientConstructor;\n };\n // ioredis exports the class as default (ESM) and as named Redis export.\n Constructor = ioredis.default ?? ioredis.Redis;\n } catch (err) {\n logger.throw(`Failed to load ioredis: ${String(err)}`);\n return config;\n }\n }\n\n if (!Constructor) {\n logger.throw('ioredis constructor not found');\n return config;\n }\n\n let client: RedisClientMock;\n if (redis.url) {\n client = new Constructor(redis.url);\n } else {\n client = new Constructor(redis.options ?? ({} as RedisClientOptions));\n }\n\n redis._client = client;\n redis._ownedClient = true;\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = config?.settings as Settings | undefined;\n const redis = settings?.redis;\n if (!redis) return;\n\n const client = redis._client;\n // Only close clients the destination created (not user-provided)\n if (client && redis._ownedClient) {\n try {\n await client.quit();\n } finally {\n redis._client = undefined;\n redis._ownedClient = undefined;\n }\n }\n },\n};\n\nexport default destinationRedis;\n","import type {\n Config,\n Settings,\n RedisSettings,\n PartialConfig,\n Env,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const raw = (partialConfig.settings ?? {}) as Partial<Settings>;\n const redis: Partial<RedisSettings> =\n raw.redis ?? ({} as Partial<RedisSettings>);\n\n if (!redis.streamKey) {\n logger.throw('Config settings redis.streamKey missing');\n }\n\n const redisSettings: RedisSettings = {\n ...redis,\n streamKey: redis.streamKey as string,\n serialization: redis.serialization ?? 'json',\n };\n\n const settings: Settings = { redis: redisSettings };\n\n return { ...partialConfig, settings };\n}\n\nexport function isRedisEnv(env: unknown): env is Env {\n if (!isObject(env)) return false;\n const maybe = env as { Redis?: { Client?: unknown } };\n return typeof maybe.Redis?.Client === 'function';\n}\n","import type {\n PushFn,\n RedisSettings,\n RedisClientMock,\n XaddArg,\n SerializationMode,\n} from './types';\nimport { isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (event, { config, rule, logger }) {\n const settings = config.settings as { redis?: RedisSettings } | undefined;\n const redis: RedisSettings | undefined = settings?.redis;\n\n if (!redis) {\n logger.warn('Redis settings missing');\n return;\n }\n\n const client = redis._client;\n if (!client) {\n logger.warn('Redis client not initialized');\n return;\n }\n\n // Derive stream key: rule override -> destination default\n const ruleSettings = rule?.settings ?? {};\n const streamKey = isString(ruleSettings.streamKey)\n ? ruleSettings.streamKey\n : redis.streamKey;\n\n const serialization: SerializationMode = redis.serialization ?? 'json';\n\n // Serialize event\n const fields: string[] =\n serialization === 'flat'\n ? flattenEvent(event as unknown as Record<string, unknown>)\n : ['event', JSON.stringify(event)];\n\n // Build XADD arguments\n const args: XaddArg[] = [streamKey];\n\n // Optional MAXLEN trimming\n if (redis.maxLen) {\n args.push('MAXLEN');\n if (!redis.exactTrimming) args.push('~');\n args.push(redis.maxLen);\n }\n\n args.push('*'); // Auto-generate entry ID\n args.push(...fields); // Field-value pairs\n\n logger.debug('Redis XADD', { stream: streamKey });\n\n try {\n const entryId = await (client as RedisClientMock).xadd(...args);\n logger.debug('Redis XADD complete', { stream: streamKey, entryId });\n } catch (error) {\n logger.error('Redis XADD failed', {\n stream: streamKey,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n};\n\nfunction flattenEvent(event: Record<string, unknown>): string[] {\n const fields: string[] = [];\n for (const [key, value] of Object.entries(event)) {\n fields.push(\n key,\n typeof value === 'object' && value !== null\n ? JSON.stringify(value)\n : String(value),\n );\n }\n return fields;\n}\n","import type { Destination as CoreDestination } from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/**\n * Arguments passed to Redis XADD. Strings or numbers (for MAXLEN counts).\n */\nexport type XaddArg = string | number;\n\n/**\n * Mock-friendly Redis pipeline interface. Accumulates commands and\n * executes them with a single round-trip via exec().\n */\nexport interface RedisPipelineMock {\n xadd: (...args: XaddArg[]) => RedisPipelineMock;\n exec: () => Promise<Array<[Error | null, unknown]> | null>;\n}\n\n/**\n * Mock-friendly Redis client interface used by the destination.\n * Tests provide this via env.Redis; production creates a real ioredis\n * client and uses it directly.\n */\nexport interface RedisClientMock {\n xadd: (...args: XaddArg[]) => Promise<string | null>;\n pipeline: () => RedisPipelineMock;\n quit: () => Promise<string>;\n on?: (event: string, listener: (...args: unknown[]) => void) => unknown;\n}\n\n/**\n * Constructor signature for the Redis client. Accepts either a URL\n * string or an options object, matching ioredis's dual signature.\n */\nexport interface RedisClientConstructor {\n new (url: string): RedisClientMock;\n new (options: RedisClientOptions): RedisClientMock;\n}\n\n/**\n * Minimal ioredis options subset the destination passes through.\n * Unknown options are preserved for the SDK to handle.\n */\nexport interface RedisClientOptions {\n host?: string;\n port?: number;\n username?: string;\n password?: string;\n db?: number;\n tls?: boolean | Record<string, unknown>;\n connectTimeout?: number;\n commandTimeout?: number;\n [key: string]: unknown;\n}\n\nexport type SerializationMode = 'json' | 'flat';\n\nexport interface RedisSettings {\n /** Redis stream key name (e.g. 'walkeros:events'). */\n streamKey: string;\n /** Redis connection URL (e.g. 'redis://localhost:6379' or 'rediss://...'). */\n url?: string;\n /** ioredis connection options (used if no url provided). */\n options?: RedisClientOptions;\n /**\n * Maximum stream length. Enables MAXLEN trimming on every XADD.\n * Uses approximate (~) trimming by default for performance.\n * Omit for unlimited stream length.\n */\n maxLen?: number;\n /**\n * Use exact MAXLEN instead of approximate (~).\n * Not recommended for production -- significantly slower.\n * Default: false (approximate trimming).\n */\n exactTrimming?: boolean;\n /**\n * Serialization mode for the event payload.\n * - 'json': Single 'event' field with JSON string (default)\n * - 'flat': Top-level event fields as separate stream fields\n */\n serialization?: SerializationMode;\n\n // Runtime -- set during init, not user-facing\n _client?: RedisClientMock;\n _ownedClient?: boolean;\n}\n\nexport interface Settings {\n redis: RedisSettings;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Override stream key for this rule. */\n streamKey?: string;\n}\n\n/**\n * Env -- optional Redis SDK override. Production leaves this undefined\n * and the destination creates real ioredis client instances. Tests provide\n * mocks via env.Redis.\n */\nexport interface Env extends DestinationServer.Env {\n Redis?: {\n Client: RedisClientConstructor;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n"],"mappings":"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","names":["import_core"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=(e=>"undefined"!=typeof require?require:"undefined"!=typeof Proxy?new Proxy(e,{get:(e,i)=>("undefined"!=typeof require?require:e)[i]}):e)(function(e){if("undefined"!=typeof require)return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});import{isObject as i}from"@walkeros/core";import{isString as n}from"@walkeros/core";var t=async function(e,{config:i,rule:t,logger:r}){var s,o;const l=i.settings,u=null==l?void 0:l.redis;if(!u)return void r.warn("Redis settings missing");const a=u._client;if(!a)return void r.warn("Redis client not initialized");const d=null!=(s=null==t?void 0:t.settings)?s:{},c=n(d.streamKey)?d.streamKey:u.streamKey,f="flat"===(null!=(o=u.serialization)?o:"json")?function(e){const i=[];for(const[n,t]of Object.entries(e))i.push(n,"object"==typeof t&&null!==t?JSON.stringify(t):String(t));return i}(e):["event",JSON.stringify(e)],y=[c];u.maxLen&&(y.push("MAXLEN"),u.exactTrimming||y.push("~"),y.push(u.maxLen)),y.push("*"),y.push(...f),r.debug("Redis XADD",{stream:c});try{const e=await a.xadd(...y);r.debug("Redis XADD complete",{stream:c,entryId:e})}catch(e){r.error("Redis XADD failed",{stream:c,error:e instanceof Error?e.message:String(e)})}};var r={},s={type:"redis",config:{},async init({config:n,logger:t,env:r}){var s,o,l;const u=function(e={},i){var n,t,r;const s=null!=(t=(null!=(n=e.settings)?n:{}).redis)?t:{};s.streamKey||i.throw("Config settings redis.streamKey missing");const o={redis:{...s,streamKey:s.streamKey,serialization:null!=(r=s.serialization)?r:"json"}};return{...e,settings:o}}(n,t),a=u.settings.redis;if(a._client)return u;let d,c;if(function(e){var n;return!!i(e)&&"function"==typeof(null==(n=e.Redis)?void 0:n.Client)}(r)){d=null==(s=r.Redis)?void 0:s.Client}if(!d)try{const i=e("ioredis");d=null!=(o=i.default)?o:i.Redis}catch(e){return t.throw(`Failed to load ioredis: ${String(e)}`),u}return d?(c=a.url?new d(a.url):new d(null!=(l=a.options)?l:{}),a._client=c,a._ownedClient=!0,u):(t.throw("ioredis constructor not found"),u)},push:async(e,i)=>await t(e,i),async destroy({config:e}){const i=null==e?void 0:e.settings,n=null==i?void 0:i.redis;if(!n)return;const t=n._client;if(t&&n._ownedClient)try{await t.quit()}finally{n._client=void 0,n._ownedClient=void 0}}},o=s;export{r as DestinationRedis,o as default,s as destinationRedis};//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type {\n Config,\n Settings,\n RedisSettings,\n PartialConfig,\n Env,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const raw = (partialConfig.settings ?? {}) as Partial<Settings>;\n const redis: Partial<RedisSettings> =\n raw.redis ?? ({} as Partial<RedisSettings>);\n\n if (!redis.streamKey) {\n logger.throw('Config settings redis.streamKey missing');\n }\n\n const redisSettings: RedisSettings = {\n ...redis,\n streamKey: redis.streamKey as string,\n serialization: redis.serialization ?? 'json',\n };\n\n const settings: Settings = { redis: redisSettings };\n\n return { ...partialConfig, settings };\n}\n\nexport function isRedisEnv(env: unknown): env is Env {\n if (!isObject(env)) return false;\n const maybe = env as { Redis?: { Client?: unknown } };\n return typeof maybe.Redis?.Client === 'function';\n}\n","import type {\n PushFn,\n RedisSettings,\n RedisClientMock,\n XaddArg,\n SerializationMode,\n} from './types';\nimport { isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (event, { config, rule, logger }) {\n const settings = config.settings as { redis?: RedisSettings } | undefined;\n const redis: RedisSettings | undefined = settings?.redis;\n\n if (!redis) {\n logger.warn('Redis settings missing');\n return;\n }\n\n const client = redis._client;\n if (!client) {\n logger.warn('Redis client not initialized');\n return;\n }\n\n // Derive stream key: rule override -> destination default\n const ruleSettings = rule?.settings ?? {};\n const streamKey = isString(ruleSettings.streamKey)\n ? ruleSettings.streamKey\n : redis.streamKey;\n\n const serialization: SerializationMode = redis.serialization ?? 'json';\n\n // Serialize event\n const fields: string[] =\n serialization === 'flat'\n ? flattenEvent(event as unknown as Record<string, unknown>)\n : ['event', JSON.stringify(event)];\n\n // Build XADD arguments\n const args: XaddArg[] = [streamKey];\n\n // Optional MAXLEN trimming\n if (redis.maxLen) {\n args.push('MAXLEN');\n if (!redis.exactTrimming) args.push('~');\n args.push(redis.maxLen);\n }\n\n args.push('*'); // Auto-generate entry ID\n args.push(...fields); // Field-value pairs\n\n logger.debug('Redis XADD', { stream: streamKey });\n\n try {\n const entryId = await (client as RedisClientMock).xadd(...args);\n logger.debug('Redis XADD complete', { stream: streamKey, entryId });\n } catch (error) {\n logger.error('Redis XADD failed', {\n stream: streamKey,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n};\n\nfunction flattenEvent(event: Record<string, unknown>): string[] {\n const fields: string[] = [];\n for (const [key, value] of Object.entries(event)) {\n fields.push(\n key,\n typeof value === 'object' && value !== null\n ? JSON.stringify(value)\n : String(value),\n );\n }\n return fields;\n}\n","import type { Destination as CoreDestination } from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/**\n * Arguments passed to Redis XADD. Strings or numbers (for MAXLEN counts).\n */\nexport type XaddArg = string | number;\n\n/**\n * Mock-friendly Redis pipeline interface. Accumulates commands and\n * executes them with a single round-trip via exec().\n */\nexport interface RedisPipelineMock {\n xadd: (...args: XaddArg[]) => RedisPipelineMock;\n exec: () => Promise<Array<[Error | null, unknown]> | null>;\n}\n\n/**\n * Mock-friendly Redis client interface used by the destination.\n * Tests provide this via env.Redis; production creates a real ioredis\n * client and uses it directly.\n */\nexport interface RedisClientMock {\n xadd: (...args: XaddArg[]) => Promise<string | null>;\n pipeline: () => RedisPipelineMock;\n quit: () => Promise<string>;\n on?: (event: string, listener: (...args: unknown[]) => void) => unknown;\n}\n\n/**\n * Constructor signature for the Redis client. Accepts either a URL\n * string or an options object, matching ioredis's dual signature.\n */\nexport interface RedisClientConstructor {\n new (url: string): RedisClientMock;\n new (options: RedisClientOptions): RedisClientMock;\n}\n\n/**\n * Minimal ioredis options subset the destination passes through.\n * Unknown options are preserved for the SDK to handle.\n */\nexport interface RedisClientOptions {\n host?: string;\n port?: number;\n username?: string;\n password?: string;\n db?: number;\n tls?: boolean | Record<string, unknown>;\n connectTimeout?: number;\n commandTimeout?: number;\n [key: string]: unknown;\n}\n\nexport type SerializationMode = 'json' | 'flat';\n\nexport interface RedisSettings {\n /** Redis stream key name (e.g. 'walkeros:events'). */\n streamKey: string;\n /** Redis connection URL (e.g. 'redis://localhost:6379' or 'rediss://...'). */\n url?: string;\n /** ioredis connection options (used if no url provided). */\n options?: RedisClientOptions;\n /**\n * Maximum stream length. Enables MAXLEN trimming on every XADD.\n * Uses approximate (~) trimming by default for performance.\n * Omit for unlimited stream length.\n */\n maxLen?: number;\n /**\n * Use exact MAXLEN instead of approximate (~).\n * Not recommended for production -- significantly slower.\n * Default: false (approximate trimming).\n */\n exactTrimming?: boolean;\n /**\n * Serialization mode for the event payload.\n * - 'json': Single 'event' field with JSON string (default)\n * - 'flat': Top-level event fields as separate stream fields\n */\n serialization?: SerializationMode;\n\n // Runtime -- set during init, not user-facing\n _client?: RedisClientMock;\n _ownedClient?: boolean;\n}\n\nexport interface Settings {\n redis: RedisSettings;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Override stream key for this rule. */\n streamKey?: string;\n}\n\n/**\n * Env -- optional Redis SDK override. Production leaves this undefined\n * and the destination creates real ioredis client instances. Tests provide\n * mocks via env.Redis.\n */\nexport interface Env extends DestinationServer.Env {\n Redis?: {\n Client: RedisClientConstructor;\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n","import type {\n Destination,\n Settings,\n Env,\n RedisClientMock,\n RedisClientConstructor,\n RedisClientOptions,\n} from './types';\nimport { getConfig, isRedisEnv } from './config';\nimport { push } from './push';\n\n// Types re-export\nexport * as DestinationRedis from './types';\n\nexport const destinationRedis: Destination = {\n type: 'redis',\n\n config: {},\n\n async init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n const redis = settings.redis;\n\n // Skip creation if a client has already been wired in (testing).\n if (redis._client) return config;\n\n let Constructor: RedisClientConstructor | undefined;\n\n // Prefer env-injected constructor (testing, dependency injection).\n if (isRedisEnv(env)) {\n const envTyped = env as Env;\n Constructor = envTyped.Redis?.Client;\n }\n\n // Production path: load real ioredis SDK.\n if (!Constructor) {\n try {\n // Use dynamic require to allow tests to mock via jest.mock('ioredis').\n const ioredis = require('ioredis') as {\n default?: RedisClientConstructor;\n Redis?: RedisClientConstructor;\n };\n // ioredis exports the class as default (ESM) and as named Redis export.\n Constructor = ioredis.default ?? ioredis.Redis;\n } catch (err) {\n logger.throw(`Failed to load ioredis: ${String(err)}`);\n return config;\n }\n }\n\n if (!Constructor) {\n logger.throw('ioredis constructor not found');\n return config;\n }\n\n let client: RedisClientMock;\n if (redis.url) {\n client = new Constructor(redis.url);\n } else {\n client = new Constructor(redis.options ?? ({} as RedisClientOptions));\n }\n\n redis._client = client;\n redis._ownedClient = true;\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = config?.settings as Settings | undefined;\n const redis = settings?.redis;\n if (!redis) return;\n\n const client = redis._client;\n // Only close clients the destination created (not user-provided)\n if (client && redis._ownedClient) {\n try {\n await client.quit();\n } finally {\n redis._client = undefined;\n redis._ownedClient = undefined;\n }\n }\n },\n};\n\nexport default destinationRedis;\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$meta": {
|
|
3
|
+
"package": "@walkeros/server-destination-redis",
|
|
4
|
+
"version": "3.4.0-next-1776749829492",
|
|
5
|
+
"type": "destination",
|
|
6
|
+
"platform": [
|
|
7
|
+
"server"
|
|
8
|
+
],
|
|
9
|
+
"docs": "https://www.walkeros.io/docs/destinations/server/redis",
|
|
10
|
+
"source": "https://github.com/elbwalker/walkerOS/tree/main/packages/server/destinations/redis/src"
|
|
11
|
+
},
|
|
12
|
+
"schemas": {
|
|
13
|
+
"mapping": {
|
|
14
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
15
|
+
"type": "object",
|
|
16
|
+
"properties": {
|
|
17
|
+
"streamKey": {
|
|
18
|
+
"description": "Override Redis stream key for this rule. Takes precedence over settings.redis.streamKey.",
|
|
19
|
+
"type": "string"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"additionalProperties": false
|
|
23
|
+
},
|
|
24
|
+
"settings": {
|
|
25
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
26
|
+
"type": "object",
|
|
27
|
+
"properties": {
|
|
28
|
+
"redis": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"properties": {
|
|
31
|
+
"streamKey": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"minLength": 1,
|
|
34
|
+
"description": "Redis stream key name (like 'walkeros:events'). All events are appended to this stream via XADD."
|
|
35
|
+
},
|
|
36
|
+
"url": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Redis connection URL (like 'redis://localhost:6379' or 'rediss://:password@host:6380'). Supports redis:// and rediss:// (TLS) protocols."
|
|
39
|
+
},
|
|
40
|
+
"options": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"propertyNames": {
|
|
43
|
+
"type": "string"
|
|
44
|
+
},
|
|
45
|
+
"additionalProperties": {},
|
|
46
|
+
"description": "ioredis connection options. Used when url is not provided. Supports host, port, password, db, tls, and all other ioredis options."
|
|
47
|
+
},
|
|
48
|
+
"maxLen": {
|
|
49
|
+
"type": "integer",
|
|
50
|
+
"exclusiveMinimum": 0,
|
|
51
|
+
"maximum": 9007199254740991,
|
|
52
|
+
"description": "Maximum stream length. Enables approximate MAXLEN trimming on every XADD to bound memory usage (like 50000)."
|
|
53
|
+
},
|
|
54
|
+
"exactTrimming": {
|
|
55
|
+
"type": "boolean",
|
|
56
|
+
"description": "Use exact MAXLEN instead of approximate (~). Not recommended for production. Default: false."
|
|
57
|
+
},
|
|
58
|
+
"serialization": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"enum": [
|
|
61
|
+
"json",
|
|
62
|
+
"flat"
|
|
63
|
+
],
|
|
64
|
+
"description": "Serialization mode. 'json' stores the full event as a single 'event' field (default). 'flat' stores top-level event fields as separate stream entry fields."
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"required": [
|
|
68
|
+
"streamKey"
|
|
69
|
+
],
|
|
70
|
+
"additionalProperties": false,
|
|
71
|
+
"description": "Redis Streams configuration (like { streamKey: 'walkeros:events', url: 'redis://localhost:6379' })"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"required": [
|
|
75
|
+
"redis"
|
|
76
|
+
],
|
|
77
|
+
"additionalProperties": false
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"examples": {
|
|
81
|
+
"env": {
|
|
82
|
+
"push": {
|
|
83
|
+
"Redis": {
|
|
84
|
+
"Client": {
|
|
85
|
+
"$code": "class{constructor(e){this.xadd=v,this.quit=u}pipeline(){return function(){const e={xadd:()=>e,exec:()=>Promise.resolve([])};return e}()}on(){return this}}"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"simulation": [
|
|
90
|
+
"call:client.xadd"
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
"step": {
|
|
94
|
+
"ignoredEvent": {
|
|
95
|
+
"in": {
|
|
96
|
+
"name": "debug noise",
|
|
97
|
+
"data": {
|
|
98
|
+
"string": "foo",
|
|
99
|
+
"number": 1,
|
|
100
|
+
"boolean": true,
|
|
101
|
+
"array": [
|
|
102
|
+
0,
|
|
103
|
+
"text",
|
|
104
|
+
false
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"context": {
|
|
108
|
+
"dev": [
|
|
109
|
+
"test",
|
|
110
|
+
1
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
"globals": {
|
|
114
|
+
"lang": "elb"
|
|
115
|
+
},
|
|
116
|
+
"custom": {
|
|
117
|
+
"completely": "random"
|
|
118
|
+
},
|
|
119
|
+
"user": {
|
|
120
|
+
"id": "us3r",
|
|
121
|
+
"device": "c00k13",
|
|
122
|
+
"session": "s3ss10n"
|
|
123
|
+
},
|
|
124
|
+
"nested": [
|
|
125
|
+
{
|
|
126
|
+
"entity": "child",
|
|
127
|
+
"data": {
|
|
128
|
+
"is": "subordinated"
|
|
129
|
+
},
|
|
130
|
+
"nested": [],
|
|
131
|
+
"context": {
|
|
132
|
+
"element": [
|
|
133
|
+
"child",
|
|
134
|
+
0
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
"consent": {
|
|
140
|
+
"functional": true
|
|
141
|
+
},
|
|
142
|
+
"id": "1700000105-gr0up-1",
|
|
143
|
+
"trigger": "test",
|
|
144
|
+
"entity": "debug",
|
|
145
|
+
"action": "noise",
|
|
146
|
+
"timestamp": 1700000105,
|
|
147
|
+
"timing": 3.14,
|
|
148
|
+
"group": "gr0up",
|
|
149
|
+
"count": 1,
|
|
150
|
+
"version": {
|
|
151
|
+
"source": "3.4.0-next-1776749829492",
|
|
152
|
+
"tagging": 1
|
|
153
|
+
},
|
|
154
|
+
"source": {
|
|
155
|
+
"type": "web",
|
|
156
|
+
"id": "https://localhost:80",
|
|
157
|
+
"previous_id": "http://remotehost:9001"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"mapping": {
|
|
161
|
+
"ignore": true
|
|
162
|
+
},
|
|
163
|
+
"out": []
|
|
164
|
+
},
|
|
165
|
+
"jsonDefault": {
|
|
166
|
+
"in": {
|
|
167
|
+
"name": "page view",
|
|
168
|
+
"data": {
|
|
169
|
+
"domain": "www.example.com",
|
|
170
|
+
"title": "walkerOS documentation",
|
|
171
|
+
"referrer": "https://www.walkeros.io/",
|
|
172
|
+
"search": "?foo=bar",
|
|
173
|
+
"hash": "#hash",
|
|
174
|
+
"id": "/docs/"
|
|
175
|
+
},
|
|
176
|
+
"context": {
|
|
177
|
+
"dev": [
|
|
178
|
+
"test",
|
|
179
|
+
1
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
"globals": {
|
|
183
|
+
"pagegroup": "docs"
|
|
184
|
+
},
|
|
185
|
+
"custom": {
|
|
186
|
+
"completely": "random"
|
|
187
|
+
},
|
|
188
|
+
"user": {
|
|
189
|
+
"id": "us3r",
|
|
190
|
+
"device": "c00k13",
|
|
191
|
+
"session": "s3ss10n"
|
|
192
|
+
},
|
|
193
|
+
"nested": [
|
|
194
|
+
{
|
|
195
|
+
"entity": "child",
|
|
196
|
+
"data": {
|
|
197
|
+
"is": "subordinated"
|
|
198
|
+
},
|
|
199
|
+
"nested": [],
|
|
200
|
+
"context": {
|
|
201
|
+
"element": [
|
|
202
|
+
"child",
|
|
203
|
+
0
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
"consent": {
|
|
209
|
+
"functional": true
|
|
210
|
+
},
|
|
211
|
+
"id": "1700000100-gr0up-1",
|
|
212
|
+
"trigger": "load",
|
|
213
|
+
"entity": "page",
|
|
214
|
+
"action": "view",
|
|
215
|
+
"timestamp": 1700000100,
|
|
216
|
+
"timing": 3.14,
|
|
217
|
+
"group": "gr0up",
|
|
218
|
+
"count": 1,
|
|
219
|
+
"version": {
|
|
220
|
+
"source": "3.4.0-next-1776749829492",
|
|
221
|
+
"tagging": 1
|
|
222
|
+
},
|
|
223
|
+
"source": {
|
|
224
|
+
"type": "web",
|
|
225
|
+
"id": "https://localhost:80",
|
|
226
|
+
"previous_id": "http://remotehost:9001"
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"out": [
|
|
230
|
+
[
|
|
231
|
+
"client.xadd",
|
|
232
|
+
[
|
|
233
|
+
"walkeros:events",
|
|
234
|
+
"*",
|
|
235
|
+
"event",
|
|
236
|
+
"json:event"
|
|
237
|
+
]
|
|
238
|
+
]
|
|
239
|
+
]
|
|
240
|
+
},
|
|
241
|
+
"orderComplete": {
|
|
242
|
+
"in": {
|
|
243
|
+
"name": "order complete",
|
|
244
|
+
"data": {
|
|
245
|
+
"id": "ORD-400",
|
|
246
|
+
"total": 99.99,
|
|
247
|
+
"currency": "EUR"
|
|
248
|
+
},
|
|
249
|
+
"context": {
|
|
250
|
+
"shopping": [
|
|
251
|
+
"complete",
|
|
252
|
+
0
|
|
253
|
+
]
|
|
254
|
+
},
|
|
255
|
+
"globals": {
|
|
256
|
+
"pagegroup": "shop"
|
|
257
|
+
},
|
|
258
|
+
"custom": {
|
|
259
|
+
"completely": "random"
|
|
260
|
+
},
|
|
261
|
+
"user": {
|
|
262
|
+
"id": "us3r",
|
|
263
|
+
"device": "c00k13",
|
|
264
|
+
"session": "s3ss10n"
|
|
265
|
+
},
|
|
266
|
+
"nested": [
|
|
267
|
+
{
|
|
268
|
+
"entity": "product",
|
|
269
|
+
"data": {
|
|
270
|
+
"id": "ers",
|
|
271
|
+
"name": "Everyday Ruck Snack",
|
|
272
|
+
"color": "black",
|
|
273
|
+
"size": "l",
|
|
274
|
+
"price": 420
|
|
275
|
+
},
|
|
276
|
+
"context": {
|
|
277
|
+
"shopping": [
|
|
278
|
+
"complete",
|
|
279
|
+
0
|
|
280
|
+
]
|
|
281
|
+
},
|
|
282
|
+
"nested": []
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"entity": "product",
|
|
286
|
+
"data": {
|
|
287
|
+
"id": "cc",
|
|
288
|
+
"name": "Cool Cap",
|
|
289
|
+
"size": "one size",
|
|
290
|
+
"price": 42
|
|
291
|
+
},
|
|
292
|
+
"context": {
|
|
293
|
+
"shopping": [
|
|
294
|
+
"complete",
|
|
295
|
+
0
|
|
296
|
+
]
|
|
297
|
+
},
|
|
298
|
+
"nested": []
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"entity": "gift",
|
|
302
|
+
"data": {
|
|
303
|
+
"name": "Surprise"
|
|
304
|
+
},
|
|
305
|
+
"context": {
|
|
306
|
+
"shopping": [
|
|
307
|
+
"complete",
|
|
308
|
+
0
|
|
309
|
+
]
|
|
310
|
+
},
|
|
311
|
+
"nested": []
|
|
312
|
+
}
|
|
313
|
+
],
|
|
314
|
+
"consent": {
|
|
315
|
+
"functional": true
|
|
316
|
+
},
|
|
317
|
+
"id": "1700000101-gr0up-1",
|
|
318
|
+
"trigger": "load",
|
|
319
|
+
"entity": "order",
|
|
320
|
+
"action": "complete",
|
|
321
|
+
"timestamp": 1700000101,
|
|
322
|
+
"timing": 3.14,
|
|
323
|
+
"group": "gr0up",
|
|
324
|
+
"count": 1,
|
|
325
|
+
"version": {
|
|
326
|
+
"source": "3.4.0-next-1776749829492",
|
|
327
|
+
"tagging": 1
|
|
328
|
+
},
|
|
329
|
+
"source": {
|
|
330
|
+
"type": "web",
|
|
331
|
+
"id": "https://localhost:80",
|
|
332
|
+
"previous_id": "http://remotehost:9001"
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
"out": [
|
|
336
|
+
[
|
|
337
|
+
"client.xadd",
|
|
338
|
+
[
|
|
339
|
+
"walkeros:events",
|
|
340
|
+
"*",
|
|
341
|
+
"event",
|
|
342
|
+
"json:event"
|
|
343
|
+
]
|
|
344
|
+
]
|
|
345
|
+
]
|
|
346
|
+
},
|
|
347
|
+
"streamKeyOverride": {
|
|
348
|
+
"in": {
|
|
349
|
+
"name": "order complete",
|
|
350
|
+
"data": {
|
|
351
|
+
"id": "ORD-500",
|
|
352
|
+
"total": 42
|
|
353
|
+
},
|
|
354
|
+
"context": {
|
|
355
|
+
"shopping": [
|
|
356
|
+
"complete",
|
|
357
|
+
0
|
|
358
|
+
]
|
|
359
|
+
},
|
|
360
|
+
"globals": {
|
|
361
|
+
"pagegroup": "shop"
|
|
362
|
+
},
|
|
363
|
+
"custom": {
|
|
364
|
+
"completely": "random"
|
|
365
|
+
},
|
|
366
|
+
"user": {
|
|
367
|
+
"id": "us3r",
|
|
368
|
+
"device": "c00k13",
|
|
369
|
+
"session": "s3ss10n"
|
|
370
|
+
},
|
|
371
|
+
"nested": [
|
|
372
|
+
{
|
|
373
|
+
"entity": "product",
|
|
374
|
+
"data": {
|
|
375
|
+
"id": "ers",
|
|
376
|
+
"name": "Everyday Ruck Snack",
|
|
377
|
+
"color": "black",
|
|
378
|
+
"size": "l",
|
|
379
|
+
"price": 420
|
|
380
|
+
},
|
|
381
|
+
"context": {
|
|
382
|
+
"shopping": [
|
|
383
|
+
"complete",
|
|
384
|
+
0
|
|
385
|
+
]
|
|
386
|
+
},
|
|
387
|
+
"nested": []
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"entity": "product",
|
|
391
|
+
"data": {
|
|
392
|
+
"id": "cc",
|
|
393
|
+
"name": "Cool Cap",
|
|
394
|
+
"size": "one size",
|
|
395
|
+
"price": 42
|
|
396
|
+
},
|
|
397
|
+
"context": {
|
|
398
|
+
"shopping": [
|
|
399
|
+
"complete",
|
|
400
|
+
0
|
|
401
|
+
]
|
|
402
|
+
},
|
|
403
|
+
"nested": []
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"entity": "gift",
|
|
407
|
+
"data": {
|
|
408
|
+
"name": "Surprise"
|
|
409
|
+
},
|
|
410
|
+
"context": {
|
|
411
|
+
"shopping": [
|
|
412
|
+
"complete",
|
|
413
|
+
0
|
|
414
|
+
]
|
|
415
|
+
},
|
|
416
|
+
"nested": []
|
|
417
|
+
}
|
|
418
|
+
],
|
|
419
|
+
"consent": {
|
|
420
|
+
"functional": true
|
|
421
|
+
},
|
|
422
|
+
"id": "1700000104-gr0up-1",
|
|
423
|
+
"trigger": "load",
|
|
424
|
+
"entity": "order",
|
|
425
|
+
"action": "complete",
|
|
426
|
+
"timestamp": 1700000104,
|
|
427
|
+
"timing": 3.14,
|
|
428
|
+
"group": "gr0up",
|
|
429
|
+
"count": 1,
|
|
430
|
+
"version": {
|
|
431
|
+
"source": "3.4.0-next-1776749829492",
|
|
432
|
+
"tagging": 1
|
|
433
|
+
},
|
|
434
|
+
"source": {
|
|
435
|
+
"type": "web",
|
|
436
|
+
"id": "https://localhost:80",
|
|
437
|
+
"previous_id": "http://remotehost:9001"
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
"mapping": {
|
|
441
|
+
"settings": {
|
|
442
|
+
"streamKey": "walkeros:orders"
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
"out": [
|
|
446
|
+
[
|
|
447
|
+
"client.xadd",
|
|
448
|
+
[
|
|
449
|
+
"walkeros:orders",
|
|
450
|
+
"*",
|
|
451
|
+
"event",
|
|
452
|
+
"json:event"
|
|
453
|
+
]
|
|
454
|
+
]
|
|
455
|
+
]
|
|
456
|
+
},
|
|
457
|
+
"withExactTrim": {
|
|
458
|
+
"in": {
|
|
459
|
+
"name": "page view",
|
|
460
|
+
"data": {
|
|
461
|
+
"domain": "www.example.com",
|
|
462
|
+
"title": "walkerOS documentation",
|
|
463
|
+
"referrer": "https://www.walkeros.io/",
|
|
464
|
+
"search": "?foo=bar",
|
|
465
|
+
"hash": "#hash",
|
|
466
|
+
"id": "/docs/"
|
|
467
|
+
},
|
|
468
|
+
"context": {
|
|
469
|
+
"dev": [
|
|
470
|
+
"test",
|
|
471
|
+
1
|
|
472
|
+
]
|
|
473
|
+
},
|
|
474
|
+
"globals": {
|
|
475
|
+
"pagegroup": "docs"
|
|
476
|
+
},
|
|
477
|
+
"custom": {
|
|
478
|
+
"completely": "random"
|
|
479
|
+
},
|
|
480
|
+
"user": {
|
|
481
|
+
"id": "us3r",
|
|
482
|
+
"device": "c00k13",
|
|
483
|
+
"session": "s3ss10n"
|
|
484
|
+
},
|
|
485
|
+
"nested": [
|
|
486
|
+
{
|
|
487
|
+
"entity": "child",
|
|
488
|
+
"data": {
|
|
489
|
+
"is": "subordinated"
|
|
490
|
+
},
|
|
491
|
+
"nested": [],
|
|
492
|
+
"context": {
|
|
493
|
+
"element": [
|
|
494
|
+
"child",
|
|
495
|
+
0
|
|
496
|
+
]
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
],
|
|
500
|
+
"consent": {
|
|
501
|
+
"functional": true
|
|
502
|
+
},
|
|
503
|
+
"id": "1700000103-gr0up-1",
|
|
504
|
+
"trigger": "load",
|
|
505
|
+
"entity": "page",
|
|
506
|
+
"action": "view",
|
|
507
|
+
"timestamp": 1700000103,
|
|
508
|
+
"timing": 3.14,
|
|
509
|
+
"group": "gr0up",
|
|
510
|
+
"count": 1,
|
|
511
|
+
"version": {
|
|
512
|
+
"source": "3.4.0-next-1776749829492",
|
|
513
|
+
"tagging": 1
|
|
514
|
+
},
|
|
515
|
+
"source": {
|
|
516
|
+
"type": "web",
|
|
517
|
+
"id": "https://localhost:80",
|
|
518
|
+
"previous_id": "http://remotehost:9001"
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
"settings": {
|
|
522
|
+
"redis": {
|
|
523
|
+
"streamKey": "walkeros:events",
|
|
524
|
+
"maxLen": 5000,
|
|
525
|
+
"exactTrimming": true
|
|
526
|
+
}
|
|
527
|
+
},
|
|
528
|
+
"out": [
|
|
529
|
+
[
|
|
530
|
+
"client.xadd",
|
|
531
|
+
[
|
|
532
|
+
"walkeros:events",
|
|
533
|
+
"MAXLEN",
|
|
534
|
+
5000,
|
|
535
|
+
"*",
|
|
536
|
+
"event",
|
|
537
|
+
"json:event"
|
|
538
|
+
]
|
|
539
|
+
]
|
|
540
|
+
]
|
|
541
|
+
},
|
|
542
|
+
"withMaxLen": {
|
|
543
|
+
"in": {
|
|
544
|
+
"name": "product view",
|
|
545
|
+
"data": {
|
|
546
|
+
"id": "SKU-123",
|
|
547
|
+
"name": "Widget"
|
|
548
|
+
},
|
|
549
|
+
"context": {
|
|
550
|
+
"shopping": [
|
|
551
|
+
"detail",
|
|
552
|
+
0
|
|
553
|
+
]
|
|
554
|
+
},
|
|
555
|
+
"globals": {
|
|
556
|
+
"pagegroup": "shop"
|
|
557
|
+
},
|
|
558
|
+
"custom": {
|
|
559
|
+
"completely": "random"
|
|
560
|
+
},
|
|
561
|
+
"user": {
|
|
562
|
+
"id": "us3r",
|
|
563
|
+
"device": "c00k13",
|
|
564
|
+
"session": "s3ss10n"
|
|
565
|
+
},
|
|
566
|
+
"nested": [],
|
|
567
|
+
"consent": {
|
|
568
|
+
"functional": true
|
|
569
|
+
},
|
|
570
|
+
"id": "1700000102-gr0up-1",
|
|
571
|
+
"trigger": "load",
|
|
572
|
+
"entity": "product",
|
|
573
|
+
"action": "view",
|
|
574
|
+
"timestamp": 1700000102,
|
|
575
|
+
"timing": 3.14,
|
|
576
|
+
"group": "gr0up",
|
|
577
|
+
"count": 1,
|
|
578
|
+
"version": {
|
|
579
|
+
"source": "3.4.0-next-1776749829492",
|
|
580
|
+
"tagging": 1
|
|
581
|
+
},
|
|
582
|
+
"source": {
|
|
583
|
+
"type": "web",
|
|
584
|
+
"id": "https://localhost:80",
|
|
585
|
+
"previous_id": "http://remotehost:9001"
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
"settings": {
|
|
589
|
+
"redis": {
|
|
590
|
+
"streamKey": "walkeros:events",
|
|
591
|
+
"maxLen": 50000
|
|
592
|
+
}
|
|
593
|
+
},
|
|
594
|
+
"out": [
|
|
595
|
+
[
|
|
596
|
+
"client.xadd",
|
|
597
|
+
[
|
|
598
|
+
"walkeros:events",
|
|
599
|
+
"MAXLEN",
|
|
600
|
+
"~",
|
|
601
|
+
50000,
|
|
602
|
+
"*",
|
|
603
|
+
"event",
|
|
604
|
+
"json:event"
|
|
605
|
+
]
|
|
606
|
+
]
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|