fragment-ts 2.0.3 → 2.0.4

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 (258) hide show
  1. package/dist/platform/cli/commands/install/command.d.ts +14 -0
  2. package/dist/platform/cli/commands/install/command.d.ts.map +1 -0
  3. package/dist/platform/cli/commands/install/command.js +145 -0
  4. package/dist/platform/cli/commands/install/command.js.map +1 -0
  5. package/dist/platform/cli/commands/register.d.ts.map +1 -1
  6. package/dist/platform/cli/commands/register.js +37 -28
  7. package/dist/platform/cli/commands/register.js.map +1 -1
  8. package/dist/platform/cli/index.js +61 -1
  9. package/dist/platform/cli/index.js.map +1 -1
  10. package/dist/platform/cli/web/commands/create/feature.d.ts +11 -0
  11. package/dist/platform/cli/web/commands/create/feature.d.ts.map +1 -0
  12. package/dist/platform/cli/web/commands/create/feature.js +43 -0
  13. package/dist/platform/cli/web/commands/create/feature.js.map +1 -0
  14. package/dist/platform/cli/web/commands/create/module.d.ts +11 -0
  15. package/dist/platform/cli/web/commands/create/module.d.ts.map +1 -0
  16. package/dist/platform/cli/web/commands/create/module.js +44 -0
  17. package/dist/platform/cli/web/commands/create/module.js.map +1 -0
  18. package/dist/platform/cli/web/commands/create/mvvm.d.ts +11 -0
  19. package/dist/platform/cli/web/commands/create/mvvm.d.ts.map +1 -0
  20. package/dist/platform/cli/web/commands/create/mvvm.js +43 -0
  21. package/dist/platform/cli/web/commands/create/mvvm.js.map +1 -0
  22. package/dist/platform/cli/web/commands/init-fullstack.d.ts +12 -0
  23. package/dist/platform/cli/web/commands/init-fullstack.d.ts.map +1 -0
  24. package/dist/platform/cli/web/commands/init-fullstack.js +42 -0
  25. package/dist/platform/cli/web/commands/init-fullstack.js.map +1 -0
  26. package/dist/platform/cli/web/commands/init-web.d.ts +12 -0
  27. package/dist/platform/cli/web/commands/init-web.d.ts.map +1 -0
  28. package/dist/platform/cli/web/commands/init-web.js +70 -0
  29. package/dist/platform/cli/web/commands/init-web.js.map +1 -0
  30. package/dist/platform/cli/web/commands/install-api.d.ts +11 -0
  31. package/dist/platform/cli/web/commands/install-api.d.ts.map +1 -0
  32. package/dist/platform/cli/web/commands/install-api.js +92 -0
  33. package/dist/platform/cli/web/commands/install-api.js.map +1 -0
  34. package/dist/platform/cli/web/commands/install-web.d.ts +13 -0
  35. package/dist/platform/cli/web/commands/install-web.d.ts.map +1 -0
  36. package/dist/platform/cli/web/commands/install-web.js +102 -0
  37. package/dist/platform/cli/web/commands/install-web.js.map +1 -0
  38. package/dist/platform/cli/web/commands/install.d.ts +3 -0
  39. package/dist/platform/cli/web/commands/install.d.ts.map +1 -0
  40. package/dist/platform/cli/web/commands/install.js +23 -0
  41. package/dist/platform/cli/web/commands/install.js.map +1 -0
  42. package/dist/platform/cli/web/commands/make/component.d.ts +16 -0
  43. package/dist/platform/cli/web/commands/make/component.d.ts.map +1 -0
  44. package/dist/platform/cli/web/commands/make/component.js +73 -0
  45. package/dist/platform/cli/web/commands/make/component.js.map +1 -0
  46. package/dist/platform/cli/web/commands/make/guard.d.ts +13 -0
  47. package/dist/platform/cli/web/commands/make/guard.d.ts.map +1 -0
  48. package/dist/platform/cli/web/commands/make/guard.js +46 -0
  49. package/dist/platform/cli/web/commands/make/guard.js.map +1 -0
  50. package/dist/platform/cli/web/commands/make/layout.d.ts +12 -0
  51. package/dist/platform/cli/web/commands/make/layout.d.ts.map +1 -0
  52. package/dist/platform/cli/web/commands/make/layout.js +44 -0
  53. package/dist/platform/cli/web/commands/make/layout.js.map +1 -0
  54. package/dist/platform/cli/web/commands/make/page.d.ts +17 -0
  55. package/dist/platform/cli/web/commands/make/page.d.ts.map +1 -0
  56. package/dist/platform/cli/web/commands/make/page.js +66 -0
  57. package/dist/platform/cli/web/commands/make/page.js.map +1 -0
  58. package/dist/platform/cli/web/commands/make/resource.d.ts +17 -0
  59. package/dist/platform/cli/web/commands/make/resource.d.ts.map +1 -0
  60. package/dist/platform/cli/web/commands/make/resource.js +37 -0
  61. package/dist/platform/cli/web/commands/make/resource.js.map +1 -0
  62. package/dist/platform/cli/web/commands/make/service.d.ts +16 -0
  63. package/dist/platform/cli/web/commands/make/service.d.ts.map +1 -0
  64. package/dist/platform/cli/web/commands/make/service.js +137 -0
  65. package/dist/platform/cli/web/commands/make/service.js.map +1 -0
  66. package/dist/platform/cli/web/commands/make/store.d.ts +16 -0
  67. package/dist/platform/cli/web/commands/make/store.d.ts.map +1 -0
  68. package/dist/platform/cli/web/commands/make/store.js +72 -0
  69. package/dist/platform/cli/web/commands/make/store.js.map +1 -0
  70. package/dist/platform/cli/web/commands/web-sync.d.ts +10 -0
  71. package/dist/platform/cli/web/commands/web-sync.d.ts.map +1 -0
  72. package/dist/platform/cli/web/commands/web-sync.js +307 -0
  73. package/dist/platform/cli/web/commands/web-sync.js.map +1 -0
  74. package/dist/platform/cli/web/index.d.ts +3 -0
  75. package/dist/platform/cli/web/index.d.ts.map +1 -0
  76. package/dist/platform/cli/web/index.js +40 -0
  77. package/dist/platform/cli/web/index.js.map +1 -0
  78. package/dist/platform/cli/web/utils/config.d.ts +52 -0
  79. package/dist/platform/cli/web/utils/config.d.ts.map +1 -0
  80. package/dist/platform/cli/web/utils/config.js +89 -0
  81. package/dist/platform/cli/web/utils/config.js.map +1 -0
  82. package/dist/platform/cli/web/utils/format.d.ts +2 -0
  83. package/dist/platform/cli/web/utils/format.d.ts.map +1 -0
  84. package/dist/platform/cli/web/utils/format.js +28 -0
  85. package/dist/platform/cli/web/utils/format.js.map +1 -0
  86. package/dist/platform/cli/web/utils/header.d.ts +3 -0
  87. package/dist/platform/cli/web/utils/header.d.ts.map +1 -0
  88. package/dist/platform/cli/web/utils/header.js +11 -0
  89. package/dist/platform/cli/web/utils/header.js.map +1 -0
  90. package/dist/platform/cli/web/utils/logger.d.ts +10 -0
  91. package/dist/platform/cli/web/utils/logger.d.ts.map +1 -0
  92. package/dist/platform/cli/web/utils/logger.js +47 -0
  93. package/dist/platform/cli/web/utils/logger.js.map +1 -0
  94. package/dist/platform/cli/web/utils/names.d.ts +7 -0
  95. package/dist/platform/cli/web/utils/names.d.ts.map +1 -0
  96. package/dist/platform/cli/web/utils/names.js +43 -0
  97. package/dist/platform/cli/web/utils/names.js.map +1 -0
  98. package/dist/platform/cli/web/utils/resolve-paths.d.ts +10 -0
  99. package/dist/platform/cli/web/utils/resolve-paths.d.ts.map +1 -0
  100. package/dist/platform/cli/web/utils/resolve-paths.js +87 -0
  101. package/dist/platform/cli/web/utils/resolve-paths.js.map +1 -0
  102. package/dist/platform/cli/web/utils/write-file.d.ts +7 -0
  103. package/dist/platform/cli/web/utils/write-file.d.ts.map +1 -0
  104. package/dist/platform/cli/web/utils/write-file.js +31 -0
  105. package/dist/platform/cli/web/utils/write-file.js.map +1 -0
  106. package/dist/web/cli/commands/create/feature.d.ts +11 -0
  107. package/dist/web/cli/commands/create/feature.d.ts.map +1 -0
  108. package/dist/web/cli/commands/create/feature.js +43 -0
  109. package/dist/web/cli/commands/create/feature.js.map +1 -0
  110. package/dist/web/cli/commands/create/module.d.ts +11 -0
  111. package/dist/web/cli/commands/create/module.d.ts.map +1 -0
  112. package/dist/web/cli/commands/create/module.js +44 -0
  113. package/dist/web/cli/commands/create/module.js.map +1 -0
  114. package/dist/web/cli/commands/create/mvvm.d.ts +11 -0
  115. package/dist/web/cli/commands/create/mvvm.d.ts.map +1 -0
  116. package/dist/web/cli/commands/create/mvvm.js +43 -0
  117. package/dist/web/cli/commands/create/mvvm.js.map +1 -0
  118. package/dist/web/cli/commands/init-fullstack.d.ts +12 -0
  119. package/dist/web/cli/commands/init-fullstack.d.ts.map +1 -0
  120. package/dist/web/cli/commands/init-fullstack.js +42 -0
  121. package/dist/web/cli/commands/init-fullstack.js.map +1 -0
  122. package/dist/web/cli/commands/init-web.d.ts +12 -0
  123. package/dist/web/cli/commands/init-web.d.ts.map +1 -0
  124. package/dist/web/cli/commands/init-web.js +70 -0
  125. package/dist/web/cli/commands/init-web.js.map +1 -0
  126. package/dist/web/cli/commands/install-api.d.ts +10 -0
  127. package/dist/web/cli/commands/install-api.d.ts.map +1 -0
  128. package/dist/web/cli/commands/install-api.js +91 -0
  129. package/dist/web/cli/commands/install-api.js.map +1 -0
  130. package/dist/web/cli/commands/install-web.d.ts +12 -0
  131. package/dist/web/cli/commands/install-web.d.ts.map +1 -0
  132. package/dist/web/cli/commands/install-web.js +101 -0
  133. package/dist/web/cli/commands/install-web.js.map +1 -0
  134. package/dist/web/cli/commands/make/component.d.ts +13 -0
  135. package/dist/web/cli/commands/make/component.d.ts.map +1 -0
  136. package/dist/web/cli/commands/make/component.js +40 -0
  137. package/dist/web/cli/commands/make/component.js.map +1 -0
  138. package/dist/web/cli/commands/make/guard.d.ts +11 -0
  139. package/dist/web/cli/commands/make/guard.d.ts.map +1 -0
  140. package/dist/web/cli/commands/make/guard.js +37 -0
  141. package/dist/web/cli/commands/make/guard.js.map +1 -0
  142. package/dist/web/cli/commands/make/layout.d.ts +11 -0
  143. package/dist/web/cli/commands/make/layout.d.ts.map +1 -0
  144. package/dist/web/cli/commands/make/layout.js +37 -0
  145. package/dist/web/cli/commands/make/layout.js.map +1 -0
  146. package/dist/web/cli/commands/make/page.d.ts +14 -0
  147. package/dist/web/cli/commands/make/page.d.ts.map +1 -0
  148. package/dist/web/cli/commands/make/page.js +42 -0
  149. package/dist/web/cli/commands/make/page.js.map +1 -0
  150. package/dist/web/cli/commands/make/resource.d.ts +13 -0
  151. package/dist/web/cli/commands/make/resource.d.ts.map +1 -0
  152. package/dist/web/cli/commands/make/resource.js +33 -0
  153. package/dist/web/cli/commands/make/resource.js.map +1 -0
  154. package/dist/web/cli/commands/make/service.d.ts +14 -0
  155. package/dist/web/cli/commands/make/service.d.ts.map +1 -0
  156. package/dist/web/cli/commands/make/service.js +56 -0
  157. package/dist/web/cli/commands/make/service.js.map +1 -0
  158. package/dist/web/cli/commands/make/store.d.ts +14 -0
  159. package/dist/web/cli/commands/make/store.d.ts.map +1 -0
  160. package/dist/web/cli/commands/make/store.js +47 -0
  161. package/dist/web/cli/commands/make/store.js.map +1 -0
  162. package/dist/web/cli/commands/web-sync.d.ts +10 -0
  163. package/dist/web/cli/commands/web-sync.d.ts.map +1 -0
  164. package/dist/web/cli/commands/web-sync.js +48 -0
  165. package/dist/web/cli/commands/web-sync.js.map +1 -0
  166. package/dist/web/cli/index.d.mts +5 -0
  167. package/dist/web/cli/index.d.ts +5 -0
  168. package/dist/web/cli/index.d.ts.map +1 -0
  169. package/dist/web/cli/index.js +36 -0
  170. package/dist/web/cli/index.js.map +1 -0
  171. package/dist/web/cli/index.mjs +984 -0
  172. package/dist/web/cli/utils/config.d.ts +52 -0
  173. package/dist/web/cli/utils/config.d.ts.map +1 -0
  174. package/dist/web/cli/utils/config.js +89 -0
  175. package/dist/web/cli/utils/config.js.map +1 -0
  176. package/dist/web/cli/utils/format.d.ts +2 -0
  177. package/dist/web/cli/utils/format.d.ts.map +1 -0
  178. package/dist/web/cli/utils/format.js +28 -0
  179. package/dist/web/cli/utils/format.js.map +1 -0
  180. package/dist/web/cli/utils/logger.d.ts +10 -0
  181. package/dist/web/cli/utils/logger.d.ts.map +1 -0
  182. package/dist/web/cli/utils/logger.js +34 -0
  183. package/dist/web/cli/utils/logger.js.map +1 -0
  184. package/dist/web/cli/utils/names.d.ts +7 -0
  185. package/dist/web/cli/utils/names.d.ts.map +1 -0
  186. package/dist/web/cli/utils/names.js +43 -0
  187. package/dist/web/cli/utils/names.js.map +1 -0
  188. package/dist/web/cli/utils/resolve-paths.d.ts +10 -0
  189. package/dist/web/cli/utils/resolve-paths.d.ts.map +1 -0
  190. package/dist/web/cli/utils/resolve-paths.js +87 -0
  191. package/dist/web/cli/utils/resolve-paths.js.map +1 -0
  192. package/dist/web/cli/utils/write-file.d.ts +7 -0
  193. package/dist/web/cli/utils/write-file.d.ts.map +1 -0
  194. package/dist/web/cli/utils/write-file.js +31 -0
  195. package/dist/web/cli/utils/write-file.js.map +1 -0
  196. package/dist/web/platform/cli/web/index.d.mts +5 -0
  197. package/dist/web/platform/cli/web/index.d.ts +5 -0
  198. package/dist/web/platform/cli/web/index.js +2035 -0
  199. package/dist/web/platform/cli/web/index.mjs +1998 -0
  200. package/dist/web/src/adapters/jotai.d.ts +2 -0
  201. package/dist/web/src/adapters/jotai.d.ts.map +1 -0
  202. package/dist/web/src/adapters/jotai.js +7 -0
  203. package/dist/web/src/adapters/jotai.js.map +1 -0
  204. package/dist/web/src/adapters/mobx.d.ts +2 -0
  205. package/dist/web/src/adapters/mobx.d.ts.map +1 -0
  206. package/dist/web/src/adapters/mobx.js +7 -0
  207. package/dist/web/src/adapters/mobx.js.map +1 -0
  208. package/dist/web/src/adapters/redux.d.ts +2 -0
  209. package/dist/web/src/adapters/redux.d.ts.map +1 -0
  210. package/dist/web/src/adapters/redux.js +7 -0
  211. package/dist/web/src/adapters/redux.js.map +1 -0
  212. package/dist/web/src/adapters/zustand.d.ts +2 -0
  213. package/dist/web/src/adapters/zustand.d.ts.map +1 -0
  214. package/dist/web/src/adapters/zustand.js +7 -0
  215. package/dist/web/src/adapters/zustand.js.map +1 -0
  216. package/dist/web/src/config/web-config.d.ts +34 -0
  217. package/dist/web/src/config/web-config.d.ts.map +1 -0
  218. package/dist/web/src/config/web-config.js +73 -0
  219. package/dist/web/src/config/web-config.js.map +1 -0
  220. package/dist/web/src/core/application.d.ts +8 -0
  221. package/dist/web/src/core/application.d.ts.map +1 -0
  222. package/dist/web/src/core/application.js +45 -0
  223. package/dist/web/src/core/application.js.map +1 -0
  224. package/dist/web/src/core/decorators/component.d.ts +20 -0
  225. package/dist/web/src/core/decorators/component.d.ts.map +1 -0
  226. package/dist/web/src/core/decorators/component.js +83 -0
  227. package/dist/web/src/core/decorators/component.js.map +1 -0
  228. package/dist/web/src/core/decorators/page.d.ts +27 -0
  229. package/dist/web/src/core/decorators/page.d.ts.map +1 -0
  230. package/dist/web/src/core/decorators/page.js +58 -0
  231. package/dist/web/src/core/decorators/page.js.map +1 -0
  232. package/dist/web/src/core/di/container.d.ts +8 -0
  233. package/dist/web/src/core/di/container.d.ts.map +1 -0
  234. package/dist/web/src/core/di/container.js +26 -0
  235. package/dist/web/src/core/di/container.js.map +1 -0
  236. package/dist/web/src/core/runtime.d.ts +3 -0
  237. package/dist/web/src/core/runtime.d.ts.map +1 -0
  238. package/dist/web/src/core/runtime.js +15 -0
  239. package/dist/web/src/core/runtime.js.map +1 -0
  240. package/dist/web/src/http/fragment-fetch.d.ts +55 -0
  241. package/dist/web/src/http/fragment-fetch.d.ts.map +1 -0
  242. package/dist/web/src/http/fragment-fetch.js +290 -0
  243. package/dist/web/src/http/fragment-fetch.js.map +1 -0
  244. package/dist/web/src/index.d.mts +137 -0
  245. package/dist/web/src/index.d.ts +7 -0
  246. package/dist/web/src/index.d.ts.map +1 -0
  247. package/dist/web/src/index.js +31 -0
  248. package/dist/web/src/index.js.map +1 -0
  249. package/dist/web/src/index.mjs +643 -0
  250. package/dist/web/src/router/fragment-router.d.ts +14 -0
  251. package/dist/web/src/router/fragment-router.d.ts.map +1 -0
  252. package/dist/web/src/router/fragment-router.js +94 -0
  253. package/dist/web/src/router/fragment-router.js.map +1 -0
  254. package/dist/web/web/src/index.d.mts +137 -0
  255. package/dist/web/web/src/index.d.ts +137 -0
  256. package/dist/web/web/src/index.js +702 -0
  257. package/dist/web/web/src/index.mjs +644 -0
  258. package/package.json +15 -3
@@ -0,0 +1,644 @@
1
+ // src/web/src/http/fragment-fetch.ts
2
+ var FragmentHttpError = class extends Error {
3
+ constructor(message, init) {
4
+ super(message);
5
+ this.name = "FragmentHttpError";
6
+ this.status = init.status;
7
+ this.statusText = init.statusText;
8
+ this.body = init.body;
9
+ this.request = init.request;
10
+ this.response = init.response;
11
+ }
12
+ };
13
+ var memoryTokenState = { token: null };
14
+ var FragmentFetchClient = class {
15
+ constructor() {
16
+ this.config = {
17
+ baseUrl: "",
18
+ timeout: 1e4,
19
+ retries: 0,
20
+ retryDelay: 300,
21
+ headers: {},
22
+ tokenTransport: "cookie",
23
+ tokenKey: "fragment_token",
24
+ onUnauthorized: "throw",
25
+ onForbidden: "throw",
26
+ onError: void 0
27
+ };
28
+ this.requestInterceptors = [];
29
+ this.responseInterceptors = [];
30
+ }
31
+ configure(config) {
32
+ this.config = {
33
+ ...this.config,
34
+ ...config,
35
+ headers: {
36
+ ...this.config.headers,
37
+ ...config.headers || {}
38
+ }
39
+ };
40
+ }
41
+ setToken(token) {
42
+ memoryTokenState.token = token;
43
+ if (this.config.tokenTransport === "localStorage" && typeof window !== "undefined") {
44
+ window.localStorage.setItem(this.config.tokenKey, token);
45
+ }
46
+ }
47
+ clearToken() {
48
+ memoryTokenState.token = null;
49
+ if (this.config.tokenTransport === "localStorage" && typeof window !== "undefined") {
50
+ window.localStorage.removeItem(this.config.tokenKey);
51
+ }
52
+ }
53
+ getToken() {
54
+ if (this.config.tokenTransport === "memory") {
55
+ return memoryTokenState.token;
56
+ }
57
+ if (this.config.tokenTransport === "localStorage" && typeof window !== "undefined") {
58
+ return window.localStorage.getItem(this.config.tokenKey);
59
+ }
60
+ return null;
61
+ }
62
+ addRequestInterceptor(fn) {
63
+ this.requestInterceptors.push(fn);
64
+ return () => {
65
+ this.requestInterceptors = this.requestInterceptors.filter((it) => it !== fn);
66
+ };
67
+ }
68
+ addResponseInterceptor(fn) {
69
+ this.responseInterceptors.push(fn);
70
+ return () => {
71
+ this.responseInterceptors = this.responseInterceptors.filter((it) => it !== fn);
72
+ };
73
+ }
74
+ get(path, options) {
75
+ return this.request(path, { method: "GET" }, options);
76
+ }
77
+ post(path, body, options) {
78
+ return this.request(path, { method: "POST", body: body ? JSON.stringify(body) : void 0 }, options);
79
+ }
80
+ put(path, body, options) {
81
+ return this.request(path, { method: "PUT", body: body ? JSON.stringify(body) : void 0 }, options);
82
+ }
83
+ patch(path, body, options) {
84
+ return this.request(path, { method: "PATCH", body: body ? JSON.stringify(body) : void 0 }, options);
85
+ }
86
+ delete(path, options) {
87
+ return this.request(path, { method: "DELETE" }, options);
88
+ }
89
+ async request(path, init = {}, options = {}) {
90
+ const url = this.buildUrl(path, options.params);
91
+ const headers = {
92
+ "Content-Type": "application/json",
93
+ ...this.config.headers,
94
+ ...options.headers
95
+ };
96
+ if (!options.skipAuth && this.config.tokenTransport !== "cookie") {
97
+ const token = this.getToken();
98
+ if (token) {
99
+ headers.Authorization = `Bearer ${token}`;
100
+ }
101
+ }
102
+ const controller = new AbortController();
103
+ const timeoutMs = options.timeout ?? this.config.timeout;
104
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
105
+ let request = new Request(url, {
106
+ ...init,
107
+ headers,
108
+ credentials: this.config.tokenTransport === "cookie" ? "include" : init.credentials,
109
+ signal: options.signal || controller.signal
110
+ });
111
+ for (const interceptor of this.requestInterceptors) {
112
+ request = await interceptor(request);
113
+ }
114
+ const retries = options.retries ?? this.config.retries;
115
+ try {
116
+ return await this.executeWithRetry(request, retries, this.config.retryDelay);
117
+ } catch (error) {
118
+ if (error instanceof FragmentHttpError) {
119
+ this.config.onError?.(error);
120
+ }
121
+ throw error;
122
+ } finally {
123
+ clearTimeout(timeout);
124
+ }
125
+ }
126
+ async executeWithRetry(request, retries, retryDelay) {
127
+ let attempt = 0;
128
+ let lastError = null;
129
+ while (attempt <= retries) {
130
+ try {
131
+ const response = await fetch(request.clone());
132
+ for (const interceptor of this.responseInterceptors) {
133
+ await interceptor(response, { request });
134
+ }
135
+ if (!response.ok) {
136
+ const body = await this.parseBody(response);
137
+ const error = new FragmentHttpError(`HTTP ${response.status}`, {
138
+ status: response.status,
139
+ statusText: response.statusText,
140
+ body,
141
+ request,
142
+ response
143
+ });
144
+ if (response.status === 401) {
145
+ const result = this.handleAuthMode(this.config.onUnauthorized);
146
+ if (result === "silent") return null;
147
+ }
148
+ if (response.status === 403) {
149
+ const result = this.handleAuthMode(this.config.onForbidden);
150
+ if (result === "silent") return null;
151
+ }
152
+ for (const interceptor of this.responseInterceptors) {
153
+ await interceptor(response, { request, error });
154
+ }
155
+ if (response.status >= 500 && attempt < retries) {
156
+ await this.delay(retryDelay);
157
+ attempt += 1;
158
+ continue;
159
+ }
160
+ throw error;
161
+ }
162
+ return await this.parseBody(response);
163
+ } catch (error) {
164
+ if (error instanceof FragmentHttpError) {
165
+ throw error;
166
+ }
167
+ if (error?.name === "AbortError") {
168
+ const syntheticResponse2 = new Response(null, { status: 408, statusText: "Request Timeout" });
169
+ throw new FragmentHttpError("Request timeout", {
170
+ status: 408,
171
+ statusText: "Request Timeout",
172
+ body: null,
173
+ request,
174
+ response: syntheticResponse2
175
+ });
176
+ }
177
+ lastError = error;
178
+ if (attempt >= retries) {
179
+ const syntheticResponse2 = new Response(null, { status: 503, statusText: "Service Unavailable" });
180
+ throw new FragmentHttpError(error?.message || "Network error", {
181
+ status: 503,
182
+ statusText: "Service Unavailable",
183
+ body: null,
184
+ request,
185
+ response: syntheticResponse2
186
+ });
187
+ }
188
+ await this.delay(retryDelay);
189
+ }
190
+ attempt += 1;
191
+ }
192
+ const syntheticResponse = new Response(null, { status: 503, statusText: "Service Unavailable" });
193
+ throw new FragmentHttpError("Request failed", {
194
+ status: 503,
195
+ statusText: "Service Unavailable",
196
+ body: lastError,
197
+ request,
198
+ response: syntheticResponse
199
+ });
200
+ }
201
+ async parseBody(response) {
202
+ const contentType = response.headers.get("content-type") || "";
203
+ if (contentType.includes("application/json")) {
204
+ return response.json();
205
+ }
206
+ const text = await response.text();
207
+ return text.length ? text : null;
208
+ }
209
+ buildUrl(path, params) {
210
+ const normalizedBase = this.config.baseUrl.replace(/\/$/, "");
211
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
212
+ const url = new URL(`${normalizedBase}${normalizedPath}`);
213
+ if (params) {
214
+ Object.entries(params).forEach(([key, value]) => {
215
+ if (Array.isArray(value)) {
216
+ value.forEach((v) => url.searchParams.append(key, String(v)));
217
+ return;
218
+ }
219
+ url.searchParams.append(key, String(value));
220
+ });
221
+ }
222
+ return url.toString();
223
+ }
224
+ handleAuthMode(mode) {
225
+ if (!mode || mode === "throw") {
226
+ return "throw";
227
+ }
228
+ if (mode === "silent") {
229
+ return "silent";
230
+ }
231
+ if (mode.startsWith("redirect:")) {
232
+ const to = mode.slice("redirect:".length);
233
+ if (typeof window !== "undefined") {
234
+ window.location.href = to;
235
+ }
236
+ }
237
+ return "throw";
238
+ }
239
+ async delay(ms) {
240
+ await new Promise((resolve) => setTimeout(resolve, ms));
241
+ }
242
+ };
243
+ var client = new FragmentFetchClient();
244
+ var FragmentFetch = {
245
+ configure(config) {
246
+ client.configure(config);
247
+ },
248
+ get(path, options) {
249
+ return client.get(path, options);
250
+ },
251
+ post(path, body, options) {
252
+ return client.post(path, body, options);
253
+ },
254
+ put(path, body, options) {
255
+ return client.put(path, body, options);
256
+ },
257
+ patch(path, body, options) {
258
+ return client.patch(path, body, options);
259
+ },
260
+ delete(path, options) {
261
+ return client.delete(path, options);
262
+ },
263
+ request(path, init, options) {
264
+ return client.request(path, init, options);
265
+ },
266
+ setToken(token) {
267
+ client.setToken(token);
268
+ },
269
+ clearToken() {
270
+ client.clearToken();
271
+ },
272
+ getToken() {
273
+ return client.getToken();
274
+ },
275
+ addRequestInterceptor(fn) {
276
+ return client.addRequestInterceptor(fn);
277
+ },
278
+ addResponseInterceptor(fn) {
279
+ return client.addResponseInterceptor(fn);
280
+ }
281
+ };
282
+
283
+ // src/web/src/core/application.tsx
284
+ import { StrictMode } from "react";
285
+ import { createRoot } from "react-dom/client";
286
+
287
+ // src/web/src/router/fragment-router.tsx
288
+ import { useEffect, useMemo, useState } from "react";
289
+ import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
290
+
291
+ // src/web/src/core/decorators/page.ts
292
+ var pageRegistry = [];
293
+ function Page(options) {
294
+ return (target) => {
295
+ pageRegistry.push({
296
+ target,
297
+ path: options.path,
298
+ title: options.title,
299
+ layout: options.layout
300
+ });
301
+ };
302
+ }
303
+ function Layout(options) {
304
+ return (target) => {
305
+ const found = pageRegistry.find((page) => page.target === target);
306
+ if (found) {
307
+ found.layout = options.name;
308
+ }
309
+ };
310
+ }
311
+ function Guard(guardClass) {
312
+ return (target) => {
313
+ const found = pageRegistry.find((page) => page.target === target);
314
+ if (found) {
315
+ found.guard = guardClass;
316
+ }
317
+ };
318
+ }
319
+ function Param(_name) {
320
+ return () => void 0;
321
+ }
322
+ function Query(_name, _defaultValue) {
323
+ return () => void 0;
324
+ }
325
+ function RedirectIfAuthenticated(to = "/") {
326
+ return (target) => {
327
+ const found = pageRegistry.find((page) => page.target === target);
328
+ if (found) {
329
+ found.redirectIfAuthenticated = to;
330
+ }
331
+ };
332
+ }
333
+ function getPages() {
334
+ return [...pageRegistry];
335
+ }
336
+
337
+ // src/web/src/core/runtime.tsx
338
+ import React from "react";
339
+ function renderPageInstance(PageClass) {
340
+ const instance = new PageClass();
341
+ if (typeof instance.render === "function") {
342
+ return instance.render();
343
+ }
344
+ return React.createElement("div", null, PageClass.name);
345
+ }
346
+
347
+ // src/web/src/router/fragment-router.tsx
348
+ import { jsx } from "react/jsx-runtime";
349
+ function prefixMatch(route, pathname) {
350
+ if (route === "/") return pathname === "/";
351
+ return pathname === route || pathname.startsWith(`${route}/`);
352
+ }
353
+ async function resolveSession(config) {
354
+ if (config.fetch.tokenTransport === "cookie") {
355
+ try {
356
+ await FragmentFetch.get("/auth/me", { skipAuth: true });
357
+ return true;
358
+ } catch {
359
+ return false;
360
+ }
361
+ }
362
+ return Boolean(FragmentFetch.getToken());
363
+ }
364
+ function routeNeedsAuth(path, config) {
365
+ return config.authenticatedRoutes.some((route) => prefixMatch(route, path));
366
+ }
367
+ function routeIsPublic(path, config) {
368
+ return config.publicRoutes.some((route) => prefixMatch(route, path));
369
+ }
370
+ function extractRedirectPath(mode, fallback = "/login") {
371
+ if (!mode) return fallback;
372
+ if (mode.startsWith("redirect:")) return mode.slice("redirect:".length);
373
+ return fallback;
374
+ }
375
+ function PageRoute({ page, config }) {
376
+ const [checking, setChecking] = useState(true);
377
+ const [authenticated, setAuthenticated] = useState(false);
378
+ const [guardAllowed, setGuardAllowed] = useState(true);
379
+ useEffect(() => {
380
+ let cancelled = false;
381
+ (async () => {
382
+ const isAuthed = await resolveSession(config);
383
+ if (cancelled) return;
384
+ setAuthenticated(isAuthed);
385
+ if (page.guard) {
386
+ const guard = new page.guard();
387
+ if (typeof guard.canActivate === "function") {
388
+ const result = await Promise.resolve(guard.canActivate());
389
+ if (!cancelled) {
390
+ setGuardAllowed(result !== false);
391
+ }
392
+ }
393
+ }
394
+ if (!cancelled) {
395
+ setChecking(false);
396
+ }
397
+ })();
398
+ return () => {
399
+ cancelled = true;
400
+ };
401
+ }, [config]);
402
+ if (checking) {
403
+ return /* @__PURE__ */ jsx("div", { children: "Loading..." });
404
+ }
405
+ const needsAuth = routeNeedsAuth(page.path, config);
406
+ const isPublic = routeIsPublic(page.path, config) || !needsAuth;
407
+ if (needsAuth && !authenticated) {
408
+ return /* @__PURE__ */ jsx(Navigate, { to: extractRedirectPath(config.fetch.onUnauthorized, "/login"), replace: true });
409
+ }
410
+ if (isPublic && page.redirectIfAuthenticated && authenticated) {
411
+ return /* @__PURE__ */ jsx(Navigate, { to: page.redirectIfAuthenticated, replace: true });
412
+ }
413
+ if (!guardAllowed) {
414
+ return /* @__PURE__ */ jsx(Navigate, { to: extractRedirectPath(config.fetch.onForbidden, "/403"), replace: true });
415
+ }
416
+ return renderPageInstance(page.target);
417
+ }
418
+ function FragmentRouter({ config }) {
419
+ const pages = useMemo(() => getPages(), []);
420
+ return /* @__PURE__ */ jsx(BrowserRouter, { basename: config.webRoot, children: /* @__PURE__ */ jsx(Routes, { children: pages.map((page) => /* @__PURE__ */ jsx(
421
+ Route,
422
+ {
423
+ path: page.path,
424
+ element: /* @__PURE__ */ jsx(PageRoute, { page, config })
425
+ },
426
+ page.path
427
+ )) }) });
428
+ }
429
+
430
+ // src/web/src/config/web-config.ts
431
+ function defaultWebConfig() {
432
+ return {
433
+ webRoot: "/",
434
+ serverRoot: "/api",
435
+ publicRoutes: ["/", "/login", "/register"],
436
+ authenticatedRoutes: ["/dashboard", "/profile", "/settings"],
437
+ app: {
438
+ name: "My App",
439
+ rootElement: "#root",
440
+ strict: true,
441
+ router: "react-router",
442
+ stateAdapter: "zustand"
443
+ },
444
+ fetch: {
445
+ baseUrl: "http://localhost:3000",
446
+ timeout: 1e4,
447
+ retries: 2,
448
+ retryDelay: 300,
449
+ tokenTransport: "cookie",
450
+ tokenKey: "fragment_token",
451
+ onUnauthorized: "redirect:/login",
452
+ onForbidden: "redirect:/403"
453
+ },
454
+ structure: "layered",
455
+ di: {
456
+ autoScan: true,
457
+ scanPaths: ["src/components", "src/pages", "src/services"]
458
+ }
459
+ };
460
+ }
461
+ function interpolateEnv(value) {
462
+ const match = value.match(/^\$\{([^:}]+):([^}]+)\}$/);
463
+ if (!match) return value;
464
+ const [, envName, fallback] = match;
465
+ const fromEnv = typeof process !== "undefined" ? process.env?.[envName] : void 0;
466
+ return fromEnv || fallback;
467
+ }
468
+ async function loadWebConfig() {
469
+ try {
470
+ if (typeof fetch === "function") {
471
+ const response = await fetch("/fragment.web.json");
472
+ if (!response.ok) {
473
+ throw new Error("fragment.web.json not found");
474
+ }
475
+ const raw = await response.json();
476
+ return {
477
+ ...defaultWebConfig(),
478
+ ...raw,
479
+ fetch: {
480
+ ...defaultWebConfig().fetch,
481
+ ...raw.fetch,
482
+ baseUrl: interpolateEnv(raw.fetch?.baseUrl || defaultWebConfig().fetch.baseUrl || "")
483
+ }
484
+ };
485
+ }
486
+ throw new Error("fetch unavailable");
487
+ } catch {
488
+ return {
489
+ ...defaultWebConfig(),
490
+ fetch: {
491
+ ...defaultWebConfig().fetch,
492
+ baseUrl: interpolateEnv(defaultWebConfig().fetch.baseUrl || "")
493
+ }
494
+ };
495
+ }
496
+ }
497
+
498
+ // src/web/src/core/application.tsx
499
+ import { jsx as jsx2 } from "react/jsx-runtime";
500
+ var appMeta = /* @__PURE__ */ new WeakMap();
501
+ function FragmentWebApplication(options) {
502
+ return (target) => {
503
+ appMeta.set(target, {
504
+ rootElement: options.rootElement,
505
+ strict: options.strict ?? true
506
+ });
507
+ };
508
+ }
509
+ var FragmentWebUIApplication = class {
510
+ async bootstrap(applicationClass) {
511
+ const config = await loadWebConfig();
512
+ const meta = appMeta.get(applicationClass) || {
513
+ rootElement: config.app.rootElement,
514
+ strict: config.app.strict
515
+ };
516
+ FragmentFetch.configure({
517
+ ...config.fetch,
518
+ baseUrl: `${config.fetch.baseUrl.replace(/\/$/, "")}${config.serverRoot}`
519
+ });
520
+ const rootElement = document.querySelector(meta.rootElement);
521
+ if (!rootElement) {
522
+ throw new Error(`Root element not found: ${meta.rootElement}`);
523
+ }
524
+ const root = createRoot(rootElement);
525
+ const app = /* @__PURE__ */ jsx2(FragmentRouter, { config });
526
+ if (meta.strict) {
527
+ root.render(/* @__PURE__ */ jsx2(StrictMode, { children: app }));
528
+ return;
529
+ }
530
+ root.render(app);
531
+ }
532
+ };
533
+
534
+ // src/web/src/core/di/container.ts
535
+ var DIContainer = class {
536
+ static register(token, value) {
537
+ this.providers.set(token, value);
538
+ }
539
+ static resolve(token) {
540
+ if (!this.providers.has(token)) {
541
+ if (typeof token === "function") {
542
+ const instance = new token();
543
+ this.providers.set(token, instance);
544
+ } else {
545
+ throw new Error(`Provider not found for token ${String(token)}`);
546
+ }
547
+ }
548
+ return this.providers.get(token);
549
+ }
550
+ static clear() {
551
+ this.providers.clear();
552
+ }
553
+ };
554
+ DIContainer.providers = /* @__PURE__ */ new Map();
555
+
556
+ // src/web/src/core/decorators/component.ts
557
+ var componentMeta = /* @__PURE__ */ new Map();
558
+ function Component(options = {}) {
559
+ return (target) => {
560
+ componentMeta.set(target, options);
561
+ };
562
+ }
563
+ function State(initial) {
564
+ return (target, propertyKey) => {
565
+ Reflect.defineMetadata(`fragment:state:${String(propertyKey)}`, initial, target);
566
+ };
567
+ }
568
+ function Computed(deps) {
569
+ return (target, propertyKey) => {
570
+ Reflect.defineMetadata(`fragment:computed:${String(propertyKey)}`, deps || [], target);
571
+ };
572
+ }
573
+ function Effect(options) {
574
+ return (target, propertyKey) => {
575
+ Reflect.defineMetadata(`fragment:effect:${String(propertyKey)}`, options, target);
576
+ };
577
+ }
578
+ function Watch(key) {
579
+ return (target, propertyKey) => {
580
+ Reflect.defineMetadata(`fragment:watch:${String(propertyKey)}`, key, target);
581
+ };
582
+ }
583
+ function Store(store, selector) {
584
+ return (target, propertyKey) => {
585
+ Reflect.defineMetadata(`fragment:store:${String(propertyKey)}`, { store, selector }, target);
586
+ };
587
+ }
588
+ function Prop(defaultValue) {
589
+ return (target, propertyKey) => {
590
+ Reflect.defineMetadata(`fragment:prop:${String(propertyKey)}`, defaultValue, target);
591
+ };
592
+ }
593
+ function Ref() {
594
+ return (target, propertyKey) => {
595
+ Reflect.defineMetadata(`fragment:ref:${String(propertyKey)}`, true, target);
596
+ };
597
+ }
598
+ function Inject(token) {
599
+ return (target, propertyKey) => {
600
+ Reflect.defineMetadata(`fragment:inject:${String(propertyKey)}`, token, target);
601
+ const key = propertyKey;
602
+ Object.defineProperty(target, key, {
603
+ configurable: true,
604
+ enumerable: true,
605
+ get() {
606
+ return DIContainer.resolve(token);
607
+ }
608
+ });
609
+ };
610
+ }
611
+ function FragmentService() {
612
+ return (target) => {
613
+ DIContainer.register(target, new target());
614
+ };
615
+ }
616
+ function Injectable(_scope = "singleton") {
617
+ return (target) => {
618
+ DIContainer.register(target, new target());
619
+ };
620
+ }
621
+ export {
622
+ Component,
623
+ Computed,
624
+ DIContainer,
625
+ Effect,
626
+ FragmentFetch,
627
+ FragmentHttpError,
628
+ FragmentService,
629
+ FragmentWebApplication,
630
+ FragmentWebUIApplication,
631
+ Guard,
632
+ Inject,
633
+ Injectable,
634
+ Layout,
635
+ Page,
636
+ Param,
637
+ Prop,
638
+ Query,
639
+ RedirectIfAuthenticated,
640
+ Ref,
641
+ State,
642
+ Store,
643
+ Watch
644
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fragment-ts",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "Spring Boot-style framework for TypeScript with Express and TypeORM",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,7 +22,9 @@
22
22
  "scripts": {
23
23
  "build": "tsc",
24
24
  "prepublishOnly": "npm run build",
25
- "test": "node dist/platform/testing/runner.js"
25
+ "test": "node dist/platform/testing/runner.js",
26
+ "test:web": "vitest run src/web/tests src/platform/cli/web/tests",
27
+ "build:web": "tsup src/web/src/index.ts src/platform/cli/web/index.ts --dts --format esm,cjs --out-dir dist/web"
26
28
  },
27
29
  "keywords": [
28
30
  "framework",
@@ -56,9 +58,15 @@
56
58
  "helmet": "^7.1.0",
57
59
  "inquirer": "^9.2.12",
58
60
  "jsonwebtoken": "^9.0.2",
61
+ "handlebars": "^4.7.8",
59
62
  "mobx": "^6.12.0",
60
63
  "openai": "^4.20.1",
61
64
  "ora": "^5.4.1",
65
+ "picocolors": "^1.1.1",
66
+ "prettier": "^3.6.2",
67
+ "react": "^18.3.1",
68
+ "react-dom": "^18.3.1",
69
+ "react-router-dom": "^6.30.1",
62
70
  "reflect-metadata": "^0.1.13",
63
71
  "typeorm": "^0.3.17"
64
72
  },
@@ -75,9 +83,13 @@
75
83
  "@types/inquirer": "^9.0.9",
76
84
  "@types/jsonwebtoken": "^9.0.5",
77
85
  "@types/node": "^20.10.5",
86
+ "@types/react": "^18.3.24",
87
+ "@types/react-dom": "^18.3.7",
78
88
  "ts-node": "^10.9.2",
79
89
  "tsconfig-paths": "^4.2.0",
80
- "typescript": "^5.3.3"
90
+ "tsup": "^8.5.0",
91
+ "typescript": "^5.3.3",
92
+ "vitest": "^2.1.9"
81
93
  },
82
94
  "engines": {
83
95
  "node": ">=16.0.0"