@plures/praxis 0.2.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 (263) hide show
  1. package/FRAMEWORK.md +420 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1310 -0
  4. package/dist/adapters/cli.d.ts +43 -0
  5. package/dist/adapters/cli.d.ts.map +1 -0
  6. package/dist/adapters/cli.js +126 -0
  7. package/dist/adapters/cli.js.map +1 -0
  8. package/dist/cli/commands/auth.d.ts +26 -0
  9. package/dist/cli/commands/auth.d.ts.map +1 -0
  10. package/dist/cli/commands/auth.js +233 -0
  11. package/dist/cli/commands/auth.js.map +1 -0
  12. package/dist/cli/commands/cloud.d.ts +27 -0
  13. package/dist/cli/commands/cloud.d.ts.map +1 -0
  14. package/dist/cli/commands/cloud.js +232 -0
  15. package/dist/cli/commands/cloud.js.map +1 -0
  16. package/dist/cli/commands/generate.d.ts +25 -0
  17. package/dist/cli/commands/generate.d.ts.map +1 -0
  18. package/dist/cli/commands/generate.js +168 -0
  19. package/dist/cli/commands/generate.js.map +1 -0
  20. package/dist/cli/index.d.ts +8 -0
  21. package/dist/cli/index.d.ts.map +1 -0
  22. package/dist/cli/index.js +179 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/cloud/auth.d.ts +51 -0
  25. package/dist/cloud/auth.d.ts.map +1 -0
  26. package/dist/cloud/auth.js +194 -0
  27. package/dist/cloud/auth.js.map +1 -0
  28. package/dist/cloud/billing.d.ts +184 -0
  29. package/dist/cloud/billing.d.ts.map +1 -0
  30. package/dist/cloud/billing.js +179 -0
  31. package/dist/cloud/billing.js.map +1 -0
  32. package/dist/cloud/client.d.ts +39 -0
  33. package/dist/cloud/client.d.ts.map +1 -0
  34. package/dist/cloud/client.js +176 -0
  35. package/dist/cloud/client.js.map +1 -0
  36. package/dist/cloud/index.d.ts +44 -0
  37. package/dist/cloud/index.d.ts.map +1 -0
  38. package/dist/cloud/index.js +44 -0
  39. package/dist/cloud/index.js.map +1 -0
  40. package/dist/cloud/marketplace.d.ts +166 -0
  41. package/dist/cloud/marketplace.d.ts.map +1 -0
  42. package/dist/cloud/marketplace.js +159 -0
  43. package/dist/cloud/marketplace.js.map +1 -0
  44. package/dist/cloud/provisioning.d.ts +110 -0
  45. package/dist/cloud/provisioning.d.ts.map +1 -0
  46. package/dist/cloud/provisioning.js +148 -0
  47. package/dist/cloud/provisioning.js.map +1 -0
  48. package/dist/cloud/relay/endpoints.d.ts +62 -0
  49. package/dist/cloud/relay/endpoints.d.ts.map +1 -0
  50. package/dist/cloud/relay/endpoints.js +217 -0
  51. package/dist/cloud/relay/endpoints.js.map +1 -0
  52. package/dist/cloud/relay/health/index.d.ts +5 -0
  53. package/dist/cloud/relay/health/index.d.ts.map +1 -0
  54. package/dist/cloud/relay/health/index.js +9 -0
  55. package/dist/cloud/relay/health/index.js.map +1 -0
  56. package/dist/cloud/relay/stats/index.d.ts +5 -0
  57. package/dist/cloud/relay/stats/index.d.ts.map +1 -0
  58. package/dist/cloud/relay/stats/index.js +9 -0
  59. package/dist/cloud/relay/stats/index.js.map +1 -0
  60. package/dist/cloud/relay/sync/index.d.ts +5 -0
  61. package/dist/cloud/relay/sync/index.d.ts.map +1 -0
  62. package/dist/cloud/relay/sync/index.js +9 -0
  63. package/dist/cloud/relay/sync/index.js.map +1 -0
  64. package/dist/cloud/relay/usage/index.d.ts +5 -0
  65. package/dist/cloud/relay/usage/index.d.ts.map +1 -0
  66. package/dist/cloud/relay/usage/index.js +9 -0
  67. package/dist/cloud/relay/usage/index.js.map +1 -0
  68. package/dist/cloud/sponsors.d.ts +81 -0
  69. package/dist/cloud/sponsors.d.ts.map +1 -0
  70. package/dist/cloud/sponsors.js +130 -0
  71. package/dist/cloud/sponsors.js.map +1 -0
  72. package/dist/cloud/types.d.ts +169 -0
  73. package/dist/cloud/types.d.ts.map +1 -0
  74. package/dist/cloud/types.js +7 -0
  75. package/dist/cloud/types.js.map +1 -0
  76. package/dist/components/index.d.ts +43 -0
  77. package/dist/components/index.d.ts.map +1 -0
  78. package/dist/components/index.js +17 -0
  79. package/dist/components/index.js.map +1 -0
  80. package/dist/core/actors.d.ts +95 -0
  81. package/dist/core/actors.d.ts.map +1 -0
  82. package/dist/core/actors.js +158 -0
  83. package/dist/core/actors.js.map +1 -0
  84. package/dist/core/component/generator.d.ts +122 -0
  85. package/dist/core/component/generator.d.ts.map +1 -0
  86. package/dist/core/component/generator.js +307 -0
  87. package/dist/core/component/generator.js.map +1 -0
  88. package/dist/core/engine.d.ts +92 -0
  89. package/dist/core/engine.d.ts.map +1 -0
  90. package/dist/core/engine.js +199 -0
  91. package/dist/core/engine.js.map +1 -0
  92. package/dist/core/introspection.d.ts +141 -0
  93. package/dist/core/introspection.d.ts.map +1 -0
  94. package/dist/core/introspection.js +208 -0
  95. package/dist/core/introspection.js.map +1 -0
  96. package/dist/core/logic/generator.d.ts +76 -0
  97. package/dist/core/logic/generator.d.ts.map +1 -0
  98. package/dist/core/logic/generator.js +339 -0
  99. package/dist/core/logic/generator.js.map +1 -0
  100. package/dist/core/pluresdb/generator.d.ts +58 -0
  101. package/dist/core/pluresdb/generator.d.ts.map +1 -0
  102. package/dist/core/pluresdb/generator.js +162 -0
  103. package/dist/core/pluresdb/generator.js.map +1 -0
  104. package/dist/core/protocol.d.ts +121 -0
  105. package/dist/core/protocol.d.ts.map +1 -0
  106. package/dist/core/protocol.js +46 -0
  107. package/dist/core/protocol.js.map +1 -0
  108. package/dist/core/rules.d.ts +120 -0
  109. package/dist/core/rules.d.ts.map +1 -0
  110. package/dist/core/rules.js +81 -0
  111. package/dist/core/rules.js.map +1 -0
  112. package/dist/core/schema/loader.d.ts +47 -0
  113. package/dist/core/schema/loader.d.ts.map +1 -0
  114. package/dist/core/schema/loader.js +189 -0
  115. package/dist/core/schema/loader.js.map +1 -0
  116. package/dist/core/schema/normalize.d.ts +72 -0
  117. package/dist/core/schema/normalize.d.ts.map +1 -0
  118. package/dist/core/schema/normalize.js +190 -0
  119. package/dist/core/schema/normalize.js.map +1 -0
  120. package/dist/core/schema/types.d.ts +370 -0
  121. package/dist/core/schema/types.d.ts.map +1 -0
  122. package/dist/core/schema/types.js +161 -0
  123. package/dist/core/schema/types.js.map +1 -0
  124. package/dist/dsl/index.d.ts +152 -0
  125. package/dist/dsl/index.d.ts.map +1 -0
  126. package/dist/dsl/index.js +132 -0
  127. package/dist/dsl/index.js.map +1 -0
  128. package/dist/dsl.d.ts +124 -0
  129. package/dist/dsl.d.ts.map +1 -0
  130. package/dist/dsl.js +130 -0
  131. package/dist/dsl.js.map +1 -0
  132. package/dist/examples/advanced-todo/index.d.ts +55 -0
  133. package/dist/examples/advanced-todo/index.d.ts.map +1 -0
  134. package/dist/examples/advanced-todo/index.js +222 -0
  135. package/dist/examples/advanced-todo/index.js.map +1 -0
  136. package/dist/examples/auth-basic/index.d.ts +17 -0
  137. package/dist/examples/auth-basic/index.d.ts.map +1 -0
  138. package/dist/examples/auth-basic/index.js +122 -0
  139. package/dist/examples/auth-basic/index.js.map +1 -0
  140. package/dist/examples/cart/index.d.ts +19 -0
  141. package/dist/examples/cart/index.d.ts.map +1 -0
  142. package/dist/examples/cart/index.js +202 -0
  143. package/dist/examples/cart/index.js.map +1 -0
  144. package/dist/examples/hero-ecommerce/index.d.ts +39 -0
  145. package/dist/examples/hero-ecommerce/index.d.ts.map +1 -0
  146. package/dist/examples/hero-ecommerce/index.js +506 -0
  147. package/dist/examples/hero-ecommerce/index.js.map +1 -0
  148. package/dist/examples/svelte-counter/index.d.ts +31 -0
  149. package/dist/examples/svelte-counter/index.d.ts.map +1 -0
  150. package/dist/examples/svelte-counter/index.js +123 -0
  151. package/dist/examples/svelte-counter/index.js.map +1 -0
  152. package/dist/flows.d.ts +125 -0
  153. package/dist/flows.d.ts.map +1 -0
  154. package/dist/flows.js +160 -0
  155. package/dist/flows.js.map +1 -0
  156. package/dist/index.d.ts +67 -0
  157. package/dist/index.d.ts.map +1 -0
  158. package/dist/index.js +59 -0
  159. package/dist/index.js.map +1 -0
  160. package/dist/integrations/pluresdb.d.ts +56 -0
  161. package/dist/integrations/pluresdb.d.ts.map +1 -0
  162. package/dist/integrations/pluresdb.js +46 -0
  163. package/dist/integrations/pluresdb.js.map +1 -0
  164. package/dist/integrations/svelte.d.ts +306 -0
  165. package/dist/integrations/svelte.d.ts.map +1 -0
  166. package/dist/integrations/svelte.js +447 -0
  167. package/dist/integrations/svelte.js.map +1 -0
  168. package/dist/registry.d.ts +94 -0
  169. package/dist/registry.d.ts.map +1 -0
  170. package/dist/registry.js +181 -0
  171. package/dist/registry.js.map +1 -0
  172. package/dist/runtime/terminal-adapter.d.ts +105 -0
  173. package/dist/runtime/terminal-adapter.d.ts.map +1 -0
  174. package/dist/runtime/terminal-adapter.js +113 -0
  175. package/dist/runtime/terminal-adapter.js.map +1 -0
  176. package/dist/step.d.ts +34 -0
  177. package/dist/step.d.ts.map +1 -0
  178. package/dist/step.js +111 -0
  179. package/dist/step.js.map +1 -0
  180. package/dist/types.d.ts +63 -0
  181. package/dist/types.d.ts.map +1 -0
  182. package/dist/types.js +6 -0
  183. package/dist/types.js.map +1 -0
  184. package/docs/MONETIZATION.md +394 -0
  185. package/docs/TERMINAL_NODE.md +588 -0
  186. package/docs/guides/canvas.md +389 -0
  187. package/docs/guides/getting-started.md +347 -0
  188. package/docs/guides/history-state-pattern.md +618 -0
  189. package/docs/guides/orchestration.md +617 -0
  190. package/docs/guides/parallel-state-pattern.md +767 -0
  191. package/docs/guides/svelte-integration.md +691 -0
  192. package/package.json +96 -0
  193. package/src/__tests__/actors.test.ts +270 -0
  194. package/src/__tests__/billing.test.ts +175 -0
  195. package/src/__tests__/cloud.test.ts +247 -0
  196. package/src/__tests__/dsl.test.ts +154 -0
  197. package/src/__tests__/edge-cases.test.ts +475 -0
  198. package/src/__tests__/engine.test.ts +137 -0
  199. package/src/__tests__/generators.test.ts +270 -0
  200. package/src/__tests__/introspection.test.ts +321 -0
  201. package/src/__tests__/protocol.test.ts +40 -0
  202. package/src/__tests__/provisioning.test.ts +162 -0
  203. package/src/__tests__/schema.test.ts +241 -0
  204. package/src/__tests__/svelte-integration.test.ts +431 -0
  205. package/src/__tests__/terminal-node.test.ts +352 -0
  206. package/src/adapters/cli.ts +175 -0
  207. package/src/cli/commands/auth.ts +271 -0
  208. package/src/cli/commands/cloud.ts +281 -0
  209. package/src/cli/commands/generate.ts +225 -0
  210. package/src/cli/index.ts +190 -0
  211. package/src/cloud/README.md +383 -0
  212. package/src/cloud/auth.ts +245 -0
  213. package/src/cloud/billing.ts +336 -0
  214. package/src/cloud/client.ts +221 -0
  215. package/src/cloud/index.ts +121 -0
  216. package/src/cloud/marketplace.ts +303 -0
  217. package/src/cloud/provisioning.ts +254 -0
  218. package/src/cloud/relay/endpoints.ts +307 -0
  219. package/src/cloud/relay/health/function.json +17 -0
  220. package/src/cloud/relay/health/index.ts +10 -0
  221. package/src/cloud/relay/host.json +15 -0
  222. package/src/cloud/relay/local.settings.json +8 -0
  223. package/src/cloud/relay/stats/function.json +17 -0
  224. package/src/cloud/relay/stats/index.ts +10 -0
  225. package/src/cloud/relay/sync/function.json +17 -0
  226. package/src/cloud/relay/sync/index.ts +10 -0
  227. package/src/cloud/relay/usage/function.json +17 -0
  228. package/src/cloud/relay/usage/index.ts +10 -0
  229. package/src/cloud/sponsors.ts +213 -0
  230. package/src/cloud/types.ts +198 -0
  231. package/src/components/README.md +125 -0
  232. package/src/components/TerminalNode.svelte +457 -0
  233. package/src/components/index.ts +46 -0
  234. package/src/core/actors.ts +205 -0
  235. package/src/core/component/generator.ts +432 -0
  236. package/src/core/engine.ts +243 -0
  237. package/src/core/introspection.ts +329 -0
  238. package/src/core/logic/generator.ts +420 -0
  239. package/src/core/pluresdb/generator.ts +229 -0
  240. package/src/core/protocol.ts +132 -0
  241. package/src/core/rules.ts +167 -0
  242. package/src/core/schema/loader.ts +247 -0
  243. package/src/core/schema/normalize.ts +322 -0
  244. package/src/core/schema/types.ts +557 -0
  245. package/src/dsl/index.ts +218 -0
  246. package/src/dsl.ts +214 -0
  247. package/src/examples/advanced-todo/App.svelte +506 -0
  248. package/src/examples/advanced-todo/README.md +371 -0
  249. package/src/examples/advanced-todo/index.ts +309 -0
  250. package/src/examples/auth-basic/index.ts +163 -0
  251. package/src/examples/cart/index.ts +259 -0
  252. package/src/examples/hero-ecommerce/index.ts +657 -0
  253. package/src/examples/svelte-counter/index.ts +168 -0
  254. package/src/flows.ts +268 -0
  255. package/src/index.ts +154 -0
  256. package/src/integrations/pluresdb.ts +93 -0
  257. package/src/integrations/svelte.ts +617 -0
  258. package/src/registry.ts +223 -0
  259. package/src/runtime/terminal-adapter.ts +175 -0
  260. package/src/step.ts +151 -0
  261. package/src/types.ts +70 -0
  262. package/templates/basic-app/README.md +147 -0
  263. package/templates/fullstack-app/README.md +279 -0
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Praxis Schema Normalizer
3
+ *
4
+ * Expands and normalizes schema definitions for code generation.
5
+ */
6
+
7
+ import type {
8
+ PraxisSchema,
9
+ ModelDefinition,
10
+ ComponentDefinition,
11
+ LogicDefinition,
12
+ FieldDefinition,
13
+ } from './types.js';
14
+
15
+ /**
16
+ * Normalized schema with expanded and validated definitions
17
+ */
18
+ export interface NormalizedSchema extends PraxisSchema {
19
+ /** Normalized models with expanded references */
20
+ models: NormalizedModel[];
21
+ /** Normalized components */
22
+ components: NormalizedComponent[];
23
+ /** Normalized logic */
24
+ logic: NormalizedLogic[];
25
+ }
26
+
27
+ /**
28
+ * Normalized model definition
29
+ */
30
+ export interface NormalizedModel extends ModelDefinition {
31
+ /** Fully qualified name */
32
+ fullName: string;
33
+ /** All fields including inherited ones */
34
+ allFields: FieldDefinition[];
35
+ /** Model dependencies */
36
+ dependencies: string[];
37
+ }
38
+
39
+ /**
40
+ * Normalized component definition
41
+ */
42
+ export interface NormalizedComponent extends ComponentDefinition {
43
+ /** Fully qualified name */
44
+ fullName: string;
45
+ /** Resolved model reference */
46
+ resolvedModel?: NormalizedModel;
47
+ }
48
+
49
+ /**
50
+ * Normalized logic definition
51
+ */
52
+ export interface NormalizedLogic extends LogicDefinition {
53
+ /** Fully qualified identifier */
54
+ fullId: string;
55
+ }
56
+
57
+ /**
58
+ * Normalization options
59
+ */
60
+ export interface NormalizationOptions {
61
+ /** Schema name prefix for fully qualified names */
62
+ schemaPrefix?: string;
63
+ /** Expand all field references */
64
+ expandReferences?: boolean;
65
+ /** Include computed metadata */
66
+ includeMetadata?: boolean;
67
+ }
68
+
69
+ /**
70
+ * Normalize a Praxis schema for code generation
71
+ */
72
+ export function normalizeSchema(
73
+ schema: PraxisSchema,
74
+ options: NormalizationOptions = {}
75
+ ): NormalizedSchema {
76
+ const schemaPrefix = options.schemaPrefix || schema.name;
77
+
78
+ // Normalize models
79
+ const normalizedModels = normalizeModels(
80
+ schema.models || [],
81
+ schemaPrefix,
82
+ options
83
+ );
84
+
85
+ // Create model lookup map
86
+ const modelMap = new Map(
87
+ normalizedModels.map((model) => [model.name, model])
88
+ );
89
+
90
+ // Normalize components
91
+ const normalizedComponents = normalizeComponents(
92
+ schema.components || [],
93
+ schemaPrefix,
94
+ modelMap,
95
+ options
96
+ );
97
+
98
+ // Normalize logic
99
+ const normalizedLogic = normalizeLogic(
100
+ schema.logic || [],
101
+ schemaPrefix,
102
+ options
103
+ );
104
+
105
+ return {
106
+ ...schema,
107
+ models: normalizedModels,
108
+ components: normalizedComponents,
109
+ logic: normalizedLogic,
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Normalize model definitions
115
+ */
116
+ function normalizeModels(
117
+ models: ModelDefinition[],
118
+ schemaPrefix: string,
119
+ _options: NormalizationOptions
120
+ ): NormalizedModel[] {
121
+ return models.map((model) => {
122
+ const fullName = `${schemaPrefix}.${model.name}`;
123
+ const dependencies = extractModelDependencies(model);
124
+
125
+ // For now, allFields is the same as fields
126
+ // In the future, this could include inherited fields
127
+ const allFields = [...model.fields];
128
+
129
+ return {
130
+ ...model,
131
+ fullName,
132
+ allFields,
133
+ dependencies,
134
+ };
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Extract model dependencies from field references
140
+ */
141
+ function extractModelDependencies(model: ModelDefinition): string[] {
142
+ const dependencies = new Set<string>();
143
+
144
+ for (const field of model.fields) {
145
+ if (typeof field.type === 'object' && 'reference' in field.type) {
146
+ dependencies.add(field.type.reference);
147
+ }
148
+ }
149
+
150
+ // Add relationship dependencies
151
+ if (model.relationships) {
152
+ for (const rel of model.relationships) {
153
+ dependencies.add(rel.target);
154
+ }
155
+ }
156
+
157
+ return Array.from(dependencies);
158
+ }
159
+
160
+ /**
161
+ * Normalize component definitions
162
+ */
163
+ function normalizeComponents(
164
+ components: ComponentDefinition[],
165
+ schemaPrefix: string,
166
+ modelMap: Map<string, NormalizedModel>,
167
+ _options: NormalizationOptions
168
+ ): NormalizedComponent[] {
169
+ return components.map((component) => {
170
+ const fullName = `${schemaPrefix}.${component.name}`;
171
+ const resolvedModel = component.model
172
+ ? modelMap.get(component.model)
173
+ : undefined;
174
+
175
+ return {
176
+ ...component,
177
+ fullName,
178
+ resolvedModel,
179
+ };
180
+ });
181
+ }
182
+
183
+ /**
184
+ * Normalize logic definitions
185
+ */
186
+ function normalizeLogic(
187
+ logic: LogicDefinition[],
188
+ schemaPrefix: string,
189
+ _options: NormalizationOptions
190
+ ): NormalizedLogic[] {
191
+ return logic.map((logicDef) => {
192
+ const fullId = `${schemaPrefix}.${logicDef.id}`;
193
+
194
+ return {
195
+ ...logicDef,
196
+ fullId,
197
+ };
198
+ });
199
+ }
200
+
201
+ /**
202
+ * Expand field type to fully qualified type string
203
+ */
204
+ export function expandFieldType(
205
+ fieldType: any,
206
+ schemaPrefix: string = ''
207
+ ): string {
208
+ if (typeof fieldType === 'string') {
209
+ return fieldType;
210
+ }
211
+
212
+ if (typeof fieldType === 'object') {
213
+ if ('array' in fieldType) {
214
+ const innerType = expandFieldType(fieldType.array, schemaPrefix);
215
+ return `${innerType}[]`;
216
+ }
217
+
218
+ if ('object' in fieldType) {
219
+ return 'object';
220
+ }
221
+
222
+ if ('reference' in fieldType) {
223
+ const refName = fieldType.reference;
224
+ return schemaPrefix ? `${schemaPrefix}.${refName}` : refName;
225
+ }
226
+ }
227
+
228
+ return 'unknown';
229
+ }
230
+
231
+ /**
232
+ * Generate TypeScript type from field type
233
+ */
234
+ export function fieldTypeToTypeScript(fieldType: any): string {
235
+ if (typeof fieldType === 'string') {
236
+ switch (fieldType) {
237
+ case 'string':
238
+ return 'string';
239
+ case 'number':
240
+ return 'number';
241
+ case 'boolean':
242
+ return 'boolean';
243
+ case 'date':
244
+ return 'Date';
245
+ case 'array':
246
+ return 'unknown[]';
247
+ case 'object':
248
+ return 'Record<string, unknown>';
249
+ default:
250
+ return 'unknown';
251
+ }
252
+ }
253
+
254
+ if (typeof fieldType === 'object') {
255
+ if ('array' in fieldType) {
256
+ const innerType = fieldTypeToTypeScript(fieldType.array);
257
+ return `${innerType}[]`;
258
+ }
259
+
260
+ if ('object' in fieldType) {
261
+ const fields = fieldType.object;
262
+ const fieldTypes = Object.entries(fields)
263
+ .map(([key, field]: [string, any]) => {
264
+ const type = fieldTypeToTypeScript(field.type || field);
265
+ return `${key}: ${type}`;
266
+ })
267
+ .join('; ');
268
+ return `{ ${fieldTypes} }`;
269
+ }
270
+
271
+ if ('reference' in fieldType) {
272
+ return fieldType.reference;
273
+ }
274
+ }
275
+
276
+ return 'unknown';
277
+ }
278
+
279
+ /**
280
+ * Sort models by dependency order (models with no dependencies first)
281
+ */
282
+ export function sortModelsByDependencies(
283
+ models: NormalizedModel[]
284
+ ): NormalizedModel[] {
285
+ const sorted: NormalizedModel[] = [];
286
+ const visited = new Set<string>();
287
+ const visiting = new Set<string>();
288
+
289
+ function visit(model: NormalizedModel) {
290
+ if (visited.has(model.name)) {
291
+ return;
292
+ }
293
+
294
+ if (visiting.has(model.name)) {
295
+ // Circular dependency detected, just add it
296
+ visiting.delete(model.name);
297
+ sorted.push(model);
298
+ visited.add(model.name);
299
+ return;
300
+ }
301
+
302
+ visiting.add(model.name);
303
+
304
+ // Visit dependencies first
305
+ for (const depName of model.dependencies) {
306
+ const dep = models.find((m) => m.name === depName);
307
+ if (dep) {
308
+ visit(dep);
309
+ }
310
+ }
311
+
312
+ visiting.delete(model.name);
313
+ visited.add(model.name);
314
+ sorted.push(model);
315
+ }
316
+
317
+ for (const model of models) {
318
+ visit(model);
319
+ }
320
+
321
+ return sorted;
322
+ }