one 1.2.35 → 1.2.36

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 (59) hide show
  1. package/dist/cjs/cli/build.cjs +16 -2
  2. package/dist/cjs/cli/build.js +14 -3
  3. package/dist/cjs/cli/build.js.map +1 -1
  4. package/dist/cjs/cli/build.native.js +20 -5
  5. package/dist/cjs/cli/build.native.js.map +1 -1
  6. package/dist/cjs/cli/generateSitemap.cjs +86 -0
  7. package/dist/cjs/cli/generateSitemap.js +69 -0
  8. package/dist/cjs/cli/generateSitemap.js.map +6 -0
  9. package/dist/cjs/cli/generateSitemap.native.js +112 -0
  10. package/dist/cjs/cli/generateSitemap.native.js.map +1 -0
  11. package/dist/cjs/cli/generateSitemap.test.cjs +156 -0
  12. package/dist/cjs/cli/generateSitemap.test.js +103 -0
  13. package/dist/cjs/cli/generateSitemap.test.js.map +6 -0
  14. package/dist/cjs/cli/generateSitemap.test.native.js +200 -0
  15. package/dist/cjs/cli/generateSitemap.test.native.js.map +1 -0
  16. package/dist/cjs/vite/one.cjs +30 -14
  17. package/dist/cjs/vite/one.js +30 -14
  18. package/dist/cjs/vite/one.js.map +1 -1
  19. package/dist/cjs/vite/one.native.js +30 -14
  20. package/dist/cjs/vite/one.native.js.map +1 -1
  21. package/dist/esm/cli/build.js +14 -2
  22. package/dist/esm/cli/build.js.map +1 -1
  23. package/dist/esm/cli/build.mjs +16 -2
  24. package/dist/esm/cli/build.mjs.map +1 -1
  25. package/dist/esm/cli/build.native.js +20 -5
  26. package/dist/esm/cli/build.native.js.map +1 -1
  27. package/dist/esm/cli/generateSitemap.js +45 -0
  28. package/dist/esm/cli/generateSitemap.js.map +6 -0
  29. package/dist/esm/cli/generateSitemap.mjs +52 -0
  30. package/dist/esm/cli/generateSitemap.mjs.map +1 -0
  31. package/dist/esm/cli/generateSitemap.native.js +75 -0
  32. package/dist/esm/cli/generateSitemap.native.js.map +1 -0
  33. package/dist/esm/cli/generateSitemap.test.js +104 -0
  34. package/dist/esm/cli/generateSitemap.test.js.map +6 -0
  35. package/dist/esm/cli/generateSitemap.test.mjs +157 -0
  36. package/dist/esm/cli/generateSitemap.test.mjs.map +1 -0
  37. package/dist/esm/cli/generateSitemap.test.native.js +198 -0
  38. package/dist/esm/cli/generateSitemap.test.native.js.map +1 -0
  39. package/dist/esm/vite/one.js +30 -14
  40. package/dist/esm/vite/one.js.map +1 -1
  41. package/dist/esm/vite/one.mjs +30 -14
  42. package/dist/esm/vite/one.mjs.map +1 -1
  43. package/dist/esm/vite/one.native.js +30 -14
  44. package/dist/esm/vite/one.native.js.map +1 -1
  45. package/package.json +13 -10
  46. package/src/cli/build.ts +31 -0
  47. package/src/cli/generateSitemap.test.ts +207 -0
  48. package/src/cli/generateSitemap.ts +93 -0
  49. package/src/vite/one.ts +28 -11
  50. package/src/vite/types.ts +73 -0
  51. package/types/cli/build.d.ts.map +1 -1
  52. package/types/cli/generateSitemap.d.ts +13 -0
  53. package/types/cli/generateSitemap.d.ts.map +1 -0
  54. package/types/cli/generateSitemap.test.d.ts +2 -0
  55. package/types/cli/generateSitemap.test.d.ts.map +1 -0
  56. package/types/env.d.ts +43 -0
  57. package/types/vite/one.d.ts.map +1 -1
  58. package/types/vite/types.d.ts +62 -0
  59. package/types/vite/types.d.ts.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "one",
3
- "version": "1.2.35",
3
+ "version": "1.2.36",
4
4
  "license": "BSD-3-Clause",
5
5
  "sideEffects": [
6
6
  "setup.mjs",
@@ -78,6 +78,9 @@
78
78
  "./metro-entry": {
79
79
  "require": "./metro-entry.js",
80
80
  "import": "./metro-entry.js"
81
+ },
82
+ "./env": {
83
+ "types": "./types/env.d.ts"
81
84
  }
82
85
  },
83
86
  "main": "dist/cjs",
@@ -121,17 +124,17 @@
121
124
  "@react-navigation/routers": "~7.5.1",
122
125
  "@swc/core": "^1.14.0",
123
126
  "@ungap/structured-clone": "^1.2.0",
124
- "@vxrn/color-scheme": "1.2.35",
125
- "@vxrn/compiler": "1.2.35",
126
- "@vxrn/resolve": "1.2.35",
127
- "@vxrn/tslib-lite": "1.2.35",
128
- "@vxrn/use-isomorphic-layout-effect": "1.2.35",
129
- "@vxrn/vite-plugin-metro": "1.2.35",
127
+ "@vxrn/color-scheme": "1.2.36",
128
+ "@vxrn/compiler": "1.2.36",
129
+ "@vxrn/resolve": "1.2.36",
130
+ "@vxrn/tslib-lite": "1.2.36",
131
+ "@vxrn/use-isomorphic-layout-effect": "1.2.36",
132
+ "@vxrn/vite-plugin-metro": "1.2.36",
130
133
  "babel-dead-code-elimination": "^1.0.10",
131
134
  "babel-plugin-module-resolver": "^5.0.2",
132
135
  "citty": "^0.1.6",
133
136
  "core-js": "^3.38.1",
134
- "create-vxrn": "1.2.35",
137
+ "create-vxrn": "1.2.36",
135
138
  "escape-string-regexp": "^5.0.0",
136
139
  "expo-linking": "~8.0.8",
137
140
  "expo-modules-core": "~3.0.24",
@@ -157,7 +160,7 @@
157
160
  "vite": "^7.1.12",
158
161
  "vite-plugin-barrel": "^0.4.1",
159
162
  "vite-tsconfig-paths": "^5.1.4",
160
- "vxrn": "1.2.35",
163
+ "vxrn": "1.2.36",
161
164
  "ws": "^8.18.0",
162
165
  "xxhashjs": "^0.2.2"
163
166
  },
@@ -175,7 +178,7 @@
175
178
  "devDependencies": {
176
179
  "@react-navigation/core": "^7.13.0",
177
180
  "@react-navigation/native": "~7.1.19",
178
- "@tamagui/build": "^1.140.4",
181
+ "@tamagui/build": "^1.141.0",
179
182
  "@types/node": "^24.10.0",
180
183
  "@types/react-dom": "^19.2.2",
181
184
  "@types/xxhashjs": "^0.2.4",
package/src/cli/build.ts CHANGED
@@ -25,6 +25,7 @@ import { runWithAsyncLocalContext } from '../vite/one-server-only'
25
25
  import type { One, RouteInfo } from '../vite/types'
26
26
  import { buildPage } from './buildPage'
27
27
  import { checkNodeVersion } from './checkNodeVersion'
28
+ import { generateSitemap, type RouteSitemapData } from './generateSitemap'
28
29
  import { labelProcess } from './label-process'
29
30
 
30
31
  const { ensureDir, writeJSON } = FSExtra
@@ -219,6 +220,7 @@ export async function build(args: {
219
220
  const assets: OutputAsset[] = []
220
221
 
221
222
  const builtRoutes: One.RouteBuildInfo[] = []
223
+ const sitemapData: RouteSitemapData[] = []
222
224
 
223
225
  console.info(`\n 🔨 build static routes\n`)
224
226
 
@@ -466,6 +468,9 @@ export async function build(args: {
466
468
  console.info(`paramsList`, JSON.stringify(paramsList, null, 2))
467
469
  }
468
470
 
471
+ // Get route-level sitemap export if present
472
+ const routeSitemapExport = exported.sitemap as One.RouteSitemapExport | undefined
473
+
469
474
  for (const params of paramsList) {
470
475
  const path = getPathnameFromFilePath(relativeId, params, foundRoute.type === 'ssg')
471
476
  console.info(` ↦ route ${path}`)
@@ -490,6 +495,20 @@ export async function build(args: {
490
495
  })
491
496
 
492
497
  builtRoutes.push(built)
498
+
499
+ // Collect sitemap data for page routes (exclude API, not-found, layouts)
500
+ if (
501
+ foundRoute.type !== 'api' &&
502
+ foundRoute.type !== 'layout' &&
503
+ !foundRoute.isNotFound &&
504
+ !foundRoute.page.includes('+not-found') &&
505
+ !foundRoute.page.includes('_sitemap')
506
+ ) {
507
+ sitemapData.push({
508
+ path,
509
+ routeExport: routeSitemapExport,
510
+ })
511
+ }
493
512
  }
494
513
  }
495
514
 
@@ -562,6 +581,18 @@ export async function build(args: {
562
581
 
563
582
  await writeJSON(toAbsolute(`dist/buildInfo.json`), buildInfoForWriting)
564
583
 
584
+ // Generate sitemap.xml if enabled
585
+ const sitemapConfig = oneOptions.web?.sitemap
586
+ if (sitemapConfig) {
587
+ const sitemapOptions: One.SitemapOptions =
588
+ typeof sitemapConfig === 'boolean' ? {} : sitemapConfig
589
+
590
+ const sitemapXml = generateSitemap(sitemapData, sitemapOptions)
591
+ const sitemapPath = join(clientDir, 'sitemap.xml')
592
+ await FSExtra.writeFile(sitemapPath, sitemapXml)
593
+ console.info(`\n 📄 generated sitemap.xml (${sitemapData.length} URLs)\n`)
594
+ }
595
+
565
596
  let postBuildLogs: string[] = []
566
597
 
567
598
  const platform = oneOptions.web?.deploy
@@ -0,0 +1,207 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { generateSitemap, type RouteSitemapData } from './generateSitemap'
3
+ import type { One } from '../vite/types'
4
+
5
+ describe('generateSitemap', () => {
6
+ it('generates basic sitemap XML', () => {
7
+ const routes: RouteSitemapData[] = [{ path: '/' }, { path: '/about' }, { path: '/blog' }]
8
+ const options: One.SitemapOptions = {}
9
+
10
+ const result = generateSitemap(routes, options)
11
+
12
+ expect(result).toContain('<?xml version="1.0" encoding="UTF-8"?>')
13
+ expect(result).toContain('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">')
14
+ expect(result).toContain('<loc>/</loc>')
15
+ expect(result).toContain('<loc>/about</loc>')
16
+ expect(result).toContain('<loc>/blog</loc>')
17
+ expect(result).toContain('</urlset>')
18
+ })
19
+
20
+ it('uses baseUrl when provided', () => {
21
+ const routes: RouteSitemapData[] = [{ path: '/' }, { path: '/about' }]
22
+ const options: One.SitemapOptions = {
23
+ baseUrl: 'https://example.com',
24
+ }
25
+
26
+ const result = generateSitemap(routes, options)
27
+
28
+ expect(result).toContain('<loc>https://example.com/</loc>')
29
+ expect(result).toContain('<loc>https://example.com/about</loc>')
30
+ })
31
+
32
+ it('strips trailing slash from baseUrl', () => {
33
+ const routes: RouteSitemapData[] = [{ path: '/about' }]
34
+ const options: One.SitemapOptions = {
35
+ baseUrl: 'https://example.com/',
36
+ }
37
+
38
+ const result = generateSitemap(routes, options)
39
+
40
+ expect(result).toContain('<loc>https://example.com/about</loc>')
41
+ expect(result).not.toContain('https://example.com//about')
42
+ })
43
+
44
+ it('uses ONE_SERVER_URL env var when baseUrl not provided', () => {
45
+ const originalEnv = process.env.ONE_SERVER_URL
46
+ process.env.ONE_SERVER_URL = 'https://env-url.com'
47
+
48
+ try {
49
+ const routes: RouteSitemapData[] = [{ path: '/test' }]
50
+ const options: One.SitemapOptions = {}
51
+
52
+ const result = generateSitemap(routes, options)
53
+
54
+ expect(result).toContain('<loc>https://env-url.com/test</loc>')
55
+ } finally {
56
+ process.env.ONE_SERVER_URL = originalEnv
57
+ }
58
+ })
59
+
60
+ it('applies default priority to all routes', () => {
61
+ const routes: RouteSitemapData[] = [{ path: '/' }, { path: '/about' }]
62
+ const options: One.SitemapOptions = {
63
+ priority: 0.8,
64
+ }
65
+
66
+ const result = generateSitemap(routes, options)
67
+
68
+ expect(result).toMatch(/<url>\s*<loc>\/about<\/loc>\s*<priority>0\.8<\/priority>\s*<\/url>/s)
69
+ })
70
+
71
+ it('applies default changefreq to all routes', () => {
72
+ const routes: RouteSitemapData[] = [{ path: '/' }, { path: '/about' }]
73
+ const options: One.SitemapOptions = {
74
+ changefreq: 'weekly',
75
+ }
76
+
77
+ const result = generateSitemap(routes, options)
78
+
79
+ expect(result).toContain('<changefreq>weekly</changefreq>')
80
+ })
81
+
82
+ it('respects route-level sitemap exports', () => {
83
+ const routes: RouteSitemapData[] = [
84
+ { path: '/', routeExport: { priority: 1.0, changefreq: 'daily' } },
85
+ { path: '/about', routeExport: { priority: 0.5, changefreq: 'monthly' } },
86
+ ]
87
+ const options: One.SitemapOptions = {
88
+ priority: 0.7,
89
+ changefreq: 'weekly',
90
+ }
91
+
92
+ const result = generateSitemap(routes, options)
93
+
94
+ // Route exports should override defaults
95
+ expect(result).toMatch(
96
+ /<url>\s*<loc>\/<\/loc>\s*<changefreq>daily<\/changefreq>\s*<priority>1\.0<\/priority>\s*<\/url>/s
97
+ )
98
+ expect(result).toMatch(
99
+ /<url>\s*<loc>\/about<\/loc>\s*<changefreq>monthly<\/changefreq>\s*<priority>0\.5<\/priority>\s*<\/url>/s
100
+ )
101
+ })
102
+
103
+ it('excludes routes with routeExport.exclude = true', () => {
104
+ const routes: RouteSitemapData[] = [
105
+ { path: '/' },
106
+ { path: '/admin', routeExport: { exclude: true } },
107
+ { path: '/about' },
108
+ ]
109
+ const options: One.SitemapOptions = {}
110
+
111
+ const result = generateSitemap(routes, options)
112
+
113
+ expect(result).toContain('<loc>/</loc>')
114
+ expect(result).toContain('<loc>/about</loc>')
115
+ expect(result).not.toContain('/admin')
116
+ })
117
+
118
+ it('excludes routes matching exclude glob patterns', () => {
119
+ const routes: RouteSitemapData[] = [
120
+ { path: '/' },
121
+ { path: '/admin/dashboard' },
122
+ { path: '/admin/users' },
123
+ { path: '/about' },
124
+ { path: '/api/health' },
125
+ ]
126
+ const options: One.SitemapOptions = {
127
+ exclude: ['/admin/*', '/api/*'],
128
+ }
129
+
130
+ const result = generateSitemap(routes, options)
131
+
132
+ expect(result).toContain('<loc>/</loc>')
133
+ expect(result).toContain('<loc>/about</loc>')
134
+ expect(result).not.toContain('/admin')
135
+ expect(result).not.toContain('/api')
136
+ })
137
+
138
+ it('includes lastmod when provided in route export', () => {
139
+ const routes: RouteSitemapData[] = [
140
+ { path: '/', routeExport: { lastmod: '2024-01-15' } },
141
+ { path: '/about', routeExport: { lastmod: new Date('2024-06-20') } },
142
+ ]
143
+ const options: One.SitemapOptions = {}
144
+
145
+ const result = generateSitemap(routes, options)
146
+
147
+ expect(result).toContain('<lastmod>2024-01-15</lastmod>')
148
+ expect(result).toContain('<lastmod>2024-06-20</lastmod>')
149
+ })
150
+
151
+ it('escapes XML special characters in URLs', () => {
152
+ const routes: RouteSitemapData[] = [{ path: '/search?q=foo&bar=baz' }]
153
+ const options: One.SitemapOptions = {
154
+ baseUrl: 'https://example.com',
155
+ }
156
+
157
+ const result = generateSitemap(routes, options)
158
+
159
+ expect(result).toContain('&amp;')
160
+ expect(result).not.toContain('&bar')
161
+ })
162
+
163
+ it('generates empty sitemap when no routes', () => {
164
+ const routes: RouteSitemapData[] = []
165
+ const options: One.SitemapOptions = {}
166
+
167
+ const result = generateSitemap(routes, options)
168
+
169
+ expect(result).toContain('<?xml version="1.0" encoding="UTF-8"?>')
170
+ expect(result).toContain('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">')
171
+ expect(result).toContain('</urlset>')
172
+ expect(result).not.toContain('<url>')
173
+ })
174
+
175
+ it('handles all valid changefreq values', () => {
176
+ const changefreqs: One.SitemapChangefreq[] = [
177
+ 'always',
178
+ 'hourly',
179
+ 'daily',
180
+ 'weekly',
181
+ 'monthly',
182
+ 'yearly',
183
+ 'never',
184
+ ]
185
+
186
+ for (const changefreq of changefreqs) {
187
+ const routes: RouteSitemapData[] = [{ path: '/', routeExport: { changefreq } }]
188
+ const result = generateSitemap(routes, {})
189
+ expect(result).toContain(`<changefreq>${changefreq}</changefreq>`)
190
+ }
191
+ })
192
+
193
+ it('formats priority with one decimal place', () => {
194
+ const routes: RouteSitemapData[] = [
195
+ { path: '/', routeExport: { priority: 1 } },
196
+ { path: '/about', routeExport: { priority: 0.5 } },
197
+ { path: '/blog', routeExport: { priority: 0.75 } },
198
+ ]
199
+ const options: One.SitemapOptions = {}
200
+
201
+ const result = generateSitemap(routes, options)
202
+
203
+ expect(result).toContain('<priority>1.0</priority>')
204
+ expect(result).toContain('<priority>0.5</priority>')
205
+ expect(result).toContain('<priority>0.8</priority>') // 0.75 rounds to 0.8
206
+ })
207
+ })
@@ -0,0 +1,93 @@
1
+ import MicroMatch from 'micromatch'
2
+ import type { One } from '../vite/types'
3
+
4
+ export type SitemapEntry = {
5
+ path: string
6
+ priority?: number
7
+ changefreq?: One.SitemapChangefreq
8
+ lastmod?: string | Date
9
+ }
10
+
11
+ export type RouteSitemapData = {
12
+ path: string
13
+ routeExport?: One.RouteSitemapExport
14
+ }
15
+
16
+ export function generateSitemap(routes: RouteSitemapData[], options: One.SitemapOptions): string {
17
+ const envUrl = process.env.ONE_SERVER_URL
18
+ const baseUrl = options.baseUrl ?? (envUrl && envUrl !== 'undefined' ? envUrl : '')
19
+ const defaultPriority = options.priority ?? 0.5
20
+ const defaultChangefreq = options.changefreq
21
+ const excludePatterns = options.exclude || []
22
+
23
+ const entries: SitemapEntry[] = []
24
+
25
+ for (const route of routes) {
26
+ const { path, routeExport } = route
27
+
28
+ // Skip if route exports exclude: true
29
+ if (routeExport?.exclude) {
30
+ continue
31
+ }
32
+
33
+ // Skip if path matches any exclude pattern
34
+ if (excludePatterns.length > 0 && MicroMatch.isMatch(path, excludePatterns)) {
35
+ continue
36
+ }
37
+
38
+ const priority = routeExport?.priority ?? defaultPriority
39
+ const changefreq = routeExport?.changefreq ?? defaultChangefreq
40
+ const lastmod = routeExport?.lastmod
41
+
42
+ entries.push({
43
+ path,
44
+ priority,
45
+ changefreq,
46
+ lastmod,
47
+ })
48
+ }
49
+
50
+ return buildSitemapXml(entries, baseUrl)
51
+ }
52
+
53
+ function buildSitemapXml(entries: SitemapEntry[], baseUrl: string): string {
54
+ const urlEntries = entries
55
+ .map((entry) => {
56
+ const loc = baseUrl ? `${baseUrl.replace(/\/$/, '')}${entry.path}` : entry.path
57
+
58
+ let xml = ` <url>\n <loc>${escapeXml(loc)}</loc>`
59
+
60
+ if (entry.lastmod) {
61
+ const date =
62
+ entry.lastmod instanceof Date ? entry.lastmod.toISOString().split('T')[0] : entry.lastmod
63
+ xml += `\n <lastmod>${escapeXml(date)}</lastmod>`
64
+ }
65
+
66
+ if (entry.changefreq) {
67
+ xml += `\n <changefreq>${entry.changefreq}</changefreq>`
68
+ }
69
+
70
+ if (entry.priority !== undefined) {
71
+ xml += `\n <priority>${entry.priority.toFixed(1)}</priority>`
72
+ }
73
+
74
+ xml += '\n </url>'
75
+ return xml
76
+ })
77
+ .join('\n')
78
+
79
+ return `<?xml version="1.0" encoding="UTF-8"?>
80
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
81
+ ${urlEntries}
82
+ </urlset>
83
+ `
84
+ }
85
+
86
+ function escapeXml(str: string): string {
87
+ return str
88
+ .replace(/&/g, '&amp;')
89
+ .replace(/</g, '&lt;')
90
+ .replace(/>/g, '&gt;')
91
+ .replace(/"/g, '&quot;')
92
+ .replace(/'/g, '&apos;')
93
+ }
package/src/vite/one.ts CHANGED
@@ -284,6 +284,16 @@ export function one(options: One.PluginOptions = {}): PluginOption {
284
284
  config() {
285
285
  return {
286
286
  define: {
287
+ // we define this not in environment.client because there must be a bug in vite
288
+ // it doesnt define the import.meta.env at all if you do that
289
+ 'process.env.TAMAGUI_ENVIRONMENT': '"client"',
290
+ 'process.env.VITE_ENVIRONMENT': '"client"',
291
+ 'import.meta.env.VITE_ENVIRONMENT': '"client"',
292
+ 'process.env.VITE_PLATFORM': '"web"',
293
+ 'import.meta.env.VITE_PLATFORM': '"web"',
294
+ 'process.env.EXPO_OS': '"web"',
295
+ 'import.meta.env.EXPO_OS': '"web"',
296
+
287
297
  ...(options.web?.defaultRenderMode && {
288
298
  'process.env.ONE_DEFAULT_RENDER_MODE': JSON.stringify(options.web.defaultRenderMode),
289
299
  'import.meta.env.ONE_DEFAULT_RENDER_MODE': JSON.stringify(
@@ -344,39 +354,46 @@ export function one(options: One.PluginOptions = {}): PluginOption {
344
354
  },
345
355
 
346
356
  environments: {
347
- client: {
348
- define: {
349
- 'process.env.VITE_ENVIRONMENT': '"client"',
350
- 'process.env.TAMAGUI_ENVIRONMENT': '"client"',
351
- 'import.meta.env.VITE_ENVIRONMENT': '"client"',
352
- 'process.env.EXPO_OS': '"web"',
353
- },
354
- },
357
+ // we define client vars not in environment.client because there must be a bug in vite
358
+ // it doesnt define the import.meta.env at all if you do that
359
+ // client: {
360
+ // define: {
361
+ // },
362
+ // },
355
363
 
356
364
  ssr: {
357
365
  define: {
358
- 'process.env.VITE_ENVIRONMENT': '"ssr"', // Note that we are also setting `process.env.VITE_ENVIRONMENT = 'ssr'` for this current process. See `setServerGlobals()` and `setupServerGlobals.ts`.
359
366
  'process.env.TAMAGUI_ENVIRONMENT': '"ssr"',
367
+ 'process.env.VITE_ENVIRONMENT': '"ssr"', // Note that we are also setting `process.env.VITE_ENVIRONMENT = 'ssr'` for this current process. See `setServerGlobals()` and `setupServerGlobals.ts`.
360
368
  'import.meta.env.VITE_ENVIRONMENT': '"ssr"',
369
+ 'process.env.VITE_PLATFORM': '"web"',
370
+ 'import.meta.env.VITE_PLATFORM': '"web"',
361
371
  'process.env.EXPO_OS': '"web"',
372
+ 'import.meta.env.EXPO_OS': '"web"',
362
373
  },
363
374
  },
364
375
 
365
376
  ios: {
366
377
  define: {
367
- 'process.env.VITE_ENVIRONMENT': '"ios"',
368
378
  'process.env.TAMAGUI_ENVIRONMENT': '"ios"',
379
+ 'process.env.VITE_ENVIRONMENT': '"ios"',
369
380
  'import.meta.env.VITE_ENVIRONMENT': '"ios"',
381
+ 'process.env.VITE_PLATFORM': '"native"',
382
+ 'import.meta.env.VITE_PLATFORM': '"native"',
370
383
  'process.env.EXPO_OS': '"ios"',
384
+ 'import.meta.env.EXPO_OS': '"ios"',
371
385
  },
372
386
  },
373
387
 
374
388
  android: {
375
389
  define: {
376
- 'process.env.VITE_ENVIRONMENT': '"android"',
377
390
  'process.env.TAMAGUI_ENVIRONMENT': '"android"',
391
+ 'process.env.VITE_ENVIRONMENT': '"android"',
378
392
  'import.meta.env.VITE_ENVIRONMENT': '"android"',
393
+ 'process.env.VITE_PLATFORM': '"native"',
394
+ 'import.meta.env.VITE_PLATFORM': '"native"',
379
395
  'process.env.EXPO_OS': '"android"',
396
+ 'import.meta.env.EXPO_OS': '"android"',
380
397
  },
381
398
  },
382
399
  },
package/src/vite/types.ts CHANGED
@@ -342,6 +342,30 @@ export namespace One {
342
342
  * @default false
343
343
  */
344
344
  inlineLayoutCSS?: boolean
345
+
346
+ /**
347
+ * Generate a sitemap.xml file during build.
348
+ *
349
+ * Set to `true` for default behavior, or pass an object to configure:
350
+ *
351
+ * @example
352
+ * sitemap: true
353
+ *
354
+ * @example
355
+ * sitemap: {
356
+ * baseUrl: 'https://example.com', // defaults to ONE_SERVER_URL env var
357
+ * priority: 0.7, // default priority for all routes
358
+ * changefreq: 'weekly', // default changefreq for all routes
359
+ * exclude: ['/admin/*', '/api/*'], // glob patterns to exclude
360
+ * }
361
+ *
362
+ * Routes can also export sitemap metadata:
363
+ * ```ts
364
+ * export const sitemap = { priority: 0.9, changefreq: 'daily' }
365
+ * // or exclude: export const sitemap = { exclude: true }
366
+ * ```
367
+ */
368
+ sitemap?: boolean | SitemapOptions
345
369
  }
346
370
 
347
371
  server?: VXRNOptions['server']
@@ -442,4 +466,53 @@ export namespace One {
442
466
  /** See PluginOptions.router.experimental.PreventLayoutRemounting */
443
467
  experimentalPreventLayoutRemounting?: boolean
444
468
  }
469
+
470
+ export type SitemapChangefreq =
471
+ | 'always'
472
+ | 'hourly'
473
+ | 'daily'
474
+ | 'weekly'
475
+ | 'monthly'
476
+ | 'yearly'
477
+ | 'never'
478
+
479
+ export type SitemapOptions = {
480
+ /**
481
+ * Base URL for the sitemap. Defaults to ONE_SERVER_URL environment variable.
482
+ */
483
+ baseUrl?: string
484
+ /**
485
+ * Default priority for all routes (0.0 to 1.0).
486
+ * @default 0.5
487
+ */
488
+ priority?: number
489
+ /**
490
+ * Default change frequency for all routes.
491
+ */
492
+ changefreq?: SitemapChangefreq
493
+ /**
494
+ * Glob patterns for routes to exclude from the sitemap.
495
+ * API routes and not-found routes are always excluded.
496
+ */
497
+ exclude?: string[]
498
+ }
499
+
500
+ export type RouteSitemapExport = {
501
+ /**
502
+ * Priority for this route (0.0 to 1.0).
503
+ */
504
+ priority?: number
505
+ /**
506
+ * Change frequency for this route.
507
+ */
508
+ changefreq?: SitemapChangefreq
509
+ /**
510
+ * Last modification date for this route.
511
+ */
512
+ lastmod?: string | Date
513
+ /**
514
+ * Exclude this route from the sitemap.
515
+ */
516
+ exclude?: boolean
517
+ }
445
518
  }
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAmCA,wBAAsB,KAAK,CAAC,IAAI,EAAE;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAAA;CACrC,iBAukBA"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAoCA,wBAAsB,KAAK,CAAC,IAAI,EAAE;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAAA;CACrC,iBAqmBA"}
@@ -0,0 +1,13 @@
1
+ import type { One } from '../vite/types';
2
+ export type SitemapEntry = {
3
+ path: string;
4
+ priority?: number;
5
+ changefreq?: One.SitemapChangefreq;
6
+ lastmod?: string | Date;
7
+ };
8
+ export type RouteSitemapData = {
9
+ path: string;
10
+ routeExport?: One.RouteSitemapExport;
11
+ };
12
+ export declare function generateSitemap(routes: RouteSitemapData[], options: One.SitemapOptions): string;
13
+ //# sourceMappingURL=generateSitemap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateSitemap.d.ts","sourceRoot":"","sources":["../../src/cli/generateSitemap.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAA;IAClC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,GAAG,CAAC,kBAAkB,CAAA;CACrC,CAAA;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,cAAc,GAAG,MAAM,CAmC/F"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=generateSitemap.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateSitemap.test.d.ts","sourceRoot":"","sources":["../../src/cli/generateSitemap.test.ts"],"names":[],"mappings":""}
package/types/env.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ interface OneEnvVariables {
4
+ // Core One variables
5
+ /** Random number for each production build, or stable per dev server run. Useful for cache keys. */
6
+ ONE_CACHE_KEY: string
7
+ /** Your app.key setting from vite.config */
8
+ ONE_APP_NAME: string
9
+ /** Current running server URL in development, e.g. "http://0.0.0.0:8081". Set this yourself for production. */
10
+ ONE_SERVER_URL: string
11
+ /** "ssr", "ssg", or "spa" based on your defaultRenderMode setting */
12
+ ONE_DEFAULT_RENDER_MODE: 'ssr' | 'ssg' | 'spa'
13
+
14
+ // Platform detection
15
+ /** "client" for client-side web, "ssr" for server-side web, "ios" or "android" for native */
16
+ VITE_ENVIRONMENT: 'client' | 'ssr' | 'ios' | 'android'
17
+ /** "web" for all web builds (client and SSR), "native" for native platforms (iOS and Android) */
18
+ VITE_PLATFORM: 'web' | 'native'
19
+ /** "web" for web builds, "ios" or "android" for native. Matches Expo convention. */
20
+ EXPO_OS: 'web' | 'ios' | 'android'
21
+
22
+ // React Native (available in native builds)
23
+ /** The React Native version string */
24
+ REACT_NATIVE_VERSION: string
25
+ /** "ios" or "android" in native builds */
26
+ REACT_NATIVE_PLATFORM: 'ios' | 'android'
27
+ /** Dev server port for React Native */
28
+ REACT_NATIVE_SERVER_PUBLIC_PORT: string
29
+ }
30
+
31
+ declare global {
32
+ namespace NodeJS {
33
+ interface ProcessEnv extends Partial<OneEnvVariables> {}
34
+ }
35
+ }
36
+
37
+ interface ImportMetaEnv extends Partial<OneEnvVariables> {}
38
+
39
+ interface ImportMeta {
40
+ readonly env: ImportMetaEnv
41
+ }
42
+
43
+ export {}
@@ -1 +1 @@
1
- {"version":3,"file":"one.d.ts","sourceRoot":"","sources":["../../src/vite/one.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAU,YAAY,EAAE,MAAM,MAAM,CAAA;AAOhD,OAAO,qBAAqB,CAAA;AAW5B,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAoBlC,wBAAgB,GAAG,CAAC,OAAO,GAAE,GAAG,CAAC,aAAkB,GAAG,YAAY,CA6iBjE"}
1
+ {"version":3,"file":"one.d.ts","sourceRoot":"","sources":["../../src/vite/one.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAU,YAAY,EAAE,MAAM,MAAM,CAAA;AAOhD,OAAO,qBAAqB,CAAA;AAW5B,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAoBlC,wBAAgB,GAAG,CAAC,OAAO,GAAE,GAAG,CAAC,aAAkB,GAAG,YAAY,CA8jBjE"}