@reckona/mreact-router 0.0.207 → 0.0.209

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 (62) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/cloudflare.d.ts +3 -3
  3. package/dist/adapters/cloudflare.d.ts.map +1 -1
  4. package/dist/adapters/cloudflare.js +11 -4
  5. package/dist/adapters/cloudflare.js.map +1 -1
  6. package/dist/boundaries.d.ts +37 -1
  7. package/dist/boundaries.d.ts.map +1 -1
  8. package/dist/boundaries.js +125 -4
  9. package/dist/boundaries.js.map +1 -1
  10. package/dist/build.d.ts +6 -0
  11. package/dist/build.d.ts.map +1 -1
  12. package/dist/build.js +269 -24
  13. package/dist/build.js.map +1 -1
  14. package/dist/bundle-pipeline.d.ts +1 -0
  15. package/dist/bundle-pipeline.d.ts.map +1 -1
  16. package/dist/bundle-pipeline.js +4 -1
  17. package/dist/bundle-pipeline.js.map +1 -1
  18. package/dist/client.d.ts +1 -0
  19. package/dist/client.d.ts.map +1 -1
  20. package/dist/client.js +67 -7
  21. package/dist/client.js.map +1 -1
  22. package/dist/config.d.ts +7 -0
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +17 -0
  25. package/dist/config.js.map +1 -1
  26. package/dist/index.d.ts +5 -5
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/module-runner.js +9 -1
  31. package/dist/module-runner.js.map +1 -1
  32. package/dist/render.d.ts.map +1 -1
  33. package/dist/render.js +23 -23
  34. package/dist/render.js.map +1 -1
  35. package/dist/request-header-tracking.d.ts +19 -0
  36. package/dist/request-header-tracking.d.ts.map +1 -1
  37. package/dist/request-header-tracking.js +48 -0
  38. package/dist/request-header-tracking.js.map +1 -1
  39. package/dist/tailwind-source.d.ts.map +1 -1
  40. package/dist/tailwind-source.js +147 -1
  41. package/dist/tailwind-source.js.map +1 -1
  42. package/dist/types.d.ts +14 -2
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/types.js.map +1 -1
  45. package/dist/vite.d.ts +1 -0
  46. package/dist/vite.d.ts.map +1 -1
  47. package/dist/vite.js +4 -0
  48. package/dist/vite.js.map +1 -1
  49. package/package.json +11 -11
  50. package/src/adapters/cloudflare.ts +14 -5
  51. package/src/boundaries.ts +224 -4
  52. package/src/build.ts +383 -24
  53. package/src/bundle-pipeline.ts +9 -4
  54. package/src/client.ts +104 -10
  55. package/src/config.ts +32 -0
  56. package/src/index.ts +10 -0
  57. package/src/module-runner.ts +9 -1
  58. package/src/render.ts +30 -16
  59. package/src/request-header-tracking.ts +61 -0
  60. package/src/tailwind-source.ts +164 -1
  61. package/src/types.ts +15 -2
  62. package/src/vite.ts +5 -0
@@ -14,7 +14,170 @@ export function prependTailwindSourceDirectives(options: {
14
14
  .map((sourceDir) => `${tailwindSourceDirective(cssDir, sourceDir)}\n`)
15
15
  .join("");
16
16
 
17
- return directives.length === 0 ? options.code : `${directives}${options.code}`;
17
+ if (directives.length === 0) {
18
+ return options.code;
19
+ }
20
+
21
+ const insertionIndex = leadingCssPreludeEnd(options.code);
22
+ const prefix = options.code.slice(0, insertionIndex);
23
+ const suffix = options.code.slice(insertionIndex);
24
+ const lineEnding = suffix.startsWith("\r\n") ? "\r\n" : "\n";
25
+ const existingLineEnding = suffix.startsWith(lineEnding) ? lineEnding : "";
26
+ const separator = insertionIndex === 0 ? "" : existingLineEnding || lineEnding;
27
+ const formattedDirectives = directives.replaceAll("\n", lineEnding);
28
+ return `${prefix}${separator}${formattedDirectives}${suffix.slice(existingLineEnding.length)}`;
29
+ }
30
+
31
+ function leadingCssPreludeEnd(code: string): number {
32
+ let cursor = 0;
33
+ let lastRuleEnd = 0;
34
+
35
+ for (;;) {
36
+ cursor = skipCssTrivia(code, cursor);
37
+ const ruleEnd = consumeLeadingCssRule(code, cursor);
38
+ if (ruleEnd === undefined) {
39
+ return lastRuleEnd;
40
+ }
41
+
42
+ lastRuleEnd = ruleEnd;
43
+ cursor = ruleEnd;
44
+ }
45
+ }
46
+
47
+ function skipCssTrivia(code: string, start: number): number {
48
+ let cursor = start;
49
+ while (cursor < code.length) {
50
+ if (/\s/u.test(code[cursor] ?? "")) {
51
+ cursor += 1;
52
+ continue;
53
+ }
54
+
55
+ if (code.startsWith("/*", cursor)) {
56
+ const commentEnd = code.indexOf("*/", cursor + 2);
57
+ if (commentEnd < 0) {
58
+ return code.length;
59
+ }
60
+ cursor = commentEnd + 2;
61
+ continue;
62
+ }
63
+
64
+ break;
65
+ }
66
+
67
+ return cursor;
68
+ }
69
+
70
+ function consumeLeadingCssRule(code: string, start: number): number | undefined {
71
+ const match = /^@(charset|import|layer)(?=\s|[;{]|\/\*)/iu.exec(code.slice(start));
72
+ const ruleName = match?.[1]?.toLowerCase();
73
+ if (match === null || ruleName === undefined) {
74
+ return undefined;
75
+ }
76
+
77
+ let quote: '"' | "'" | undefined;
78
+ let parentheses = 0;
79
+ for (let cursor = start + match[0].length; cursor < code.length; cursor += 1) {
80
+ const character = code[cursor];
81
+ if (character === undefined) {
82
+ return undefined;
83
+ }
84
+
85
+ if (quote !== undefined) {
86
+ if (character === "\\") {
87
+ cursor += 1;
88
+ } else if (character === quote) {
89
+ quote = undefined;
90
+ }
91
+ continue;
92
+ }
93
+
94
+ if (code.startsWith("/*", cursor)) {
95
+ const commentEnd = code.indexOf("*/", cursor + 2);
96
+ if (commentEnd < 0) {
97
+ return undefined;
98
+ }
99
+ cursor = commentEnd + 1;
100
+ continue;
101
+ }
102
+
103
+ if (character === '"' || character === "'") {
104
+ quote = character;
105
+ continue;
106
+ }
107
+ if (character === "(") {
108
+ parentheses += 1;
109
+ continue;
110
+ }
111
+ if (character === ")") {
112
+ parentheses = Math.max(0, parentheses - 1);
113
+ continue;
114
+ }
115
+ if (character === ";" && parentheses === 0) {
116
+ return cursor + 1;
117
+ }
118
+ if (character === "{" && parentheses === 0) {
119
+ if (ruleName !== "layer") {
120
+ return undefined;
121
+ }
122
+
123
+ const blockEnd = consumeCssBlock(code, cursor);
124
+ if (blockEnd === undefined || !isCssTrivia(code.slice(cursor + 1, blockEnd - 1))) {
125
+ return undefined;
126
+ }
127
+ return blockEnd;
128
+ }
129
+ if (character === "}" && parentheses === 0) {
130
+ return undefined;
131
+ }
132
+ }
133
+
134
+ return undefined;
135
+ }
136
+
137
+ function consumeCssBlock(code: string, start: number): number | undefined {
138
+ let depth = 1;
139
+ let quote: '"' | "'" | undefined;
140
+ for (let cursor = start + 1; cursor < code.length; cursor += 1) {
141
+ const character = code[cursor];
142
+ if (character === undefined) {
143
+ return undefined;
144
+ }
145
+
146
+ if (quote !== undefined) {
147
+ if (character === "\\") {
148
+ cursor += 1;
149
+ } else if (character === quote) {
150
+ quote = undefined;
151
+ }
152
+ continue;
153
+ }
154
+
155
+ if (code.startsWith("/*", cursor)) {
156
+ const commentEnd = code.indexOf("*/", cursor + 2);
157
+ if (commentEnd < 0) {
158
+ return undefined;
159
+ }
160
+ cursor = commentEnd + 1;
161
+ continue;
162
+ }
163
+
164
+ if (character === '"' || character === "'") {
165
+ quote = character;
166
+ } else if (character === "{") {
167
+ depth += 1;
168
+ } else if (character === "}") {
169
+ depth -= 1;
170
+ if (depth === 0) {
171
+ return cursor + 1;
172
+ }
173
+ }
174
+ }
175
+
176
+ return undefined;
177
+ }
178
+
179
+ function isCssTrivia(value: string): boolean {
180
+ return skipCssTrivia(value, 0) === value.length;
18
181
  }
19
182
 
20
183
  function isTailwindCssEntry(code: string): boolean {
package/src/types.ts CHANGED
@@ -62,13 +62,26 @@ export interface RouteHandlerContext<TParams extends RouteParams = RouteParams>
62
62
  request: Request;
63
63
  }
64
64
 
65
+ /**
66
+ * Serializable location data passed to shared page and layout components.
67
+ *
68
+ * Server-only request data such as headers, body, credentials, and abort
69
+ * signals is available through loader and handler contexts instead.
70
+ */
71
+ export interface RouteLocation {
72
+ readonly hash: string;
73
+ readonly pathname: string;
74
+ readonly search: string;
75
+ readonly url: string;
76
+ }
77
+
65
78
  /**
66
79
  * Provides loader data, params, and request context to page components.
67
80
  */
68
81
  export interface PageProps<TData = unknown, TParams extends RouteParams = RouteParams> {
69
82
  data: TData;
70
83
  params: TParams;
71
- request: Request;
84
+ request: RouteLocation;
72
85
  }
73
86
 
74
87
  /**
@@ -95,7 +108,7 @@ export function definePage<TLoader extends RouteLoader>(
95
108
  export interface LayoutProps<TParams extends RouteParams = RouteParams> {
96
109
  children: ReactCompatNode;
97
110
  params: TParams;
98
- request: Request;
111
+ request: RouteLocation;
99
112
  }
100
113
 
101
114
  /**
package/src/vite.ts CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  type AppRouterProjectOptions,
25
25
  type ResolvedAppRouterProject,
26
26
  } from "./config.js";
27
+ export type { AppRouterExecutionContracts } from "./config.js";
27
28
  import type { AppRouterImportPolicy } from "./import-policy.js";
28
29
  import { dehydrateOptionsFromModule } from "./dehydrate-policy.js";
29
30
  import {
@@ -237,6 +238,10 @@ export function createAppRouterVitePlugin(options: AppRouterVitePluginOptions):
237
238
  "@reckona/mreact-shared/url-safety",
238
239
  packageFile("shared", "@reckona/mreact-shared", "url-safety"),
239
240
  ],
241
+ [
242
+ "@reckona/mreact-shared/server-render-value-internal",
243
+ packageFile("shared", "@reckona/mreact-shared", "server-render-value-internal"),
244
+ ],
240
245
  ]);
241
246
 
242
247
  // User-declared plugins captured from the resolving config. Unlike the fully