Skip to content

Commit 4558e99

Browse files
package to code
1 parent d32449d commit 4558e99

File tree

15 files changed

+472
-118
lines changed

15 files changed

+472
-118
lines changed

packages/cli/examples/flow.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
},
2020
"destinations": {
2121
"ga4": {
22-
"code": "destinationGtag",
22+
"package": "@walkeros/web-destination-gtag",
2323
"config": {
2424
"consent": {
2525
"marketing": true
@@ -61,7 +61,7 @@
6161
}
6262
},
6363
"demo": {
64-
"code": "destinationDemo",
64+
"package": "@walkeros/destination-demo",
6565
"config": {
6666
"settings": {
6767
"name": "Order Complete Demo",

packages/cli/examples/server-collect.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
},
2020
"sources": {
2121
"http": {
22-
"code": "sourceExpress",
22+
"package": "@walkeros/server-source-express",
2323
"config": {
2424
"settings": {
2525
"path": "/collect",
@@ -32,7 +32,7 @@
3232
},
3333
"destinations": {
3434
"demo": {
35-
"code": "destinationDemo",
35+
"package": "@walkeros/destination-demo",
3636
"config": {
3737
"settings": {
3838
"name": "Server Collection Demo",

packages/cli/examples/web-serve.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
},
2323
"sources": {
2424
"demo": {
25-
"code": "sourceDemo",
25+
"package": "@walkeros/source-demo",
2626
"config": {
2727
"settings": {
2828
"events": [
@@ -48,15 +48,14 @@
4848
"destinations": {
4949
"demo": {
5050
"package": "@walkeros/destination-demo",
51-
"code": "destinationDemo",
5251
"config": {
5352
"settings": {
5453
"name": "demo"
5554
}
5655
}
5756
},
5857
"api": {
59-
"code": "destinationAPI",
58+
"package": "@walkeros/web-destination-api",
6059
"config": {
6160
"settings": {
6261
"url": "http://localhost:8080/collect"

packages/cli/src/__tests__/config-loader.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ describe('Config Loader', () => {
269269
loadBundleConfig(invalidConfig, {
270270
configPath: '/test/config.json',
271271
}),
272-
).toThrow(/Invalid configuration.*version/);
272+
).toThrow(/Invalid configuration[\s\S]*version/);
273273
});
274274

275275
test('throws error for invalid config format (wrong version)', () => {
@@ -284,7 +284,7 @@ describe('Config Loader', () => {
284284
loadBundleConfig(invalidConfig, {
285285
configPath: '/test/config.json',
286286
}),
287-
).toThrow(/Invalid configuration.*version/);
287+
).toThrow(/Invalid configuration[\s\S]*version/);
288288
});
289289

290290
test('throws error for invalid config format (missing flows)', () => {
@@ -296,7 +296,7 @@ describe('Config Loader', () => {
296296
loadBundleConfig(invalidConfig, {
297297
configPath: '/test/config.json',
298298
}),
299-
).toThrow(/Invalid configuration.*flows/);
299+
).toThrow(/Invalid configuration[\s\S]*flows/);
300300
});
301301

302302
test('throws error for empty flows', () => {
@@ -309,7 +309,7 @@ describe('Config Loader', () => {
309309
loadBundleConfig(invalidConfig, {
310310
configPath: '/test/config.json',
311311
}),
312-
).toThrow(/must contain at least one flow/);
312+
).toThrow(/at least one flow/i);
313313
});
314314

315315
test('throws error for flow without web/server key', () => {
@@ -326,7 +326,7 @@ describe('Config Loader', () => {
326326
loadBundleConfig(invalidConfig, {
327327
configPath: '/test/config.json',
328328
}),
329-
).toThrow(/must have a "web" or "server" key/);
329+
).toThrow(/web.*or.*server|Exactly one of/i);
330330
});
331331

332332
test('returns empty array for non-Flow.Setup config', () => {

packages/cli/src/__tests__/simulate/server-simulate.integration.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('Server Simulation Integration', () => {
3232
},
3333
destinations: {
3434
demo: {
35-
code: 'destinationDemo',
35+
package: '@walkeros/destination-demo',
3636
config: { settings: { name: 'Test', values: ['name'] } },
3737
},
3838
},

packages/cli/src/commands/push/index.ts

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import path from 'path';
22
import { JSDOM, VirtualConsole } from 'jsdom';
33
import fs from 'fs-extra';
44
import { getPlatform, type Elb } from '@walkeros/core';
5+
import { schemas } from '@walkeros/core/dev';
56
import {
67
createCommandLogger,
78
createLogger,
@@ -40,22 +41,34 @@ export async function pushCommand(options: PushCommandOptions): Promise<void> {
4041
name: 'event',
4142
});
4243

43-
// Validate event format
44-
if (
45-
!event ||
46-
typeof event !== 'object' ||
47-
!('name' in event) ||
48-
typeof event.name !== 'string'
49-
) {
50-
throw new Error(
51-
'Event must be an object with a "name" property (string)',
52-
);
44+
// Validate event format using Zod schema
45+
const eventResult = schemas.PartialEventSchema.safeParse(event);
46+
if (!eventResult.success) {
47+
const errors = eventResult.error.issues
48+
.map((issue) => `${String(issue.path.join('.'))}: ${issue.message}`)
49+
.join(', ');
50+
throw new Error(`Invalid event: ${errors}`);
5351
}
5452

55-
// Warn about event naming format
56-
if (!event.name.includes(' ')) {
53+
const parsedEvent = eventResult.data as {
54+
name?: string;
55+
data?: Record<string, unknown>;
56+
};
57+
if (!parsedEvent.name) {
58+
throw new Error('Invalid event: Missing required "name" property');
59+
}
60+
61+
// Create typed event object for execution
62+
const validatedEvent: { name: string; data: Record<string, unknown> } =
63+
{
64+
name: parsedEvent.name,
65+
data: (parsedEvent.data || {}) as Record<string, unknown>,
66+
};
67+
68+
// Warn about event naming format (walkerOS business logic)
69+
if (!validatedEvent.name.includes(' ')) {
5770
logger.warn(
58-
`Event name "${event.name}" should follow "ENTITY ACTION" format (e.g., "page view")`,
71+
`Event name "${validatedEvent.name}" should follow "ENTITY ACTION" format (e.g., "page view")`,
5972
);
6073
}
6174

@@ -108,10 +121,10 @@ export async function pushCommand(options: PushCommandOptions): Promise<void> {
108121

109122
if (platform === 'web') {
110123
logger.info('🌐 Executing in web environment (JSDOM)...');
111-
result = await executeWebPush(tempPath, event, logger);
124+
result = await executeWebPush(tempPath, validatedEvent, logger);
112125
} else if (platform === 'server') {
113126
logger.info('🖥️ Executing in server environment (Node.js)...');
114-
result = await executeServerPush(tempPath, event, logger);
127+
result = await executeServerPush(tempPath, validatedEvent, logger);
115128
} else {
116129
throw new Error(`Unsupported platform: ${platform}`);
117130
}
@@ -199,12 +212,20 @@ export async function pushCommand(options: PushCommandOptions): Promise<void> {
199212
);
200213
}
201214

215+
/**
216+
* Typed event input for push command
217+
*/
218+
interface PushEventInput {
219+
name: string;
220+
data: Record<string, unknown>;
221+
}
222+
202223
/**
203224
* Execute push for web platform using JSDOM with real APIs
204225
*/
205226
async function executeWebPush(
206227
bundlePath: string,
207-
event: Record<string, unknown>,
228+
event: PushEventInput,
208229
logger: Logger,
209230
): Promise<PushResult> {
210231
const startTime = Date.now();
@@ -244,8 +265,7 @@ async function executeWebPush(
244265

245266
// Push event
246267
logger.info(`Pushing event: ${event.name}`);
247-
const eventData = (event.data || {}) as Record<string, unknown>;
248-
const elbResult = await elb(event.name as string, eventData);
268+
const elbResult = await elb(event.name, event.data);
249269

250270
return {
251271
success: true,
@@ -266,7 +286,7 @@ async function executeWebPush(
266286
*/
267287
async function executeServerPush(
268288
bundlePath: string,
269-
event: Record<string, unknown>,
289+
event: PushEventInput,
270290
logger: Logger,
271291
timeout: number = 60000, // 60 second default timeout
272292
): Promise<PushResult> {
@@ -305,13 +325,12 @@ async function executeServerPush(
305325

306326
// Push event
307327
logger.info(`Pushing event: ${event.name}`);
308-
const eventData = (event.data || {}) as Record<string, unknown>;
309328
const elbResult = await (
310329
elb as (
311330
name: string,
312331
data: Record<string, unknown>,
313332
) => Promise<Elb.PushResult>
314-
)(event.name as string, eventData);
333+
)(event.name, event.data);
315334

316335
return {
317336
success: true,

packages/cli/src/commands/run/validators.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
11
/**
22
* Run Command Validators
33
*
4-
* Validation logic for run command inputs
4+
* Validation logic for run command inputs.
5+
* Uses Zod schemas for type-safe validation.
56
*/
67

78
import { existsSync } from 'fs';
89
import { resolveAsset } from '../../core/asset-resolver.js';
9-
import type { RunMode } from './types.js';
10+
import {
11+
RunModeSchema,
12+
PortSchema,
13+
type RunMode,
14+
} from '../../schemas/index.js';
1015

1116
/**
12-
* Valid run modes
13-
*/
14-
const VALID_MODES: RunMode[] = ['collect', 'serve'];
15-
16-
/**
17-
* Validates run mode
17+
* Validates run mode using Zod schema.
1818
*
1919
* @param mode - Mode to validate
2020
* @throws Error if mode is invalid
2121
*/
2222
export function validateMode(mode: string): asserts mode is RunMode {
23-
if (!VALID_MODES.includes(mode as RunMode)) {
23+
const result = RunModeSchema.safeParse(mode);
24+
if (!result.success) {
2425
throw new Error(
2526
`Invalid mode: "${mode}"\n` +
26-
` Valid modes: ${VALID_MODES.join(', ')}\n` +
27+
` Valid modes: collect, serve\n` +
2728
` Example: walkeros run collect ./flow.json`,
2829
);
2930
}
3031
}
3132

3233
/**
33-
* Validates flow file exists
34+
* Validates flow file exists.
35+
*
36+
* @remarks
37+
* File existence cannot be validated by Zod, so this remains a custom check.
3438
*
3539
* @param filePath - Path to flow configuration file (bare name, relative, or absolute)
3640
* @returns Absolute path to flow file
@@ -52,13 +56,14 @@ export function validateFlowFile(filePath: string): string {
5256
}
5357

5458
/**
55-
* Validates port number
59+
* Validates port number using Zod schema.
5660
*
5761
* @param port - Port number to validate
5862
* @throws Error if port is invalid
5963
*/
6064
export function validatePort(port: number): void {
61-
if (!Number.isInteger(port) || port < 1 || port > 65535) {
65+
const result = PortSchema.safeParse(port);
66+
if (!result.success) {
6267
throw new Error(
6368
`Invalid port: ${port}\n` +
6469
` Port must be an integer between 1 and 65535\n` +

packages/cli/src/config/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
export {
1010
isObject,
1111
detectPlatform,
12-
hasValidPlatform,
1312
isFlowSetup,
1413
validateFlowSetup,
1514
getAvailableFlows as getFlowNames,

0 commit comments

Comments
 (0)