synthra 0.1.0

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 (302) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +4 -0
  3. data/.rubocop.yml +40 -0
  4. data/.yardopts +18 -0
  5. data/ACCESS_DOCS.md +116 -0
  6. data/ADVANCED_FEATURES_SUMMARY.md +245 -0
  7. data/CHANGELOG.md +498 -0
  8. data/CODE_OF_CONDUCT.md +122 -0
  9. data/CONTRIBUTING.md +307 -0
  10. data/DOCUMENTATION.md +204 -0
  11. data/DOCUMENTATION_GUIDE.md +194 -0
  12. data/LICENSE +22 -0
  13. data/README.md +1458 -0
  14. data/Rakefile +128 -0
  15. data/benchmark/README.md +591 -0
  16. data/benchmark/batch_generation.rb +63 -0
  17. data/benchmark/engine_comparison.rb +295 -0
  18. data/benchmark/single_record.rb +108 -0
  19. data/benchmark/streaming.rb +74 -0
  20. data/docs/ACTIVERECORD_INFERENCE.md +524 -0
  21. data/docs/API_SERVER.md +278 -0
  22. data/docs/CONFIG_FILE.md +315 -0
  23. data/docs/DATA_CONTRACTS.md +312 -0
  24. data/docs/ENHANCED_REPL.md +304 -0
  25. data/docs/FACTORY_BOT.md +271 -0
  26. data/docs/GITHUB_ACTION.md +420 -0
  27. data/docs/GRAPHQL_EXPORT.md +303 -0
  28. data/docs/GRAPHQL_FEDERATION.md +651 -0
  29. data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
  30. data/docs/LSP.md +189 -0
  31. data/docs/MIGRATION_GENERATOR.md +547 -0
  32. data/docs/MOCK_SERVER.md +280 -0
  33. data/docs/NATIVE_ENGINE.md +298 -0
  34. data/docs/OPENAPI_EXPORT.md +252 -0
  35. data/docs/PERFORMANCE_MODE.md +228 -0
  36. data/docs/PERSONAS.md +547 -0
  37. data/docs/PROPERTY_TESTING.md +284 -0
  38. data/docs/PROTOBUF_EXPORT.md +276 -0
  39. data/docs/QUALITY_METRICS.md +555 -0
  40. data/docs/QUICK_REFERENCE.md +88 -0
  41. data/docs/RAILS_ENGINE.md +404 -0
  42. data/docs/RAILS_INTEGRATION.md +454 -0
  43. data/docs/README.md +175 -0
  44. data/docs/REPL_QUICK_REFERENCE.md +149 -0
  45. data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
  46. data/docs/SCENARIOS.md +576 -0
  47. data/docs/SECURITY_TESTING.md +318 -0
  48. data/docs/SNAPSHOT_TESTING.md +308 -0
  49. data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
  50. data/docs/TERRAFORM_EXPORT.md +447 -0
  51. data/docs/TIME_TRAVEL.md +507 -0
  52. data/docs/USAGE_GUIDE.md +980 -0
  53. data/docs/WEBHOOK_SIMULATOR.md +579 -0
  54. data/docs/advanced_features.md +183 -0
  55. data/docs/api_reference.md +153 -0
  56. data/docs/behaviors.md +138 -0
  57. data/docs/best_practices.md +191 -0
  58. data/docs/dsl_reference.md +172 -0
  59. data/docs/examples.md +162 -0
  60. data/docs/generation_modes.md +125 -0
  61. data/docs/getting_started.md +92 -0
  62. data/docs/index.html +177 -0
  63. data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
  64. data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
  65. data/docs/troubleshooting.md +215 -0
  66. data/docs/type_reference.md +224 -0
  67. data/examples/hostile_mode_demo.rb +64 -0
  68. data/exe/synthra +6 -0
  69. data/ext/synthra_native/Cargo.lock +972 -0
  70. data/ext/synthra_native/Cargo.toml +46 -0
  71. data/ext/synthra_native/extconf.rb +41 -0
  72. data/ext/synthra_native/src/generator.rs +397 -0
  73. data/ext/synthra_native/src/lib.rs +229 -0
  74. data/ext/synthra_native/src/types.rs +1485 -0
  75. data/lib/generators/synthra/install_generator.rb +86 -0
  76. data/lib/generators/synthra/templates/api_response.dsl +15 -0
  77. data/lib/generators/synthra/templates/fake_data.rake +116 -0
  78. data/lib/generators/synthra/templates/synthra.yml +31 -0
  79. data/lib/generators/synthra/templates/synthra_support.rb +19 -0
  80. data/lib/generators/synthra/templates/user.dsl +11 -0
  81. data/lib/synthra/activerecord_inference.rb +394 -0
  82. data/lib/synthra/api.rb +381 -0
  83. data/lib/synthra/api_server.rb +718 -0
  84. data/lib/synthra/behaviors/applicator.rb +165 -0
  85. data/lib/synthra/behaviors/base.rb +155 -0
  86. data/lib/synthra/behaviors/close_connection.rb +60 -0
  87. data/lib/synthra/behaviors/deprecated.rb +100 -0
  88. data/lib/synthra/behaviors/failure.rb +69 -0
  89. data/lib/synthra/behaviors/latency.rb +103 -0
  90. data/lib/synthra/behaviors/partial_data.rb +83 -0
  91. data/lib/synthra/behaviors/randomize_order.rb +74 -0
  92. data/lib/synthra/behaviors/registry.rb +238 -0
  93. data/lib/synthra/behaviors/simulate_error.rb +79 -0
  94. data/lib/synthra/cli/commands/base.rb +105 -0
  95. data/lib/synthra/cli/commands/diff.rb +227 -0
  96. data/lib/synthra/cli/commands/docs.rb +67 -0
  97. data/lib/synthra/cli/commands/export.rb +150 -0
  98. data/lib/synthra/cli/commands/generate.rb +72 -0
  99. data/lib/synthra/cli/commands/import.rb +80 -0
  100. data/lib/synthra/cli/commands/lint.rb +53 -0
  101. data/lib/synthra/cli/commands/live.rb +57 -0
  102. data/lib/synthra/cli/commands/seed.rb +99 -0
  103. data/lib/synthra/cli/commands/validate.rb +28 -0
  104. data/lib/synthra/cli.rb +2471 -0
  105. data/lib/synthra/config_file.rb +129 -0
  106. data/lib/synthra/configuration.rb +281 -0
  107. data/lib/synthra/contracts_registry.rb +408 -0
  108. data/lib/synthra/database_seeder.rb +268 -0
  109. data/lib/synthra/deterministic_ids.rb +218 -0
  110. data/lib/synthra/documentation_generator.rb +414 -0
  111. data/lib/synthra/engine.rb +251 -0
  112. data/lib/synthra/errors.rb +1169 -0
  113. data/lib/synthra/export/base.rb +85 -0
  114. data/lib/synthra/export/csv.rb +101 -0
  115. data/lib/synthra/export/graphql.rb +266 -0
  116. data/lib/synthra/export/graphql_federation.rb +377 -0
  117. data/lib/synthra/export/graphviz.rb +258 -0
  118. data/lib/synthra/export/javascript.rb +327 -0
  119. data/lib/synthra/export/json_data.rb +61 -0
  120. data/lib/synthra/export/json_schema.rb +290 -0
  121. data/lib/synthra/export/openapi.rb +514 -0
  122. data/lib/synthra/export/protobuf.rb +483 -0
  123. data/lib/synthra/export/python.rb +560 -0
  124. data/lib/synthra/export/sql.rb +381 -0
  125. data/lib/synthra/export/sql_insert.rb +152 -0
  126. data/lib/synthra/export/terraform.rb +501 -0
  127. data/lib/synthra/export/type_mapping.rb +389 -0
  128. data/lib/synthra/export/typescript.rb +300 -0
  129. data/lib/synthra/export/xml_data.rb +104 -0
  130. data/lib/synthra/export/yaml_data.rb +56 -0
  131. data/lib/synthra/export.rb +404 -0
  132. data/lib/synthra/factory_bot_integration.rb +157 -0
  133. data/lib/synthra/field.rb +440 -0
  134. data/lib/synthra/functions/registry.rb +104 -0
  135. data/lib/synthra/generator/context.rb +372 -0
  136. data/lib/synthra/generator/engine.rb +336 -0
  137. data/lib/synthra/generator/faker_adapter.rb +425 -0
  138. data/lib/synthra/generator/modes.rb +444 -0
  139. data/lib/synthra/generator/resolver.rb +256 -0
  140. data/lib/synthra/generator/rng.rb +273 -0
  141. data/lib/synthra/generator/streamer.rb +63 -0
  142. data/lib/synthra/generator/uniqueness.rb +118 -0
  143. data/lib/synthra/initializer.rb +97 -0
  144. data/lib/synthra/limits.rb +279 -0
  145. data/lib/synthra/live_preview.rb +518 -0
  146. data/lib/synthra/loader_config.rb +78 -0
  147. data/lib/synthra/lsp/server.rb +689 -0
  148. data/lib/synthra/migration_generator.rb +301 -0
  149. data/lib/synthra/mixin.rb +174 -0
  150. data/lib/synthra/mock_server.rb +458 -0
  151. data/lib/synthra/native_engine.rb +304 -0
  152. data/lib/synthra/openapi_importer.rb +228 -0
  153. data/lib/synthra/output/json_formatter.rb +40 -0
  154. data/lib/synthra/output/ndjson_formatter.rb +55 -0
  155. data/lib/synthra/parser/ast.rb +1287 -0
  156. data/lib/synthra/parser/lexer.rb +1152 -0
  157. data/lib/synthra/parser/parser.rb +1664 -0
  158. data/lib/synthra/parser/tokens.rb +461 -0
  159. data/lib/synthra/performance_mode.rb +364 -0
  160. data/lib/synthra/personas.rb +397 -0
  161. data/lib/synthra/property_testing.rb +172 -0
  162. data/lib/synthra/quality_metrics.rb +405 -0
  163. data/lib/synthra/rails_test_helper.rb +248 -0
  164. data/lib/synthra/registry.rb +533 -0
  165. data/lib/synthra/relationships.rb +193 -0
  166. data/lib/synthra/repl/enhanced_repl.rb +607 -0
  167. data/lib/synthra/repl/formatter.rb +191 -0
  168. data/lib/synthra/scenarios.rb +423 -0
  169. data/lib/synthra/schema.rb +605 -0
  170. data/lib/synthra/schema_inheritance.rb +104 -0
  171. data/lib/synthra/schema_versioning.rb +212 -0
  172. data/lib/synthra/snapshot_testing.rb +199 -0
  173. data/lib/synthra/time_travel.rb +338 -0
  174. data/lib/synthra/type_definitions.rb +274 -0
  175. data/lib/synthra/types/address_location/addresses.rb +125 -0
  176. data/lib/synthra/types/address_location/airports.rb +200 -0
  177. data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
  178. data/lib/synthra/types/address_location/locations.rb +406 -0
  179. data/lib/synthra/types/base.rb +48 -0
  180. data/lib/synthra/types/commerce_products/commerce.rb +119 -0
  181. data/lib/synthra/types/commerce_products/companies.rb +71 -0
  182. data/lib/synthra/types/commerce_products/construction.rb +126 -0
  183. data/lib/synthra/types/commerce_products/products.rb +205 -0
  184. data/lib/synthra/types/core/collections.rb +513 -0
  185. data/lib/synthra/types/core/defaults.rb +76 -0
  186. data/lib/synthra/types/core/enums.rb +102 -0
  187. data/lib/synthra/types/core/identifiers.rb +445 -0
  188. data/lib/synthra/types/core/primitives.rb +586 -0
  189. data/lib/synthra/types/core/references.rb +466 -0
  190. data/lib/synthra/types/core/sequences.rb +304 -0
  191. data/lib/synthra/types/crypto/crypto.rb +162 -0
  192. data/lib/synthra/types/date_time/dates.rb +387 -0
  193. data/lib/synthra/types/finance_banking/banking.rb +424 -0
  194. data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
  195. data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
  196. data/lib/synthra/types/formula.rb +184 -0
  197. data/lib/synthra/types/health_medical/medical.rb +150 -0
  198. data/lib/synthra/types/hostile_payloads.rb +122 -0
  199. data/lib/synthra/types/json_array.rb +51 -0
  200. data/lib/synthra/types/media_entertainment/media.rb +62 -0
  201. data/lib/synthra/types/naughty_string.rb +30 -0
  202. data/lib/synthra/types/personal_names/chinese.rb +41 -0
  203. data/lib/synthra/types/personal_names/identifiers.rb +187 -0
  204. data/lib/synthra/types/personal_names/names.rb +246 -0
  205. data/lib/synthra/types/personal_names/national_id.rb +89 -0
  206. data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
  207. data/lib/synthra/types/regex.rb +248 -0
  208. data/lib/synthra/types/registry.rb +182 -0
  209. data/lib/synthra/types/repeating_element.rb +50 -0
  210. data/lib/synthra/types/scenario.rb +29 -0
  211. data/lib/synthra/types/technology_internet/apps.rb +67 -0
  212. data/lib/synthra/types/technology_internet/communication.rb +162 -0
  213. data/lib/synthra/types/technology_internet/devices.rb +80 -0
  214. data/lib/synthra/types/technology_internet/formats.rb +139 -0
  215. data/lib/synthra/types/technology_internet/networking.rb +143 -0
  216. data/lib/synthra/types/template.rb +92 -0
  217. data/lib/synthra/types/text_content/business.rb +128 -0
  218. data/lib/synthra/types/text_content/colors.rb +70 -0
  219. data/lib/synthra/types/text_content/misc.rb +237 -0
  220. data/lib/synthra/types/text_content/security.rb +130 -0
  221. data/lib/synthra/types/text_content/text_generation.rb +532 -0
  222. data/lib/synthra/types/travel/travel.rb +150 -0
  223. data/lib/synthra/utils/string_distance.rb +133 -0
  224. data/lib/synthra/validator/dsl_validator.rb +339 -0
  225. data/lib/synthra/validator/path_validator.rb +615 -0
  226. data/lib/synthra/version.rb +35 -0
  227. data/lib/synthra/webhook_simulator.rb +341 -0
  228. data/lib/synthra.rb +259 -0
  229. data/schemas/address.dsl +16 -0
  230. data/schemas/api_response.dsl +8 -0
  231. data/schemas/error_payload.dsl +9 -0
  232. data/schemas/order.dsl +10 -0
  233. data/schemas/order_item.dsl +8 -0
  234. data/schemas/payment.dsl +11 -0
  235. data/schemas/social_post.dsl +13 -0
  236. data/schemas/user.dsl +10 -0
  237. data/scripts/batch_fix_all.rb +96 -0
  238. data/scripts/delete_old_files.rb +32 -0
  239. data/scripts/fix_all_grouped_files.rb +137 -0
  240. data/scripts/fix_all_indentation.rb +48 -0
  241. data/scripts/fix_all_syntax.rb +124 -0
  242. data/scripts/fix_grouped_files.rb +184 -0
  243. data/scripts/fix_syntax_errors.rb +108 -0
  244. data/scripts/group_domain_types.rb +112 -0
  245. data/scripts/group_domain_types_fixed.rb +150 -0
  246. data/scripts/merge_domains_to_one_file.rb +68 -0
  247. data/scripts/move_existing_types.rb +130 -0
  248. data/scripts/split_grouped_types.rb +142 -0
  249. data/tech_docs/README.md +134 -0
  250. data/tech_docs/advanced/streaming.md +405 -0
  251. data/tech_docs/advanced/thread_safety.md +253 -0
  252. data/tech_docs/api/overview.md +485 -0
  253. data/tech_docs/appendices/type_chart.md +193 -0
  254. data/tech_docs/basic_concepts.md +383 -0
  255. data/tech_docs/behaviors/overview.md +346 -0
  256. data/tech_docs/dsl/complex_types.md +790 -0
  257. data/tech_docs/dsl/core_types.md +464 -0
  258. data/tech_docs/dsl/datetime_types.md +325 -0
  259. data/tech_docs/dsl/field_modifiers.md +414 -0
  260. data/tech_docs/dsl/grammar.md +431 -0
  261. data/tech_docs/dsl/schema_definition.md +399 -0
  262. data/tech_docs/export/README.md +276 -0
  263. data/tech_docs/installation.md +273 -0
  264. data/tech_docs/integration/ci_cd.md +707 -0
  265. data/tech_docs/integration/ci_cd_guide.md +579 -0
  266. data/tech_docs/integration/factory_bot.md +485 -0
  267. data/tech_docs/integration/rails.md +630 -0
  268. data/tech_docs/integration/rspec.md +449 -0
  269. data/tech_docs/modes/overview.md +350 -0
  270. data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
  271. data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
  272. data/tech_docs/quick_start.md +256 -0
  273. data/tech_docs/templates/README.md +805 -0
  274. data/tech_docs/tutorials/advanced.md +371 -0
  275. data/tech_docs/tutorials/getting_started.md +189 -0
  276. data/tech_docs/tutorials/intermediate.md +231 -0
  277. data/tech_docs/tutorials/template_gallery.md +569 -0
  278. data/tech_example/01_basic_usage.rb +238 -0
  279. data/tech_example/02_types_demo.rb +336 -0
  280. data/tech_example/04_cli_usage.md +429 -0
  281. data/tech_example/05_database_seeding.rb +283 -0
  282. data/tech_example/07_rspec_integration.rb +359 -0
  283. data/tech_example/10_custom_types.rb +387 -0
  284. data/tech_example/12_behaviors.rb +372 -0
  285. data/tech_example/13_twitter_dm_example.rb +120 -0
  286. data/tech_example/14_exact_json_structure.rb +253 -0
  287. data/tech_example/16_lsp_server.rb +56 -0
  288. data/tech_example/17_property_testing.rb +92 -0
  289. data/tech_example/18_enhanced_repl.rb +120 -0
  290. data/tech_example/19_security_fuzzing.rb +145 -0
  291. data/tech_example/NEW_FEATURES.md +169 -0
  292. data/tech_example/README.md +118 -0
  293. data/tech_example/schemas/api_response.dsl +123 -0
  294. data/tech_example/schemas/ecommerce.dsl +121 -0
  295. data/tech_example/schemas/twitter_dm.dsl +109 -0
  296. data/tech_example/schemas/user.dsl +36 -0
  297. data/vscode-extension/README.md +246 -0
  298. data/vscode-extension/language-configuration.json +31 -0
  299. data/vscode-extension/package.json +55 -0
  300. data/vscode-extension/snippets/fakedatadsl.json +198 -0
  301. data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
  302. metadata +478 -0
@@ -0,0 +1,341 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "openssl"
6
+
7
+ module Synthra
8
+ # Webhook Simulation
9
+ #
10
+ # Simulate webhook deliveries for testing integrations with
11
+ # payment providers, notification services, and third-party APIs.
12
+ #
13
+ # @example Configure and send webhook
14
+ # Synthra::WebhookSimulator.configure do |config|
15
+ # config.endpoint = "http://localhost:3000/webhooks/stripe"
16
+ # config.secret = "whsec_test123"
17
+ # end
18
+ #
19
+ # Synthra::WebhookSimulator.send(
20
+ # "payment_intent.succeeded",
21
+ # data: { amount: 2000, currency: "usd" }
22
+ # )
23
+ #
24
+ module WebhookSimulator
25
+ class << self
26
+ attr_accessor :configuration
27
+
28
+ def configure
29
+ self.configuration ||= Configuration.new
30
+ yield(configuration) if block_given?
31
+ configuration
32
+ end
33
+
34
+ # Send a webhook
35
+ #
36
+ # @param event_type [String] event type (e.g., "payment_intent.succeeded")
37
+ # @param data [Hash] event data
38
+ # @param options [Hash] delivery options
39
+ # @option options [String] :endpoint override default endpoint
40
+ # @option options [String] :secret override default secret
41
+ # @option options [Integer] :delay delay in seconds before sending
42
+ # @option options [String] :schema schema to generate data from
43
+ # @option options [Hash] :headers additional headers
44
+ # @return [WebhookResult] delivery result
45
+ #
46
+ def send(event_type, data: nil, **options)
47
+ config = configuration || Configuration.new
48
+ endpoint = options[:endpoint] || config.endpoint
49
+ secret = options[:secret] || config.secret
50
+
51
+ raise ConfigurationError, "Endpoint not configured" unless endpoint
52
+
53
+ # Generate data from schema if specified
54
+ if options[:schema] && data.nil?
55
+ schema = Synthra.registry.schema(options[:schema].to_s)
56
+ data = schema.generate
57
+ end
58
+
59
+ # Build webhook payload
60
+ payload = build_payload(event_type, data, config)
61
+
62
+ # Handle delay
63
+ if options[:delay]
64
+ Thread.new do
65
+ sleep(options[:delay])
66
+ deliver(endpoint, payload, secret, options[:headers])
67
+ end
68
+ return WebhookResult.new(
69
+ success: true,
70
+ status: :scheduled,
71
+ message: "Webhook scheduled for delivery in #{options[:delay]}s"
72
+ )
73
+ end
74
+
75
+ # Deliver immediately
76
+ deliver(endpoint, payload, secret, options[:headers])
77
+ end
78
+
79
+ # Send webhook asynchronously
80
+ #
81
+ # @param event_type [String] event type
82
+ # @param options [Hash] options
83
+ # @return [Thread] delivery thread
84
+ #
85
+ def send_async(event_type, **options)
86
+ Thread.new { send(event_type, **options) }
87
+ end
88
+
89
+ # Simulate a sequence of webhooks
90
+ #
91
+ # @param events [Array<Hash>] list of events with delays
92
+ # @yield [result] for each delivered webhook
93
+ # @return [Array<WebhookResult>] results
94
+ #
95
+ # @example Simulate payment flow
96
+ # WebhookSimulator.sequence([
97
+ # { type: "payment_intent.created", delay: 0 },
98
+ # { type: "payment_intent.processing", delay: 1 },
99
+ # { type: "payment_intent.succeeded", delay: 2 }
100
+ # ])
101
+ #
102
+ def sequence(events, &block)
103
+ results = []
104
+
105
+ events.each do |event|
106
+ sleep(event[:delay] || 0) if event[:delay]
107
+
108
+ result = send(
109
+ event[:type],
110
+ data: event[:data],
111
+ schema: event[:schema],
112
+ endpoint: event[:endpoint]
113
+ )
114
+
115
+ results << result
116
+ yield result if block_given?
117
+ end
118
+
119
+ results
120
+ end
121
+
122
+ # Register a webhook template
123
+ #
124
+ # @param name [Symbol] template name
125
+ # @param event_type [String] event type
126
+ # @param schema [String] schema for data
127
+ # @param options [Hash] default options
128
+ #
129
+ def register_template(name, event_type:, schema: nil, **options)
130
+ templates[name] = {
131
+ event_type: event_type,
132
+ schema: schema,
133
+ options: options
134
+ }
135
+ end
136
+
137
+ # Send webhook using template
138
+ #
139
+ # @param template_name [Symbol] registered template name
140
+ # @param overrides [Hash] data overrides
141
+ # @return [WebhookResult]
142
+ #
143
+ def from_template(template_name, **overrides)
144
+ template = templates[template_name]
145
+ raise ArgumentError, "Unknown template: #{template_name}" unless template
146
+
147
+ send(
148
+ template[:event_type],
149
+ schema: template[:schema],
150
+ **template[:options].merge(overrides)
151
+ )
152
+ end
153
+
154
+ # Templates registry
155
+ def templates
156
+ @templates ||= {}
157
+ end
158
+
159
+ private
160
+
161
+ def build_payload(event_type, data, config)
162
+ {
163
+ id: "evt_#{SecureRandom.hex(12)}",
164
+ type: event_type,
165
+ created: Time.now.to_i,
166
+ data: {
167
+ object: data || {}
168
+ },
169
+ livemode: false,
170
+ api_version: config.api_version
171
+ }
172
+ end
173
+
174
+ def deliver(endpoint, payload, secret, extra_headers)
175
+ uri = URI.parse(endpoint)
176
+ http = Net::HTTP.new(uri.host, uri.port)
177
+ http.use_ssl = uri.scheme == "https"
178
+ http.open_timeout = 10
179
+ http.read_timeout = 30
180
+
181
+ body = JSON.generate(payload)
182
+
183
+ request = Net::HTTP::Post.new(uri.request_uri)
184
+ request["Content-Type"] = "application/json"
185
+ request["User-Agent"] = "Synthra-Webhook/1.0"
186
+
187
+ # Add signature if secret provided
188
+ if secret
189
+ timestamp = Time.now.to_i
190
+ signature = compute_signature(timestamp, body, secret)
191
+ request["Stripe-Signature"] = "t=#{timestamp},v1=#{signature}"
192
+ end
193
+
194
+ # Add extra headers
195
+ extra_headers&.each { |k, v| request[k] = v }
196
+
197
+ request.body = body
198
+
199
+ response = http.request(request)
200
+
201
+ WebhookResult.new(
202
+ success: response.code.to_i < 400,
203
+ status: response.code.to_i,
204
+ body: response.body,
205
+ payload: payload
206
+ )
207
+ rescue StandardError => e
208
+ WebhookResult.new(
209
+ success: false,
210
+ status: 0,
211
+ error: e.message,
212
+ payload: payload
213
+ )
214
+ end
215
+
216
+ def compute_signature(timestamp, payload, secret)
217
+ signed_payload = "#{timestamp}.#{payload}"
218
+ OpenSSL::HMAC.hexdigest("SHA256", secret, signed_payload)
219
+ end
220
+ end
221
+
222
+ # Configuration class
223
+ class Configuration
224
+ attr_accessor :endpoint, :secret, :api_version
225
+ attr_accessor :default_headers, :timeout
226
+
227
+ def initialize
228
+ @endpoint = nil
229
+ @secret = nil
230
+ @api_version = "2023-10-16"
231
+ @default_headers = {}
232
+ @timeout = 30
233
+ end
234
+ end
235
+
236
+ # Webhook delivery result
237
+ class WebhookResult
238
+ attr_reader :success, :status, :body, :error, :payload
239
+
240
+ def initialize(success:, status:, body: nil, error: nil, payload: nil, message: nil)
241
+ @success = success
242
+ @status = status
243
+ @body = body
244
+ @error = error
245
+ @payload = payload
246
+ @message = message
247
+ end
248
+
249
+ def success?
250
+ @success
251
+ end
252
+
253
+ def failed?
254
+ !@success
255
+ end
256
+
257
+ def to_h
258
+ {
259
+ success: @success,
260
+ status: @status,
261
+ body: @body,
262
+ error: @error
263
+ }
264
+ end
265
+ end
266
+
267
+ class ConfigurationError < StandardError; end
268
+
269
+ # Simulate Stripe webhooks
270
+ module Stripe
271
+ EVENTS = {
272
+ payment_succeeded: "payment_intent.succeeded",
273
+ payment_failed: "payment_intent.payment_failed",
274
+ subscription_created: "customer.subscription.created",
275
+ subscription_updated: "customer.subscription.updated",
276
+ subscription_deleted: "customer.subscription.deleted",
277
+ invoice_paid: "invoice.paid",
278
+ invoice_payment_failed: "invoice.payment_failed",
279
+ charge_succeeded: "charge.succeeded",
280
+ charge_refunded: "charge.refunded"
281
+ }.freeze
282
+
283
+ class << self
284
+ def payment_succeeded(amount:, currency: "usd", **options)
285
+ WebhookSimulator.send("payment_intent.succeeded", data: {
286
+ id: "pi_#{SecureRandom.hex(12)}",
287
+ object: "payment_intent",
288
+ amount: amount,
289
+ currency: currency,
290
+ status: "succeeded",
291
+ created: Time.now.to_i
292
+ }, **options)
293
+ end
294
+
295
+ def subscription_created(customer_id:, plan_id:, **options)
296
+ WebhookSimulator.send("customer.subscription.created", data: {
297
+ id: "sub_#{SecureRandom.hex(12)}",
298
+ object: "subscription",
299
+ customer: customer_id,
300
+ items: { data: [{ price: { id: plan_id } }] },
301
+ status: "active",
302
+ created: Time.now.to_i
303
+ }, **options)
304
+ end
305
+ end
306
+ end
307
+
308
+ # Simulate GitHub webhooks
309
+ module GitHub
310
+ EVENTS = {
311
+ push: "push",
312
+ pull_request: "pull_request",
313
+ issue: "issues",
314
+ release: "release"
315
+ }.freeze
316
+
317
+ class << self
318
+ def push(repo:, ref: "refs/heads/main", **options)
319
+ WebhookSimulator.send("push", data: {
320
+ ref: ref,
321
+ repository: { full_name: repo },
322
+ commits: [],
323
+ pusher: { name: "user", email: "user@example.com" }
324
+ }, **options)
325
+ end
326
+
327
+ def pull_request(repo:, action: "opened", **options)
328
+ WebhookSimulator.send("pull_request", data: {
329
+ action: action,
330
+ number: rand(1..1000),
331
+ repository: { full_name: repo },
332
+ pull_request: {
333
+ title: "Test PR",
334
+ state: action == "closed" ? "closed" : "open"
335
+ }
336
+ }, **options)
337
+ end
338
+ end
339
+ end
340
+ end
341
+ end
data/lib/synthra.rb ADDED
@@ -0,0 +1,259 @@
1
+ # frozen_string_literal: true
2
+
3
+ # =============================================================================
4
+ # Synthra - Generate fake data from a human-friendly DSL
5
+ # =============================================================================
6
+ #
7
+ # A Ruby gem for defining data schemas using a simple DSL and generating
8
+ # realistic fake data with support for:
9
+ #
10
+ # - 50+ built-in types (uuid, name, email, etc.)
11
+ # - Schema inheritance
12
+ # - Cross-schema references
13
+ # - Behaviors (latency, failure simulation)
14
+ # - Multiple generation modes (random, edge, invalid, hostile)
15
+ # - Export to multiple formats (TypeScript, Python, GraphQL, etc.)
16
+ #
17
+ # @example Basic usage
18
+ # schema = Synthra.load("schemas/user.dsl")
19
+ # user = schema.generate
20
+ #
21
+ # @author Synthra Contributors
22
+ # @see https://github.com/talaatmagdyx/synthra
23
+ #
24
+ # =============================================================================
25
+
26
+ require "zeitwerk"
27
+ require "faker"
28
+ require "json"
29
+ require "securerandom"
30
+
31
+ # Configure Zeitwerk autoloader
32
+ loader = Zeitwerk::Loader.for_gem
33
+ loader.inflector.inflect(
34
+ "synthra" => "Synthra",
35
+ "dsl" => "DSL",
36
+ "rng" => "RNG",
37
+ "ast" => "AST",
38
+ "cli" => "CLI",
39
+ "lsp" => "LSP",
40
+ "repl" => "REPL",
41
+ "api" => "API"
42
+ )
43
+
44
+ # Ignore domain folders (manually loaded for flat namespace)
45
+ IGNORED_DOMAIN_FOLDERS = %w[
46
+ address_location finance_banking technology_internet commerce_products
47
+ media_entertainment personal_names text_content health_medical travel
48
+ date_time crypto core
49
+ ].freeze
50
+
51
+ # Ignore deprecated files and domain folders
52
+ %w[
53
+ address_location_types finance_banking_types technology_internet_types
54
+ commerce_product_types media_entertainment_types personal_names_types
55
+ text_content_types datetime hash time
56
+ ].each { |f| loader.ignore("#{__dir__}/synthra/types/#{f}.rb") }
57
+
58
+ IGNORED_DOMAIN_FOLDERS.each do |folder|
59
+ loader.ignore("#{__dir__}/synthra/types/#{folder}")
60
+ end
61
+
62
+ # Ignore manually loaded modules
63
+ loader.ignore("#{__dir__}/synthra/utils")
64
+ loader.ignore("#{__dir__}/synthra/validator")
65
+ loader.ignore("#{__dir__}/synthra/lsp")
66
+ loader.ignore("#{__dir__}/synthra/repl")
67
+ loader.ignore("#{__dir__}/synthra/cli/commands")
68
+ loader.ignore("#{__dir__}/synthra/types/hostile_payloads.rb")
69
+
70
+ # Ignore new feature files (manually loaded)
71
+ loader.ignore("#{__dir__}/synthra/api.rb")
72
+ loader.ignore("#{__dir__}/synthra/type_definitions.rb")
73
+ loader.ignore("#{__dir__}/synthra/config_file.rb")
74
+ loader.ignore("#{__dir__}/synthra/schema_inheritance.rb")
75
+ loader.ignore("#{__dir__}/synthra/factory_bot_integration.rb")
76
+ loader.ignore("#{__dir__}/synthra/snapshot_testing.rb")
77
+ loader.ignore("#{__dir__}/synthra/export/type_mapping.rb")
78
+ loader.ignore("#{__dir__}/synthra/export/graphql.rb")
79
+
80
+ # Ignore Phase 2 feature files (manually loaded)
81
+ loader.ignore("#{__dir__}/synthra/rails_test_helper.rb")
82
+ loader.ignore("#{__dir__}/synthra/mixin.rb")
83
+ loader.ignore("#{__dir__}/synthra/relationships.rb")
84
+ loader.ignore("#{__dir__}/synthra/schema_versioning.rb")
85
+ loader.ignore("#{__dir__}/synthra/openapi_importer.rb")
86
+ loader.ignore("#{__dir__}/synthra/database_seeder.rb")
87
+ loader.ignore("#{__dir__}/synthra/live_preview.rb")
88
+ loader.ignore("#{__dir__}/synthra/documentation_generator.rb")
89
+ loader.ignore("#{__dir__}/synthra/deterministic_ids.rb")
90
+
91
+ # Ignore Production-grade features (manually loaded)
92
+ loader.ignore("#{__dir__}/synthra/export/protobuf.rb")
93
+ loader.ignore("#{__dir__}/synthra/export/openapi.rb")
94
+ loader.ignore("#{__dir__}/synthra/mock_server.rb")
95
+ loader.ignore("#{__dir__}/synthra/contracts_registry.rb")
96
+ loader.ignore("#{__dir__}/synthra/performance_mode.rb")
97
+ loader.ignore("#{__dir__}/synthra/api_server.rb")
98
+
99
+ # Ignore Rails-tier features (manually loaded)
100
+ loader.ignore("#{__dir__}/synthra/engine.rb")
101
+ loader.ignore("#{__dir__}/synthra/activerecord_inference.rb")
102
+ loader.ignore("#{__dir__}/synthra/scenarios.rb")
103
+ loader.ignore("#{__dir__}/synthra/personas.rb")
104
+ loader.ignore("#{__dir__}/synthra/time_travel.rb")
105
+ loader.ignore("#{__dir__}/synthra/quality_metrics.rb")
106
+ loader.ignore("#{__dir__}/synthra/webhook_simulator.rb")
107
+ loader.ignore("#{__dir__}/synthra/migration_generator.rb")
108
+ loader.ignore("#{__dir__}/synthra/export/graphql_federation.rb")
109
+ loader.ignore("#{__dir__}/synthra/export/terraform.rb")
110
+
111
+ # Ignore Rails generators (loaded by Rails when available)
112
+ loader.ignore("#{__dir__}/generators")
113
+
114
+ # Ignore initializer and loader_config (loaded manually, not a class/module)
115
+ loader.ignore("#{__dir__}/synthra/initializer.rb")
116
+ loader.ignore("#{__dir__}/synthra/loader_config.rb")
117
+
118
+ loader.setup
119
+
120
+ # =============================================================================
121
+ # Manual requires for organized modules
122
+ # =============================================================================
123
+
124
+ # Core utilities
125
+ require_relative "synthra/utils/string_distance"
126
+ require_relative "synthra/validator/path_validator"
127
+ require_relative "synthra/validator/dsl_validator"
128
+
129
+ # Export system
130
+ require_relative "synthra/export"
131
+ require_relative "synthra/export/type_mapping"
132
+
133
+ # LSP and REPL
134
+ require_relative "synthra/lsp/server"
135
+ require_relative "synthra/repl/formatter"
136
+ require_relative "synthra/repl/enhanced_repl"
137
+
138
+ # Hostile payloads
139
+ require_relative "synthra/types/hostile_payloads"
140
+
141
+ # New features
142
+ require_relative "synthra/api"
143
+ require_relative "synthra/type_definitions"
144
+ require_relative "synthra/config_file"
145
+ require_relative "synthra/schema_inheritance"
146
+ require_relative "synthra/factory_bot_integration"
147
+ require_relative "synthra/snapshot_testing"
148
+
149
+ # Phase 2 features
150
+ require_relative "synthra/rails_test_helper"
151
+ require_relative "synthra/mixin"
152
+ require_relative "synthra/relationships"
153
+ require_relative "synthra/schema_versioning"
154
+ require_relative "synthra/openapi_importer"
155
+ require_relative "synthra/database_seeder"
156
+ require_relative "synthra/live_preview"
157
+ require_relative "synthra/documentation_generator"
158
+ require_relative "synthra/deterministic_ids"
159
+
160
+ # Production-grade features
161
+ require_relative "synthra/export/protobuf"
162
+ require_relative "synthra/export/openapi"
163
+ require_relative "synthra/mock_server"
164
+ require_relative "synthra/contracts_registry"
165
+ require_relative "synthra/performance_mode"
166
+ require_relative "synthra/api_server"
167
+
168
+ # Rails-tier features
169
+ require_relative "synthra/time_travel"
170
+ require_relative "synthra/scenarios"
171
+ require_relative "synthra/personas"
172
+ require_relative "synthra/quality_metrics"
173
+ require_relative "synthra/webhook_simulator"
174
+ require_relative "synthra/migration_generator"
175
+ require_relative "synthra/export/graphql_federation"
176
+ require_relative "synthra/export/terraform"
177
+
178
+ # Rails Engine (only if Rails is available)
179
+ # :nocov: — load-time, Rails-only. The gem's RSpec suite runs without Rails, so
180
+ # Rails::Engine is never defined and this require block cannot execute under test.
181
+ if defined?(Rails::Engine)
182
+ require_relative "synthra/engine"
183
+ require_relative "synthra/activerecord_inference"
184
+ end
185
+ # :nocov:
186
+
187
+ # CLI command pattern
188
+ require_relative "synthra/cli/commands/base"
189
+ require_relative "synthra/cli/commands/validate"
190
+ require_relative "synthra/cli/commands/lint"
191
+ require_relative "synthra/cli/commands/generate"
192
+ require_relative "synthra/cli/commands/export"
193
+ require_relative "synthra/cli/commands/diff"
194
+ require_relative "synthra/cli/commands/import"
195
+ require_relative "synthra/cli/commands/docs"
196
+ require_relative "synthra/cli/commands/live"
197
+ require_relative "synthra/cli/commands/seed"
198
+
199
+ # =============================================================================
200
+ # Main Module
201
+ # =============================================================================
202
+
203
+ module Synthra
204
+ # Probability that an optional field will be included (80%)
205
+ OPTIONAL_FIELD_PRESENCE_RATE = 0.8
206
+
207
+ # Probability that a nullable field will be null (10%)
208
+ NULLABLE_FIELD_NULL_RATE = 0.1
209
+
210
+ # Maximum DSL file size to prevent DoS (10MB)
211
+ MAX_DSL_FILE_SIZE = 10 * 1024 * 1024
212
+
213
+ # Extend with API methods
214
+ extend API
215
+
216
+ class << self
217
+ # Load configuration from config file on first use
218
+ #
219
+ # @return [void]
220
+ #
221
+ def load_config_file!
222
+ @config_loaded ||= begin
223
+ ConfigFile.load_and_apply
224
+ true
225
+ end
226
+ end
227
+ end
228
+ end
229
+
230
+ # =============================================================================
231
+ # Eager loading and initialization
232
+ # =============================================================================
233
+
234
+ # Eager load all autoloaded files
235
+ loader.eager_load
236
+
237
+ # Load domain folder type files
238
+ IGNORED_DOMAIN_FOLDERS.each do |folder|
239
+ dir = File.join(__dir__, "synthra/types/#{folder}")
240
+ # :nocov: — load-time guard. Every listed domain folder ships with the gem, so
241
+ # the missing-directory (`next`) arm is never taken once the gem is installed.
242
+ next unless Dir.exist?(dir)
243
+ # :nocov:
244
+
245
+ Dir.glob(File.join(dir, "*.rb")).sort.each do |file|
246
+ require_relative file.sub(%r{^#{__dir__}/}, "")
247
+ end
248
+ end
249
+
250
+ # Register built-in types and behaviors
251
+ Synthra.register_builtin_types!
252
+ Synthra::Behaviors::Registry.register_builtins!
253
+
254
+ # Auto-load config file if present
255
+ # :nocov: — load-time, runs exactly once at require. Which arm is taken depends
256
+ # on whether a config file is present in the boot CWD; it cannot be re-driven by
257
+ # a unit test. (load_config_file! itself is covered directly in its own spec.)
258
+ Synthra.load_config_file! if Synthra::ConfigFile.find_config_file
259
+ # :nocov:
@@ -0,0 +1,16 @@
1
+ # Address schema example
2
+ Address:
3
+ street: text(10..100)
4
+ city: text(5..30)
5
+ state: text(2..20)
6
+ postal_code: postal_code(country: US)
7
+ country: country_code
8
+
9
+
10
+ PostalCode:
11
+ postal_code: text(5..10)
12
+ country: country_code
13
+
14
+ CountryCode:
15
+ country_code: text(2)
16
+
@@ -0,0 +1,8 @@
1
+ # API response wrapper
2
+ ApiResponse:
3
+ success: boolean(true:95%)
4
+ data?: User
5
+ error?: text if success
6
+ timestamp: timestamp
7
+ request_id: ulid
8
+
@@ -0,0 +1,9 @@
1
+ # Error response schema
2
+ ErrorPayload:
3
+ error_code: text(3..10)
4
+ message: text(10..200)
5
+ details?: text(20..500)
6
+ timestamp: timestamp
7
+ request_id: ulid
8
+ path: url
9
+
data/schemas/order.dsl ADDED
@@ -0,0 +1,10 @@
1
+ # Order schema with references
2
+ Order:
3
+ id: uuid(unique: true)
4
+ user_id: Ref(User.id)
5
+ status: enum(pending, processing:30%, shipped:40%, delivered:25%, cancelled:5%)
6
+ total: money(range: 10..1000, currency: USD)
7
+ items: array(OrderItem, 1..5)
8
+ created_at: past_date(30d)
9
+ shipped_at?: future_date(7d) if status
10
+
@@ -0,0 +1,8 @@
1
+ # Order item schema
2
+ OrderItem:
3
+ id: uuid
4
+ product_name: text(5..50)
5
+ quantity: number(1..10)
6
+ unit_price: money(range: 1..500)
7
+ sku: text(8..12)
8
+
@@ -0,0 +1,11 @@
1
+ # Payment schema
2
+ Payment:
3
+ id: uuid(unique: true)
4
+ order_id: Ref(Order.id)
5
+ amount: money
6
+ currency: currency
7
+ method: enum(credit_card:60%, debit_card:20%, paypal:15%, bank_transfer:5%)
8
+ status: enum(pending, completed:80%, failed:10%, refunded:10%)
9
+ processed_at?: timestamp
10
+ ip_address: ip
11
+
@@ -0,0 +1,13 @@
1
+ # Social media post schema
2
+ SocialPost:
3
+ id: ulid
4
+ author_id: uuid
5
+ content: text(10..280)
6
+ likes: number(0..10000)
7
+ shares: number(0..1000)
8
+ comments_count: number(0..500)
9
+ tags: array(text, 0..5)
10
+ media_url?: url
11
+ is_sponsored: boolean(true:10%)
12
+ created_at: past_date(30d)
13
+
data/schemas/user.dsl ADDED
@@ -0,0 +1,10 @@
1
+ # User schema example
2
+ User:
3
+ id: uuid(unique: true)
4
+ name: name
5
+ email: email
6
+ age?: number(18..80)
7
+ active: boolean(true:80%)
8
+ role: enum(user, admin:10%, moderator:20%)
9
+ created_at: past_date(2y)
10
+