@browserflow-ai/core 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/config-schema.d.ts +354 -0
  2. package/dist/config-schema.d.ts.map +1 -0
  3. package/dist/config-schema.js +83 -0
  4. package/dist/config-schema.js.map +1 -0
  5. package/dist/config.d.ts +107 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +5 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/duration.d.ts +39 -0
  10. package/dist/duration.d.ts.map +1 -0
  11. package/dist/duration.js +111 -0
  12. package/dist/duration.js.map +1 -0
  13. package/dist/index.d.ts +12 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +20 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/locator-object.d.ts +556 -0
  18. package/dist/locator-object.d.ts.map +1 -0
  19. package/dist/locator-object.js +114 -0
  20. package/dist/locator-object.js.map +1 -0
  21. package/dist/lockfile.d.ts +1501 -0
  22. package/dist/lockfile.d.ts.map +1 -0
  23. package/dist/lockfile.js +86 -0
  24. package/dist/lockfile.js.map +1 -0
  25. package/dist/run-store.d.ts +81 -0
  26. package/dist/run-store.d.ts.map +1 -0
  27. package/dist/run-store.js +181 -0
  28. package/dist/run-store.js.map +1 -0
  29. package/dist/spec-loader.d.ts +17 -0
  30. package/dist/spec-loader.d.ts.map +1 -0
  31. package/dist/spec-loader.js +37 -0
  32. package/dist/spec-loader.js.map +1 -0
  33. package/dist/spec-schema.d.ts +1411 -0
  34. package/dist/spec-schema.d.ts.map +1 -0
  35. package/dist/spec-schema.js +239 -0
  36. package/dist/spec-schema.js.map +1 -0
  37. package/package.json +45 -0
  38. package/schemas/browserflow.schema.json +220 -0
  39. package/schemas/lockfile.schema.json +568 -0
  40. package/schemas/spec-v2.schema.json +413 -0
  41. package/src/config-schema.test.ts +190 -0
  42. package/src/config-schema.ts +111 -0
  43. package/src/config.ts +112 -0
  44. package/src/duration.test.ts +175 -0
  45. package/src/duration.ts +128 -0
  46. package/src/index.ts +136 -0
  47. package/src/json-schemas.test.ts +374 -0
  48. package/src/locator-object.test.ts +323 -0
  49. package/src/locator-object.ts +250 -0
  50. package/src/lockfile.test.ts +345 -0
  51. package/src/lockfile.ts +209 -0
  52. package/src/run-store.test.ts +232 -0
  53. package/src/run-store.ts +240 -0
  54. package/src/spec-loader.test.ts +181 -0
  55. package/src/spec-loader.ts +47 -0
  56. package/src/spec-schema.test.ts +360 -0
  57. package/src/spec-schema.ts +347 -0
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Duration string parser
3
+ *
4
+ * Parses human-readable duration strings like "30s", "5m", "1h30m"
5
+ * into milliseconds.
6
+ *
7
+ * @see bf-x1q for implementation task
8
+ */
9
+ const UNITS = {
10
+ ms: 1,
11
+ s: 1000,
12
+ m: 60 * 1000,
13
+ h: 60 * 60 * 1000,
14
+ };
15
+ /**
16
+ * Validates a duration string without parsing it.
17
+ *
18
+ * @param input - Duration string to validate
19
+ * @returns true if valid, false otherwise
20
+ */
21
+ export function isValidDuration(input) {
22
+ if (typeof input !== 'string') {
23
+ return false;
24
+ }
25
+ const trimmed = input.trim().toLowerCase();
26
+ if (!trimmed) {
27
+ return false;
28
+ }
29
+ // Plain number (milliseconds)
30
+ if (/^\d+$/.test(trimmed)) {
31
+ return true;
32
+ }
33
+ // Duration with units
34
+ const regex = /(\d+(?:\.\d+)?)(ms|s|m|h)/g;
35
+ let hasMatch = false;
36
+ // Check if entire string matches expected pattern
37
+ let lastIndex = 0;
38
+ let match;
39
+ while ((match = regex.exec(trimmed)) !== null) {
40
+ if (match.index !== lastIndex) {
41
+ return false; // Gap in matching
42
+ }
43
+ hasMatch = true;
44
+ lastIndex = regex.lastIndex;
45
+ }
46
+ return hasMatch && lastIndex === trimmed.length;
47
+ }
48
+ /**
49
+ * Parses a duration string into milliseconds.
50
+ *
51
+ * Supported formats:
52
+ * - "30s" -> 30000
53
+ * - "5m" -> 300000
54
+ * - "1h" -> 3600000
55
+ * - "1h30m" -> 5400000
56
+ * - "500ms" -> 500
57
+ * - "500" -> 500 (plain numbers treated as ms)
58
+ *
59
+ * @param input - Duration string to parse
60
+ * @returns Duration in milliseconds
61
+ * @throws Error if format is invalid
62
+ */
63
+ export function parseDuration(input) {
64
+ if (typeof input === 'number') {
65
+ return input;
66
+ }
67
+ if (typeof input !== 'string' || !input.trim()) {
68
+ throw new Error('Duration must be a non-empty string');
69
+ }
70
+ const trimmed = input.trim().toLowerCase();
71
+ // Plain number (milliseconds)
72
+ if (/^\d+$/.test(trimmed)) {
73
+ return parseInt(trimmed, 10);
74
+ }
75
+ let total = 0;
76
+ const regex = /(\d+(?:\.\d+)?)(ms|s|m|h)/g;
77
+ let match;
78
+ let hasMatch = false;
79
+ while ((match = regex.exec(trimmed)) !== null) {
80
+ hasMatch = true;
81
+ const [, value, unit] = match;
82
+ total += parseFloat(value) * UNITS[unit];
83
+ }
84
+ if (!hasMatch) {
85
+ throw new Error(`Invalid duration "${input}". Use format like "3s", "2m", "500ms", or "1m30s"`);
86
+ }
87
+ return Math.round(total);
88
+ }
89
+ /**
90
+ * Formats milliseconds into a human-readable duration string.
91
+ *
92
+ * @param ms - Duration in milliseconds
93
+ * @returns Human-readable duration string
94
+ */
95
+ export function formatDuration(ms) {
96
+ if (ms < 1000) {
97
+ return `${ms}ms`;
98
+ }
99
+ const hours = Math.floor(ms / 3600000);
100
+ const minutes = Math.floor((ms % 3600000) / 60000);
101
+ const seconds = Math.floor((ms % 60000) / 1000);
102
+ const parts = [];
103
+ if (hours > 0)
104
+ parts.push(`${hours}h`);
105
+ if (minutes > 0)
106
+ parts.push(`${minutes}m`);
107
+ if (seconds > 0)
108
+ parts.push(`${seconds}s`);
109
+ return parts.join('') || '0s';
110
+ }
111
+ //# sourceMappingURL=duration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duration.js","sourceRoot":"","sources":["../src/duration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @browserflow-ai/core - Shared types, schemas, and utilities
3
+ */
4
+ export { specSchema, specStepSchema, stepSchema, actionTypeSchema, verifyCheckSchema, expectedOutcomeSchema, highlightRegionSchema, maskRegionSchema, durationSchema, targetSchema, preconditionsSchema, stateSchema, type ActionType, type VerifyCheck, type HighlightRegion, type MaskRegion, type SpecStep, type LegacySpecStep, type ExpectedOutcome, type BrowserFlowSpec, type Target, type State, type Preconditions, } from './spec-schema.js';
5
+ export { normalizePreconditions, loadSpec } from './spec-loader.js';
6
+ export { type LocatorObject, type LocatorStrategy, type LocatorStrategyType, type LocatorScoping, type LocatorProof, type DOMFingerprint, type BoundingBox, type ResolveOptions, type LocatorMethod, type LocatorArgs, type LegacyLocatorObject, locatorObjectSchema, locatorStrategySchema, locatorStrategyTypeSchema, locatorScopingSchema, locatorProofSchema, domFingerprintSchema, boundingBoxSchema, resolveLocator, strategyToLocator, resolveLegacyLocator, } from './locator-object.js';
7
+ export { type Lockfile, type Mask, type Assertion, type AssertionType, type GenerationMetadata, type ExplorationReport, type ExplorationLockfile, type ExplorationStep, type StepExecution, type OutcomeCheck, type ExplorationError, lockfileSchema, maskSchema, assertionSchema, assertionTypeSchema, generationMetadataSchema, validateLockfile, computeSpecHash, readLockfile, writeLockfile, } from './lockfile.js';
8
+ export { parseDuration, formatDuration, isValidDuration } from './duration.js';
9
+ export { type RunDirectoryPaths, type RunStore, createRunStore, createRunId, getRunPaths, generateExplorationId, getScreenshotPath, } from './run-store.js';
10
+ export { type GeneratorOutputFormat, type BrowserType, type PlaywrightProject, type PlaywrightConfigOptions, type GeneratorConfig, type ReviewStepData, type ReviewData, type GeneratedTest, type GeneratedConfig, } from './config.js';
11
+ export { browserflowConfigSchema, browserTypeSchema, viewportSchema, projectConfigSchema, runtimeConfigSchema, locatorsConfigSchema, explorationConfigSchema, reviewConfigSchema, outputConfigSchema, ciConfigSchema, validateBrowserflowConfig, parseBrowserflowConfig, type BrowserTypeConfig, type ViewportConfig, type ProjectConfig, type RuntimeConfig, type LocatorsConfig, type ExplorationConfig, type ReviewConfig, type OutputConfig, type CiConfig, type BrowserflowConfig, } from './config-schema.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,UAAU,EACV,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACX,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,MAAM,EACX,KAAK,KAAK,EACV,KAAK,aAAa,GACnB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGpE,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,IAAI,EACT,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,cAAc,EACd,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAG/E,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,cAAc,EACd,WAAW,EACX,WAAW,EACX,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,yBAAyB,EACzB,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,iBAAiB,GACvB,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @browserflow-ai/core - Shared types, schemas, and utilities
3
+ */
4
+ // Spec schema and types
5
+ export { specSchema, specStepSchema, stepSchema, actionTypeSchema, verifyCheckSchema, expectedOutcomeSchema, highlightRegionSchema, maskRegionSchema, durationSchema, targetSchema, preconditionsSchema, stateSchema, } from './spec-schema.js';
6
+ // Spec loading and normalization
7
+ export { normalizePreconditions, loadSpec } from './spec-loader.js';
8
+ // Locator types and resolution
9
+ export { locatorObjectSchema, locatorStrategySchema, locatorStrategyTypeSchema, locatorScopingSchema, locatorProofSchema, domFingerprintSchema, boundingBoxSchema, resolveLocator, strategyToLocator, resolveLegacyLocator, } from './locator-object.js';
10
+ // Lockfile types
11
+ export { lockfileSchema, maskSchema, assertionSchema, assertionTypeSchema, generationMetadataSchema, validateLockfile, computeSpecHash, readLockfile, writeLockfile, } from './lockfile.js';
12
+ // Duration utilities
13
+ export { parseDuration, formatDuration, isValidDuration } from './duration.js';
14
+ // Run store utilities
15
+ export { createRunStore, createRunId, getRunPaths, generateExplorationId, getScreenshotPath, } from './run-store.js';
16
+ // Configuration types
17
+ export {} from './config.js';
18
+ // Browserflow config schema (for browserflow.yaml validation)
19
+ export { browserflowConfigSchema, browserTypeSchema, viewportSchema, projectConfigSchema, runtimeConfigSchema, locatorsConfigSchema, explorationConfigSchema, reviewConfigSchema, outputConfigSchema, ciConfigSchema, validateBrowserflowConfig, parseBrowserflowConfig, } from './config-schema.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAwB;AACxB,OAAO,EACL,UAAU,EACV,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,WAAW,GAYZ,MAAM,kBAAkB,CAAC;AAE1B,iCAAiC;AACjC,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEpE,+BAA+B;AAC/B,OAAO,EAYL,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,iBAAiB;AACjB,OAAO,EAYL,cAAc,EACd,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,qBAAqB;AACrB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE/E,sBAAsB;AACtB,OAAO,EAGL,cAAc,EACd,WAAW,EACX,WAAW,EACX,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,sBAAsB;AACtB,OAAO,EAUN,MAAM,aAAa,CAAC;AAErB,8DAA8D;AAC9D,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,yBAAyB,EACzB,sBAAsB,GAWvB,MAAM,oBAAoB,CAAC"}