zudoku 0.78.0 → 0.78.1

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 (90) hide show
  1. package/dist/cli/cli.js +601 -160
  2. package/dist/cli/worker.js +6 -4
  3. package/dist/declarations/app/adapter.d.ts +12 -0
  4. package/dist/declarations/app/adapters/cloudflare.d.ts +8 -0
  5. package/dist/declarations/app/adapters/lambda.d.ts +13 -0
  6. package/dist/declarations/app/adapters/node.d.ts +12 -0
  7. package/dist/declarations/app/adapters/vercel.d.ts +14 -0
  8. package/dist/declarations/app/entry.client.d.ts +2 -0
  9. package/dist/declarations/app/entry.server.d.ts +13 -0
  10. package/dist/declarations/app/protectChunks.d.ts +17 -0
  11. package/dist/declarations/app/wrapProtectedRoutes.d.ts +4 -0
  12. package/dist/declarations/config/validators/HeaderNavigationSchema.d.ts +216 -80
  13. package/dist/declarations/config/validators/ZudokuConfig.d.ts +81 -30
  14. package/dist/declarations/config/validators/icon-types.d.ts +1 -1
  15. package/dist/declarations/lib/authentication/authentication.d.ts +7 -0
  16. package/dist/declarations/lib/authentication/cookie-sync.d.ts +3 -0
  17. package/dist/declarations/lib/authentication/cookies.d.ts +10 -0
  18. package/dist/declarations/lib/authentication/providers/azureb2c.d.ts +6 -1
  19. package/dist/declarations/lib/authentication/providers/clerk.d.ts +1 -0
  20. package/dist/declarations/lib/authentication/providers/openid.d.ts +2 -1
  21. package/dist/declarations/lib/authentication/providers/supabase.d.ts +2 -0
  22. package/dist/declarations/lib/authentication/session-handler.d.ts +81 -0
  23. package/dist/declarations/lib/authentication/state.d.ts +7 -0
  24. package/dist/declarations/lib/authentication/verify-cache.d.ts +2 -0
  25. package/dist/declarations/lib/components/Bootstrap.d.ts +2 -2
  26. package/dist/declarations/lib/components/Heading.d.ts +1 -1
  27. package/dist/declarations/lib/components/context/RenderContext.d.ts +6 -0
  28. package/dist/declarations/lib/core/RouteGuard.d.ts +11 -0
  29. package/dist/declarations/lib/core/ZudokuContext.d.ts +5 -2
  30. package/dist/declarations/lib/manifest.d.ts +25 -0
  31. package/dist/declarations/lib/util/url.d.ts +2 -0
  32. package/dist/flat-config.d.ts +1 -1
  33. package/docs/configuration/protected-routes.md +21 -4
  34. package/docs/guides/server-side-content-protection.md +207 -0
  35. package/package.json +26 -4
  36. package/src/app/adapter.ts +16 -0
  37. package/src/app/adapters/cloudflare.ts +18 -0
  38. package/src/app/adapters/lambda.ts +36 -0
  39. package/src/app/adapters/node.ts +32 -0
  40. package/src/app/adapters/vercel.ts +39 -0
  41. package/src/app/demo.tsx +2 -2
  42. package/src/app/entry.client.tsx +17 -7
  43. package/src/app/entry.server.tsx +128 -9
  44. package/src/app/main.tsx +20 -3
  45. package/src/app/protectChunks.ts +64 -0
  46. package/src/app/standalone.tsx +2 -2
  47. package/src/app/wrapProtectedRoutes.ts +82 -0
  48. package/src/config/validators/icon-types.ts +17 -0
  49. package/src/lib/authentication/authentication.ts +15 -0
  50. package/src/lib/authentication/cookie-sync.ts +90 -0
  51. package/src/lib/authentication/cookies.ts +54 -0
  52. package/src/lib/authentication/hook.ts +13 -0
  53. package/src/lib/authentication/providers/azureb2c.tsx +70 -2
  54. package/src/lib/authentication/providers/clerk.tsx +49 -0
  55. package/src/lib/authentication/providers/openid.tsx +46 -0
  56. package/src/lib/authentication/providers/supabase.tsx +30 -2
  57. package/src/lib/authentication/session-handler.ts +164 -0
  58. package/src/lib/authentication/state.ts +36 -5
  59. package/src/lib/authentication/verify-cache.ts +32 -0
  60. package/src/lib/components/Bootstrap.tsx +20 -14
  61. package/src/lib/components/Header.tsx +56 -57
  62. package/src/lib/components/MobileTopNavigation.tsx +66 -67
  63. package/src/lib/components/Zudoku.tsx +14 -1
  64. package/src/lib/components/context/RenderContext.ts +8 -0
  65. package/src/lib/components/context/ZudokuContext.ts +2 -1
  66. package/src/lib/core/RouteGuard.tsx +50 -29
  67. package/src/lib/core/ZudokuContext.ts +39 -6
  68. package/src/lib/errors/RouterError.tsx +43 -1
  69. package/src/lib/manifest.ts +62 -0
  70. package/src/lib/oas/parser/dereference/index.ts +2 -1
  71. package/src/lib/oas/parser/dereference/resolveRef.ts +2 -1
  72. package/src/lib/oas/parser/index.ts +1 -1
  73. package/src/lib/plugins/openapi/client/createServer.ts +13 -4
  74. package/src/lib/plugins/search-pagefind/index.tsx +1 -4
  75. package/src/lib/util/os.ts +1 -0
  76. package/src/lib/util/url.ts +13 -0
  77. package/src/vite/build.ts +84 -24
  78. package/src/vite/config.ts +50 -5
  79. package/src/vite/dev-server.ts +61 -8
  80. package/src/vite/manifest.ts +15 -0
  81. package/src/vite/plugin-api.ts +3 -1
  82. package/src/vite/plugin-markdown-export.ts +3 -9
  83. package/src/vite/prerender/worker.ts +2 -4
  84. package/src/vite/protected/annotator.ts +136 -0
  85. package/src/vite/protected/build.ts +151 -0
  86. package/src/vite/protected/registry.ts +82 -0
  87. package/src/vite/ssr-templates/cloudflare.ts +5 -18
  88. package/src/vite/ssr-templates/lambda.ts +4 -0
  89. package/src/vite/ssr-templates/node.ts +7 -22
  90. package/src/vite/ssr-templates/vercel.ts +6 -20
package/dist/cli/cli.js CHANGED
@@ -131,7 +131,7 @@ import { stat } from "node:fs/promises";
131
131
  var fileExists;
132
132
  var init_file_exists = __esm({
133
133
  "src/config/file-exists.ts"() {
134
- fileExists = (path28) => stat(path28).then(() => true).catch(() => false);
134
+ fileExists = (path30) => stat(path30).then(() => true).catch(() => false);
135
135
  }
136
136
  });
137
137
 
@@ -815,6 +815,7 @@ var init_icon_types = __esm({
815
815
  "arrows-up-from-line",
816
816
  "asterisk",
817
817
  "asterisk-square",
818
+ "astroid",
818
819
  "at-sign",
819
820
  "atom",
820
821
  "audio-lines",
@@ -882,6 +883,7 @@ var init_icon_types = __esm({
882
883
  "beer",
883
884
  "beer-off",
884
885
  "bell",
886
+ "bell-check",
885
887
  "bell-dot",
886
888
  "bell-electric",
887
889
  "bell-minus",
@@ -903,6 +905,7 @@ var init_icon_types = __esm({
903
905
  "birdhouse",
904
906
  "bitcoin",
905
907
  "blend",
908
+ "blender",
906
909
  "blinds",
907
910
  "blocks",
908
911
  "bluetooth",
@@ -968,6 +971,7 @@ var init_icon_types = __esm({
968
971
  "briefcase-conveyor-belt",
969
972
  "briefcase-medical",
970
973
  "bring-to-front",
974
+ "broccoli",
971
975
  "brush",
972
976
  "brush-cleaning",
973
977
  "bubbles",
@@ -1460,6 +1464,7 @@ var init_icon_types = __esm({
1460
1464
  "fold-vertical",
1461
1465
  "folder",
1462
1466
  "folder-archive",
1467
+ "folder-bookmark",
1463
1468
  "folder-check",
1464
1469
  "folder-clock",
1465
1470
  "folder-closed",
@@ -1609,6 +1614,7 @@ var init_icon_types = __esm({
1609
1614
  "heart-off",
1610
1615
  "heart-plus",
1611
1616
  "heart-pulse",
1617
+ "heart-x",
1612
1618
  "heater",
1613
1619
  "helicopter",
1614
1620
  "help-circle",
@@ -1686,6 +1692,7 @@ var init_icon_types = __esm({
1686
1692
  "layers",
1687
1693
  "layers-2",
1688
1694
  "layers-3",
1695
+ "layers-minus",
1689
1696
  "layers-plus",
1690
1697
  "layout",
1691
1698
  "layout-dashboard",
@@ -2094,6 +2101,7 @@ var init_icon_types = __esm({
2094
2101
  "repeat",
2095
2102
  "repeat-1",
2096
2103
  "repeat-2",
2104
+ "repeat-off",
2097
2105
  "replace",
2098
2106
  "replace-all",
2099
2107
  "reply",
@@ -2353,6 +2361,12 @@ var init_icon_types = __esm({
2353
2361
  "stethoscope",
2354
2362
  "sticker",
2355
2363
  "sticky-note",
2364
+ "sticky-note-check",
2365
+ "sticky-note-minus",
2366
+ "sticky-note-off",
2367
+ "sticky-note-plus",
2368
+ "sticky-note-x",
2369
+ "sticky-notes",
2356
2370
  "stone",
2357
2371
  "stop-circle",
2358
2372
  "store",
@@ -2433,6 +2447,7 @@ var init_icon_types = __esm({
2433
2447
  "ticket-x",
2434
2448
  "tickets",
2435
2449
  "tickets-plane",
2450
+ "timeline",
2436
2451
  "timer",
2437
2452
  "timer-off",
2438
2453
  "timer-reset",
@@ -2572,7 +2587,9 @@ var init_icon_types = __esm({
2572
2587
  "waves",
2573
2588
  "waves-arrow-down",
2574
2589
  "waves-arrow-up",
2590
+ "waves-horizontal",
2575
2591
  "waves-ladder",
2592
+ "waves-vertical",
2576
2593
  "waypoints",
2577
2594
  "webcam",
2578
2595
  "webhook",
@@ -2836,6 +2853,16 @@ var init_joinUrl = __esm({
2836
2853
  }
2837
2854
  });
2838
2855
 
2856
+ // src/lib/util/url.ts
2857
+ import { matchPath } from "react-router";
2858
+ var matchesProtectedPattern, matchesAnyProtectedPattern;
2859
+ var init_url = __esm({
2860
+ "src/lib/util/url.ts"() {
2861
+ matchesProtectedPattern = (pattern, path30) => matchPath({ path: pattern, end: true }, path30) != null;
2862
+ matchesAnyProtectedPattern = (patterns, path30) => patterns.some((p) => matchesProtectedPattern(p, path30));
2863
+ }
2864
+ });
2865
+
2839
2866
  // src/lib/core/ZudokuContext.ts
2840
2867
  import { createNanoEvents } from "nanoevents";
2841
2868
  var normalizeProtectedRoutes;
@@ -3596,8 +3623,8 @@ var llms_exports = {};
3596
3623
  __export(llms_exports, {
3597
3624
  generateLlmsTxtFiles: () => generateLlmsTxtFiles
3598
3625
  });
3599
- import { writeFile as writeFile4 } from "node:fs/promises";
3600
- import path19 from "node:path";
3626
+ import { writeFile as writeFile5 } from "node:fs/promises";
3627
+ import path20 from "node:path";
3601
3628
  import colors6 from "picocolors";
3602
3629
  async function generateLlmsTxtFiles({
3603
3630
  markdownFileInfos,
@@ -3632,7 +3659,7 @@ async function generateLlmsTxtFiles({
3632
3659
  }
3633
3660
  }
3634
3661
  const llmsTxt2 = llmsTxtParts.join("\n");
3635
- await writeFile4(path19.join(baseOutputDir, "llms.txt"), llmsTxt2, "utf-8");
3662
+ await writeFile5(path20.join(baseOutputDir, "llms.txt"), llmsTxt2, "utf-8");
3636
3663
  console.log(colors6.blue("\u2713 generated llms.txt"));
3637
3664
  }
3638
3665
  if (llmsTxtFull) {
@@ -3657,8 +3684,8 @@ ${info.content}
3657
3684
  `);
3658
3685
  }
3659
3686
  const llmsFull = llmsFullParts.join("\n");
3660
- await writeFile4(
3661
- path19.join(baseOutputDir, "llms-full.txt"),
3687
+ await writeFile5(
3688
+ path20.join(baseOutputDir, "llms-full.txt"),
3662
3689
  llmsFull,
3663
3690
  "utf-8"
3664
3691
  );
@@ -3677,11 +3704,12 @@ import { hideBin } from "yargs/helpers";
3677
3704
  import yargs from "yargs/yargs";
3678
3705
 
3679
3706
  // src/cli/build/handler.ts
3680
- import path23 from "node:path";
3707
+ import path25 from "node:path";
3681
3708
 
3682
3709
  // src/vite/build.ts
3683
- import { mkdir as mkdir5, readFile as readFile3, rename, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
3684
- import path21 from "node:path";
3710
+ import { existsSync as existsSync2 } from "node:fs";
3711
+ import { mkdir as mkdir6, readFile as readFile4, rename as rename2, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
3712
+ import path23 from "node:path";
3685
3713
  import { build as esbuild } from "esbuild";
3686
3714
  import { createBuilder } from "vite";
3687
3715
 
@@ -3825,7 +3853,7 @@ import {
3825
3853
  // package.json
3826
3854
  var package_default = {
3827
3855
  name: "zudoku",
3828
- version: "0.77.0",
3856
+ version: "0.78.0",
3829
3857
  type: "module",
3830
3858
  sideEffects: [
3831
3859
  "**/*.css",
@@ -3884,6 +3912,11 @@ var package_default = {
3884
3912
  "./react-query": "./src/lib/core/react-query.ts",
3885
3913
  "./icons": "./src/lib/icons.ts",
3886
3914
  "./vite": "./src/vite/index.ts",
3915
+ "./server": "./src/app/entry.server.tsx",
3916
+ "./server/adapters/lambda": "./src/app/adapters/lambda.ts",
3917
+ "./server/adapters/node": "./src/app/adapters/node.ts",
3918
+ "./server/adapters/vercel": "./src/app/adapters/vercel.ts",
3919
+ "./server/adapters/cloudflare": "./src/app/adapters/cloudflare.ts",
3887
3920
  "./app/*": "./src/app/*",
3888
3921
  "./hooks": "./src/lib/hooks/index.ts",
3889
3922
  "./processors/*": "./src/lib/plugins/openapi/processors/*.ts",
@@ -3974,9 +4007,10 @@ var package_default = {
3974
4007
  hono: "4.12.18",
3975
4008
  "http-terminator": "3.2.0",
3976
4009
  "javascript-stringify": "2.1.0",
4010
+ jose: "6.2.2",
3977
4011
  "json-schema-to-typescript-lite": "15.0.0",
3978
4012
  loglevel: "1.9.2",
3979
- "lucide-react": "1.8.0",
4013
+ "lucide-react": "1.16.0",
3980
4014
  "mdast-util-from-markdown": "2.0.2",
3981
4015
  "mdast-util-mdx": "3.0.0",
3982
4016
  "mdast-util-mdx-jsx": "3.2.0",
@@ -3990,6 +4024,7 @@ var package_default = {
3990
4024
  picocolors: "1.1.1",
3991
4025
  piscina: "5.1.4",
3992
4026
  "posthog-node": "5.33.4",
4027
+ "quick-lru": "7.3.0",
3993
4028
  "react-error-boundary": "6.1.1",
3994
4029
  "react-hook-form": "7.75.0",
3995
4030
  "react-is": "catalog:",
@@ -4009,13 +4044,13 @@ var package_default = {
4009
4044
  sitemap: "9.0.1",
4010
4045
  "strip-ansi": "7.2.0",
4011
4046
  "tailwind-merge": "3.6.0",
4012
- tailwindcss: "4.2.1",
4047
+ tailwindcss: "4.3.0",
4013
4048
  "tw-animate-css": "1.4.0",
4014
4049
  unified: "11.0.5",
4015
4050
  "unist-util-visit": "5.1.0",
4016
4051
  vaul: "1.1.2",
4017
4052
  vfile: "6.0.3",
4018
- vite: "8.0.9",
4053
+ vite: "8.0.13",
4019
4054
  yaml: "2.8.4",
4020
4055
  yargs: "18.0.0",
4021
4056
  zod: "4.3.6",
@@ -4081,6 +4116,46 @@ init_logger();
4081
4116
  init_package_json();
4082
4117
  init_loader();
4083
4118
  init_ZudokuConfig();
4119
+
4120
+ // src/lib/manifest.ts
4121
+ init_ProtectedRoutesSchema();
4122
+
4123
+ // src/lib/authentication/cookies.ts
4124
+ var ACCESS_TOKEN_COOKIE = "zudoku-access-token";
4125
+ var REFRESH_TOKEN_COOKIE = "zudoku-refresh-token";
4126
+ var AUTH_PROFILE_COOKIE = "zudoku-auth-profile";
4127
+
4128
+ // src/lib/manifest.ts
4129
+ init_joinUrl();
4130
+ var PROTECTED_CHUNK_DIR = "_protected";
4131
+ var MANIFEST_VERSION = 1;
4132
+ var MANIFEST_FILENAME = "zudoku-manifest.json";
4133
+ var buildManifest = (config2) => {
4134
+ const protectedRoutes = ProtectedRoutesSchema.parse(config2.protectedRoutes);
4135
+ const routePatterns = protectedRoutes ? Object.keys(protectedRoutes) : [];
4136
+ return {
4137
+ version: MANIFEST_VERSION,
4138
+ basePath: config2.basePath ?? "/",
4139
+ ssrEntry: "server/entry.js",
4140
+ static: {
4141
+ prefixes: [joinUrl(config2.basePath, "assets")]
4142
+ },
4143
+ protected: {
4144
+ chunkPrefix: joinUrl(config2.basePath, PROTECTED_CHUNK_DIR),
4145
+ routePatterns
4146
+ },
4147
+ auth: {
4148
+ sessionEndpoint: joinUrl(config2.basePath, "/__z/auth/session"),
4149
+ cookies: {
4150
+ access: ACCESS_TOKEN_COOKIE,
4151
+ refresh: REFRESH_TOKEN_COOKIE,
4152
+ profile: AUTH_PROFILE_COOKIE
4153
+ }
4154
+ }
4155
+ };
4156
+ };
4157
+
4158
+ // src/vite/config.ts
4084
4159
  init_joinUrl();
4085
4160
 
4086
4161
  // src/vite/package-root.ts
@@ -4426,14 +4501,14 @@ var flattenAllOf = (schema2) => {
4426
4501
  };
4427
4502
 
4428
4503
  // src/lib/util/traverse.ts
4429
- var traverse = (specification, transform, path28 = []) => {
4430
- const transformed = transform(specification, path28);
4504
+ var traverse = (specification, transform, path30 = []) => {
4505
+ const transformed = transform(specification, path30);
4431
4506
  if (typeof transformed !== "object" || transformed === null) {
4432
4507
  return transformed;
4433
4508
  }
4434
4509
  const result = Array.isArray(transformed) ? [] : {};
4435
4510
  for (const [key, value] of Object.entries(transformed)) {
4436
- const currentPath = [...path28, key];
4511
+ const currentPath = [...path30, key];
4437
4512
  if (Array.isArray(value)) {
4438
4513
  result[key] = value.map(
4439
4514
  (item, index) => typeof item === "object" && item != null ? traverse(item, transform, [...currentPath, index.toString()]) : item
@@ -4452,7 +4527,7 @@ var CIRCULAR_REF = "$[Circular Reference]";
4452
4527
  var SCHEMA_REF_PREFIX = "$ref:";
4453
4528
 
4454
4529
  // src/lib/oas/parser/dereference/resolveRef.ts
4455
- var cache = /* @__PURE__ */ new Map();
4530
+ var cache = /* @__PURE__ */ new WeakMap();
4456
4531
  var resolveLocalRef = (schema2, ref) => {
4457
4532
  if (!cache.has(schema2)) {
4458
4533
  cache.set(schema2, /* @__PURE__ */ new Map());
@@ -4461,9 +4536,9 @@ var resolveLocalRef = (schema2, ref) => {
4461
4536
  if (schemaCache?.has(ref)) {
4462
4537
  return schemaCache.get(ref);
4463
4538
  }
4464
- const path28 = ref.split("/").slice(1);
4539
+ const path30 = ref.split("/").slice(1);
4465
4540
  let current = schema2;
4466
- for (const segment of path28) {
4541
+ for (const segment of path30) {
4467
4542
  if (!current || typeof current !== "object") {
4468
4543
  current = null;
4469
4544
  }
@@ -4474,7 +4549,7 @@ var resolveLocalRef = (schema2, ref) => {
4474
4549
  };
4475
4550
 
4476
4551
  // src/lib/oas/parser/dereference/index.ts
4477
- var cache2 = /* @__PURE__ */ new Map();
4552
+ var cache2 = /* @__PURE__ */ new WeakMap();
4478
4553
  var isIndexableObject = (obj) => obj !== null && typeof obj === "object";
4479
4554
  var dereference = async (schema2, resolvers = []) => {
4480
4555
  if (cache2.has(schema2)) {
@@ -4482,7 +4557,7 @@ var dereference = async (schema2, resolvers = []) => {
4482
4557
  }
4483
4558
  const cloned = structuredClone(schema2);
4484
4559
  const visited = /* @__PURE__ */ new Set();
4485
- const resolve = async (current, path28) => {
4560
+ const resolve = async (current, path30) => {
4486
4561
  if (isIndexableObject(current)) {
4487
4562
  if (visited.has(current)) {
4488
4563
  return CIRCULAR_REF;
@@ -4490,7 +4565,7 @@ var dereference = async (schema2, resolvers = []) => {
4490
4565
  visited.add(current);
4491
4566
  if (Array.isArray(current)) {
4492
4567
  for (let index = 0; index < current.length; index++) {
4493
- current[index] = await resolve(current[index], `${path28}/${index}`);
4568
+ current[index] = await resolve(current[index], `${path30}/${index}`);
4494
4569
  }
4495
4570
  } else {
4496
4571
  if ("$ref" in current && typeof current.$ref === "string") {
@@ -4501,13 +4576,13 @@ var dereference = async (schema2, resolvers = []) => {
4501
4576
  for (const resolver of resolvers) {
4502
4577
  const resolved = await resolver($ref);
4503
4578
  if (resolved) {
4504
- result2 = await resolve(resolved, path28);
4579
+ result2 = await resolve(resolved, path30);
4505
4580
  break;
4506
4581
  }
4507
4582
  }
4508
4583
  if (result2 === void 0) {
4509
4584
  const resolved = await resolveLocalRef(cloned, $ref);
4510
- result2 = await resolve(resolved, path28);
4585
+ result2 = await resolve(resolved, path30);
4511
4586
  }
4512
4587
  if (hasSiblings) {
4513
4588
  if (result2 === CIRCULAR_REF) {
@@ -4520,7 +4595,7 @@ var dereference = async (schema2, resolvers = []) => {
4520
4595
  return result2;
4521
4596
  }
4522
4597
  for (const key in current) {
4523
- current[key] = await resolve(current[key], `${path28}/${key}`);
4598
+ current[key] = await resolve(current[key], `${path30}/${key}`);
4524
4599
  }
4525
4600
  }
4526
4601
  visited.delete(current);
@@ -4559,9 +4634,9 @@ var upgradeSchema = (schema2) => {
4559
4634
  }
4560
4635
  return sub;
4561
4636
  });
4562
- schema2 = traverse(schema2, (sub, path28) => {
4637
+ schema2 = traverse(schema2, (sub, path30) => {
4563
4638
  if (sub.example !== void 0) {
4564
- if (isSchemaPath(path28 ?? [])) {
4639
+ if (isSchemaPath(path30 ?? [])) {
4565
4640
  sub.examples = [sub.example];
4566
4641
  } else {
4567
4642
  sub.examples = {
@@ -4574,11 +4649,11 @@ var upgradeSchema = (schema2) => {
4574
4649
  }
4575
4650
  return sub;
4576
4651
  });
4577
- schema2 = traverse(schema2, (schema3, path28) => {
4652
+ schema2 = traverse(schema2, (schema3, path30) => {
4578
4653
  if (schema3.type === "object" && schema3.properties !== void 0) {
4579
- const parentPath = path28?.slice(0, -1);
4654
+ const parentPath = path30?.slice(0, -1);
4580
4655
  const isMultipart = parentPath?.some((segment, index) => {
4581
- return segment === "content" && path28?.[index + 1] === "multipart/form-data";
4656
+ return segment === "content" && path30?.[index + 1] === "multipart/form-data";
4582
4657
  });
4583
4658
  if (isMultipart) {
4584
4659
  const entries = Object.entries(schema3.properties);
@@ -4592,8 +4667,8 @@ var upgradeSchema = (schema2) => {
4592
4667
  }
4593
4668
  return schema3;
4594
4669
  });
4595
- schema2 = traverse(schema2, (schema3, path28) => {
4596
- if (path28?.includes("content") && path28.includes("application/octet-stream")) {
4670
+ schema2 = traverse(schema2, (schema3, path30) => {
4671
+ if (path30?.includes("content") && path30.includes("application/octet-stream")) {
4597
4672
  return {};
4598
4673
  }
4599
4674
  if (schema3.type === "string" && schema3.format === "binary") {
@@ -4619,11 +4694,11 @@ var upgradeSchema = (schema2) => {
4619
4694
  }
4620
4695
  return sub;
4621
4696
  });
4622
- schema2 = traverse(schema2, (schema3, path28) => {
4697
+ schema2 = traverse(schema2, (schema3, path30) => {
4623
4698
  if (schema3.type === "string" && schema3.format === "byte") {
4624
- const parentPath = path28?.slice(0, -1);
4699
+ const parentPath = path30?.slice(0, -1);
4625
4700
  const contentMediaType = parentPath?.find(
4626
- (_, index) => path28?.[index - 1] === "content"
4701
+ (_, index) => path30?.[index - 1] === "content"
4627
4702
  );
4628
4703
  return {
4629
4704
  type: "string",
@@ -4635,7 +4710,7 @@ var upgradeSchema = (schema2) => {
4635
4710
  });
4636
4711
  return schema2;
4637
4712
  };
4638
- function isSchemaPath(path28) {
4713
+ function isSchemaPath(path30) {
4639
4714
  const schemaLocations = [
4640
4715
  ["components", "schemas"],
4641
4716
  "properties",
@@ -4648,10 +4723,10 @@ function isSchemaPath(path28) {
4648
4723
  ];
4649
4724
  return schemaLocations.some((location) => {
4650
4725
  if (Array.isArray(location)) {
4651
- return location.every((segment, index) => path28[index] === segment);
4726
+ return location.every((segment, index) => path30[index] === segment);
4652
4727
  }
4653
- return path28.includes(location);
4654
- }) || path28.includes("schema") || path28.some((segment) => segment.endsWith("Schema"));
4728
+ return path30.includes(location);
4729
+ }) || path30.includes("schema") || path30.some((segment) => segment.endsWith("Schema"));
4655
4730
  }
4656
4731
 
4657
4732
  // src/lib/oas/parser/index.ts
@@ -4671,7 +4746,7 @@ var parseSchemaInput = async (schemaInput) => {
4671
4746
  let response;
4672
4747
  try {
4673
4748
  response = await fetch(schemaInput, {
4674
- cache: "force-cache"
4749
+ cache: typeof window !== "undefined" ? "force-cache" : void 0
4675
4750
  });
4676
4751
  } catch (err) {
4677
4752
  throw new GraphQLError("Failed to fetch schema", {
@@ -4733,13 +4808,13 @@ var OPENAPI_PROPS = /* @__PURE__ */ new Set([
4733
4808
  "anyOf",
4734
4809
  "oneOf"
4735
4810
  ]);
4736
- var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path28 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
4811
+ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path30 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
4737
4812
  if (obj === null || typeof obj !== "object") return obj;
4738
4813
  const refPath = obj.__$ref;
4739
4814
  const isCircular = currentPath.has(obj) || typeof refPath === "string" && currentRefPaths.has(refPath);
4740
4815
  if (isCircular) {
4741
4816
  if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
4742
- const circularProp = path28.find((p) => !OPENAPI_PROPS.has(p)) || path28[0];
4817
+ const circularProp = path30.find((p) => !OPENAPI_PROPS.has(p)) || path30[0];
4743
4818
  return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
4744
4819
  }
4745
4820
  if (refs.has(obj)) return refs.get(obj);
@@ -4749,7 +4824,7 @@ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs
4749
4824
  value,
4750
4825
  currentPath,
4751
4826
  refs,
4752
- [...path28, key],
4827
+ [...path30, key],
4753
4828
  currentRefPaths
4754
4829
  );
4755
4830
  const result = Array.isArray(obj) ? obj.map((item, i) => recurse(item, i.toString())) : Object.fromEntries(
@@ -4787,7 +4862,7 @@ var resolveExtensions = (obj) => Object.fromEntries(
4787
4862
  var getAllTags = (schema2) => {
4788
4863
  const rootTags = schema2.tags ?? [];
4789
4864
  const operations = Object.values(schema2.paths ?? {}).flatMap(
4790
- (path28) => HttpMethods.map((k) => path28?.[k]).filter((op) => op != null)
4865
+ (path30) => HttpMethods.map((k) => path30?.[k]).filter((op) => op != null)
4791
4866
  );
4792
4867
  const operationTags = new Set(operations.flatMap((op) => op.tags ?? []));
4793
4868
  const hasUntaggedOperations = operations.some(
@@ -4842,7 +4917,7 @@ var getAllSlugs = (ops, schemaTags = []) => {
4842
4917
  var getOperationSlugKey = (op) => [op.path, op.method, op.operationId, op.summary].filter(Boolean).join("-");
4843
4918
  var getAllOperations = (paths) => {
4844
4919
  const operations = Object.entries(paths ?? {}).flatMap(
4845
- ([path28, value]) => HttpMethods.flatMap((method) => {
4920
+ ([path30, value]) => HttpMethods.flatMap((method) => {
4846
4921
  if (!value?.[method]) return [];
4847
4922
  const operation = value[method];
4848
4923
  const pathParameters = value.parameters ?? [];
@@ -4862,7 +4937,7 @@ var getAllOperations = (paths) => {
4862
4937
  return {
4863
4938
  ...operation,
4864
4939
  method,
4865
- path: path28,
4940
+ path: path30,
4866
4941
  parameters,
4867
4942
  servers,
4868
4943
  tags: operation.tags ?? []
@@ -5064,10 +5139,10 @@ var resolveSecuritySchemes = (schema2) => {
5064
5139
  var resolveSecurityRequirements = (securityArray, securitySchemes) => {
5065
5140
  if (!securityArray) return [];
5066
5141
  return securityArray.map((req) => ({
5067
- schemes: Object.entries(req).filter(([key]) => !key.startsWith("__")).flatMap(([schemeName, scopes]) => {
5142
+ schemes: Object.entries(req).filter(([key]) => !key.startsWith("__")).flatMap(([schemeName, scopes2]) => {
5068
5143
  const scheme = securitySchemes.find((s) => s.name === schemeName);
5069
5144
  if (!scheme) return [];
5070
- return [{ scheme, scopes }];
5145
+ return [{ scheme, scopes: scopes2 }];
5071
5146
  })
5072
5147
  }));
5073
5148
  };
@@ -5360,8 +5435,8 @@ var Schema = builder.objectRef("Schema").implement({
5360
5435
  }),
5361
5436
  paths: t.field({
5362
5437
  type: [PathItem],
5363
- resolve: (root) => Object.entries(root.paths ?? {}).map(([path28, value]) => ({
5364
- path: path28,
5438
+ resolve: (root) => Object.entries(root.paths ?? {}).map(([path30, value]) => ({
5439
+ path: path30,
5365
5440
  // biome-ignore lint/style/noNonNullAssertion: value is guaranteed to be defined
5366
5441
  methods: Object.keys(value)
5367
5442
  }))
@@ -5517,7 +5592,7 @@ init_joinUrl();
5517
5592
 
5518
5593
  // src/vite/api/schema-codegen.ts
5519
5594
  var unescapeJsonPointer = (uri) => decodeURIComponent(uri.replace(/~1/g, "/").replace(/~0/g, "~"));
5520
- var getSegmentsFromPath = (path28) => path28.split("/").slice(1).map(unescapeJsonPointer);
5595
+ var getSegmentsFromPath = (path30) => path30.split("/").slice(1).map(unescapeJsonPointer);
5521
5596
  var createLocalRefMap = (obj) => {
5522
5597
  const refMap = /* @__PURE__ */ new Map();
5523
5598
  const siblingsMap = /* @__PURE__ */ new Map();
@@ -5548,16 +5623,16 @@ var replaceMarkers = (code, mergedRefs) => code.replace(/"__refMap:(.*?)"/g, '__
5548
5623
  /"__refMap\+Siblings:(.*?)"/g,
5549
5624
  (_, key) => mergedRefs.get(key) ?? `__refMap["${key}"]`
5550
5625
  );
5551
- var lookup = (schema2, path28, filePath) => {
5552
- const parts = getSegmentsFromPath(path28);
5626
+ var lookup = (schema2, path30, filePath) => {
5627
+ const parts = getSegmentsFromPath(path30);
5553
5628
  let val = schema2;
5554
5629
  for (const part of parts) {
5555
5630
  while (val.$ref?.startsWith("#/")) {
5556
- val = val.$ref === path28 ? val : lookup(schema2, val.$ref, filePath);
5631
+ val = val.$ref === path30 ? val : lookup(schema2, val.$ref, filePath);
5557
5632
  }
5558
5633
  if (val[part] === void 0) {
5559
5634
  throw new Error(
5560
- `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path28}`
5635
+ `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path30}`
5561
5636
  );
5562
5637
  }
5563
5638
  val = val[part];
@@ -5806,8 +5881,8 @@ var SchemaManager = class {
5806
5881
  }
5807
5882
  }
5808
5883
  };
5809
- getLatestSchema = (path28) => this.processedSchemas[path28]?.at(0);
5810
- getSchemasForPath = (path28) => this.processedSchemas[path28];
5884
+ getLatestSchema = (path30) => this.processedSchemas[path30]?.at(0);
5885
+ getSchemasForPath = (path30) => this.processedSchemas[path30];
5811
5886
  getSchemaImports = () => Object.values(this.processedSchemas).flat().filter((s) => s.importKey);
5812
5887
  getUrlToFilePathMap = () => {
5813
5888
  const map = /* @__PURE__ */ new Map();
@@ -6173,6 +6248,7 @@ var viteConfigReloadPlugin = () => ({
6173
6248
  });
6174
6249
 
6175
6250
  // src/vite/plugin-api.ts
6251
+ var PROCESSED_STORE_SUBPATH = "node_modules/.zudoku/processed";
6176
6252
  var viteApiPlugin = async () => {
6177
6253
  const virtualModuleId4 = "virtual:zudoku-api-plugins";
6178
6254
  const resolvedVirtualModuleId4 = `\0${virtualModuleId4}`;
@@ -6184,7 +6260,7 @@ var viteApiPlugin = async () => {
6184
6260
  const buildProcessors = buildConfig?.processors ?? [];
6185
6261
  const tmpStoreDir = path11.posix.join(
6186
6262
  initialConfig.__meta.rootDir,
6187
- "node_modules/.zudoku/processed"
6263
+ PROCESSED_STORE_SUBPATH
6188
6264
  );
6189
6265
  const processors = [...buildProcessors, ...zuploProcessors];
6190
6266
  const schemaManager = new SchemaManager({
@@ -6764,7 +6840,7 @@ init_ProtectedRoutesSchema();
6764
6840
  init_joinUrl();
6765
6841
  import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
6766
6842
  import path13 from "node:path";
6767
- import { matchPath } from "react-router";
6843
+ init_url();
6768
6844
  var processMarkdownFile = async (filePath) => {
6769
6845
  const { content: markdownContent, data: frontmatter } = await readFrontmatter(filePath);
6770
6846
  let finalMarkdown = markdownContent;
@@ -6816,13 +6892,9 @@ var viteMarkdownExportPlugin = () => {
6816
6892
  config2.protectedRoutes
6817
6893
  );
6818
6894
  if (protectedRoutes) {
6819
- const isProtectedRoute = (routePath) => {
6820
- return Object.keys(protectedRoutes).some(
6821
- (route) => matchPath({ path: route, end: true }, routePath)
6822
- );
6823
- };
6895
+ const patterns = Object.keys(protectedRoutes);
6824
6896
  for (const routePath of Object.keys(markdownFiles)) {
6825
- if (isProtectedRoute(routePath)) {
6897
+ if (matchesAnyProtectedPattern(patterns, routePath)) {
6826
6898
  delete markdownFiles[routePath];
6827
6899
  }
6828
6900
  }
@@ -7501,6 +7573,155 @@ function vitePlugin() {
7501
7573
  ];
7502
7574
  }
7503
7575
 
7576
+ // src/vite/protected/registry.ts
7577
+ init_ProtectedRoutesSchema();
7578
+ init_joinUrl();
7579
+ init_url();
7580
+ import { matchPath as matchPath2 } from "react-router";
7581
+ var scopes = /* @__PURE__ */ new Map();
7582
+ var clearProtectedRegistry = () => scopes.clear();
7583
+ var registerProtectedScope = (moduleId, scope) => {
7584
+ const list = scopes.get(moduleId);
7585
+ if (list) list.push(scope);
7586
+ else scopes.set(moduleId, [scope]);
7587
+ };
7588
+ var scopeMatchesPattern = (scope, pattern) => {
7589
+ if (scope.type === "route") {
7590
+ return matchesProtectedPattern(pattern, joinUrl(scope.path));
7591
+ }
7592
+ const root = joinUrl(scope.root);
7593
+ if (!pattern.includes("*")) {
7594
+ return matchesProtectedPattern(pattern, root);
7595
+ }
7596
+ return matchPath2({ path: pattern, end: false }, root) != null;
7597
+ };
7598
+ var getProtectedSourceMatcher = (config2) => {
7599
+ const protectedRoutes = ProtectedRoutesSchema.parse(config2.protectedRoutes);
7600
+ const patterns = protectedRoutes ? Object.keys(protectedRoutes) : [];
7601
+ if (patterns.length === 0) {
7602
+ return { match: () => false, enabled: false, patterns };
7603
+ }
7604
+ return {
7605
+ enabled: true,
7606
+ patterns,
7607
+ match: (id) => {
7608
+ const pathOnly = id.split("?")[0] ?? id;
7609
+ const moduleScopes = scopes.get(pathOnly);
7610
+ if (!moduleScopes) return false;
7611
+ return moduleScopes.some(
7612
+ (s) => patterns.some((p) => scopeMatchesPattern(s, p))
7613
+ );
7614
+ }
7615
+ };
7616
+ };
7617
+ var findUnmatchedProtectedPatterns = (patterns) => patterns.filter(
7618
+ (p) => ![...scopes.values()].some(
7619
+ (scopeList) => scopeList.some((s) => scopeMatchesPattern(s, p))
7620
+ )
7621
+ );
7622
+
7623
+ // src/vite/protected/annotator.ts
7624
+ var walk = (node, visit9) => {
7625
+ if (!node || typeof node !== "object") return;
7626
+ if (typeof node.type === "string") visit9(node);
7627
+ for (const key of Object.keys(node)) {
7628
+ if (key === "loc" || key === "start" || key === "end" || key === "range") {
7629
+ continue;
7630
+ }
7631
+ const val = node[key];
7632
+ if (Array.isArray(val)) {
7633
+ for (const v of val) walk(v, visit9);
7634
+ } else if (val && typeof val === "object") {
7635
+ walk(val, visit9);
7636
+ }
7637
+ }
7638
+ };
7639
+ var literalString = (node) => node?.type === "Literal" && typeof node.value === "string" ? node.value : void 0;
7640
+ var propKey = (prop) => prop.key?.type === "Identifier" ? prop.key.name : literalString(prop.key);
7641
+ var collectImportSpecs = (node) => {
7642
+ const out = [];
7643
+ walk(node, (n) => {
7644
+ if (n.type === "ImportExpression") {
7645
+ const spec = literalString(n.source);
7646
+ if (spec) out.push(spec);
7647
+ }
7648
+ });
7649
+ return out;
7650
+ };
7651
+ var matchPathObject = (node) => {
7652
+ if (node.type !== "ObjectExpression") return;
7653
+ let root;
7654
+ const siblingValues = [];
7655
+ for (const prop of node.properties ?? []) {
7656
+ if (prop.type !== "Property") continue;
7657
+ const name = propKey(prop);
7658
+ const strValue = literalString(prop.value);
7659
+ if (name === "path" && strValue) root = strValue;
7660
+ else siblingValues.push(prop.value);
7661
+ }
7662
+ if (!root) return;
7663
+ const specs = siblingValues.flatMap(collectImportSpecs);
7664
+ if (specs.length === 0) return;
7665
+ return { root, specs };
7666
+ };
7667
+ var matchRouteDict = (node) => {
7668
+ if (node.type !== "ObjectExpression") return;
7669
+ const props = node.properties ?? [];
7670
+ if (props.length === 0) return;
7671
+ const pairs = [];
7672
+ for (const prop of props) {
7673
+ if (prop.type !== "Property") return;
7674
+ const key = literalString(prop.key);
7675
+ if (!key?.startsWith("/") || key.includes(".")) return;
7676
+ if (prop.value?.type !== "ArrowFunctionExpression" || prop.value.body?.type !== "ImportExpression") {
7677
+ return;
7678
+ }
7679
+ const spec = literalString(prop.value.body.source);
7680
+ if (!spec) return;
7681
+ pairs.push({ root: key, spec });
7682
+ }
7683
+ return pairs;
7684
+ };
7685
+ var protectedAnnotatorPlugin = () => ({
7686
+ name: "zudoku:protected-annotator",
7687
+ buildStart() {
7688
+ clearProtectedRegistry();
7689
+ },
7690
+ async transform(code, id) {
7691
+ if (id.includes("/node_modules/")) return;
7692
+ if (!code.includes("import(")) return;
7693
+ let ast;
7694
+ try {
7695
+ ast = this.parse(code);
7696
+ } catch (err) {
7697
+ this.warn(
7698
+ `protected-annotator: failed to parse ${id}: ${err instanceof Error ? err.message : String(err)}. Protected gating will NOT apply to this module.`
7699
+ );
7700
+ return;
7701
+ }
7702
+ const tasks = [];
7703
+ walk(ast, (node) => {
7704
+ const a = matchPathObject(node);
7705
+ if (a) for (const spec of a.specs) tasks.push({ spec, root: a.root });
7706
+ const b = matchRouteDict(node);
7707
+ if (b) for (const { spec, root } of b) tasks.push({ spec, root });
7708
+ });
7709
+ for (const { spec, root } of tasks) {
7710
+ const resolved = await this.resolve(spec, id);
7711
+ if (!resolved || resolved.external) {
7712
+ this.warn(
7713
+ `Route-shaped import "${spec}" in ${id} did not resolve to a first-party module; protected gating will not apply.`
7714
+ );
7715
+ continue;
7716
+ }
7717
+ registerProtectedScope(resolved.id.split("?")[0] ?? resolved.id, {
7718
+ type: "subtree",
7719
+ root
7720
+ });
7721
+ }
7722
+ }
7723
+ });
7724
+
7504
7725
  // src/vite/config.ts
7505
7726
  var getAppClientEntryPath = () => path16.posix.join(getZudokuRootDir(), "src/app/entry.client.tsx");
7506
7727
  var getAppServerEntryPath = () => path16.posix.join(getZudokuRootDir(), "src/app/entry.server.tsx");
@@ -7512,11 +7733,15 @@ var defineEnvVars = (vars) => Object.fromEntries(
7512
7733
  [`import.meta.env.${v}`, JSON.stringify(process.env[v])]
7513
7734
  ])
7514
7735
  );
7515
- async function getViteConfig(dir, configEnv) {
7736
+ async function getViteConfig(dir, configEnv, options = {}) {
7516
7737
  const { config: config2, publicEnv: publicEnv2, envPrefix: envPrefix2 } = await loadZudokuConfig(
7517
7738
  configEnv,
7518
7739
  dir
7519
7740
  );
7741
+ const { match: isProtectedSource, enabled: hasProtectedSources } = getProtectedSourceMatcher(config2);
7742
+ const shouldProtectChunks = hasProtectedSources && options.ssr === true;
7743
+ const isProtectedChunk = (chunk) => chunk.facadeModuleId && isProtectedSource(chunk.facadeModuleId) || chunk.moduleIds.some(isProtectedSource);
7744
+ const isWorker = options.adapter === "cloudflare";
7520
7745
  const cdnUrl = CdnUrlSchema.parse(config2.cdnUrl);
7521
7746
  const base = cdnUrl?.base ? joinUrl(cdnUrl.base, config2.basePath) : config2.basePath;
7522
7747
  if (cdnUrl && !hasLoggedCdnInfo) {
@@ -7542,6 +7767,10 @@ async function getViteConfig(dir, configEnv) {
7542
7767
  root: dir,
7543
7768
  base,
7544
7769
  appType: "custom",
7770
+ // Cloudflare Workers: `webworker` makes Vite pick the browser platform
7771
+ // for rolldown and avoids emitting `createRequire(import.meta.url)`,
7772
+ // which is undefined in Workers. See vitejs/vite#21969 (fix in 8.0.4+).
7773
+ ssr: isWorker ? { target: "webworker" } : void 0,
7545
7774
  configFile: false,
7546
7775
  clearScreen: false,
7547
7776
  logLevel: process.env.LOG_LEVEL ?? "info",
@@ -7599,13 +7828,19 @@ async function getViteConfig(dir, configEnv) {
7599
7828
  environments: {
7600
7829
  client: {
7601
7830
  build: {
7831
+ manifest: true,
7602
7832
  rolldownOptions: {
7603
- input: "zudoku/app/entry.client.tsx"
7833
+ input: "zudoku/app/entry.client.tsx",
7834
+ output: shouldProtectChunks ? {
7835
+ entryFileNames: (chunk) => isProtectedChunk(chunk) ? `${PROTECTED_CHUNK_DIR}/[name]-[hash].js` : "assets/[name]-[hash].js",
7836
+ chunkFileNames: (chunk) => isProtectedChunk(chunk) ? `${PROTECTED_CHUNK_DIR}/[name]-[hash].js` : "assets/[name]-[hash].js"
7837
+ } : void 0
7604
7838
  }
7605
7839
  }
7606
7840
  },
7607
7841
  ssr: {
7608
- resolve: {
7842
+ // Build: bundle all for self-contained SSR output; dev uses minimal externals for speed.
7843
+ resolve: configEnv.command === "build" ? { noExternal: true } : {
7609
7844
  noExternal: [/zudoku/, "@mdx-js/react"],
7610
7845
  external: ["@shikijs/themes", "@shikijs/langs"]
7611
7846
  },
@@ -7613,7 +7848,9 @@ async function getViteConfig(dir, configEnv) {
7613
7848
  outDir: path16.resolve(
7614
7849
  path16.join(dir, "dist", config2.basePath ?? "", "server")
7615
7850
  ),
7851
+ copyPublicDir: false,
7616
7852
  rolldownOptions: {
7853
+ logLevel: "warn",
7617
7854
  input: ["zudoku/app/entry.server.tsx", config2.__meta.configPath]
7618
7855
  }
7619
7856
  }
@@ -7621,6 +7858,9 @@ async function getViteConfig(dir, configEnv) {
7621
7858
  },
7622
7859
  experimental: {
7623
7860
  renderBuiltUrl(filename) {
7861
+ if (filename.startsWith(`${PROTECTED_CHUNK_DIR}/`)) {
7862
+ return joinUrl(config2.basePath, `/${filename}`);
7863
+ }
7624
7864
  if (cdnUrl?.base && [".js", ".css"].includes(path16.extname(filename))) {
7625
7865
  return joinUrl(cdnUrl.base, filename);
7626
7866
  }
@@ -7645,7 +7885,7 @@ async function getViteConfig(dir, configEnv) {
7645
7885
  "/__z/entry.client.tsx",
7646
7886
  "**/pagefind.js"
7647
7887
  ],
7648
- plugins: [vitePlugin()],
7888
+ plugins: [protectedAnnotatorPlugin(), vitePlugin()],
7649
7889
  future: {
7650
7890
  removeServerModuleGraph: "warn",
7651
7891
  removeSsrLoadModule: "warn",
@@ -7728,12 +7968,24 @@ ${cssLinks}
7728
7968
  `.trim();
7729
7969
  }
7730
7970
 
7971
+ // src/vite/manifest.ts
7972
+ import { writeFile as writeFile3 } from "node:fs/promises";
7973
+ import path17 from "node:path";
7974
+ var writeManifest = async (distDir, config2) => {
7975
+ await writeFile3(
7976
+ path17.join(distDir, MANIFEST_FILENAME),
7977
+ `${JSON.stringify(buildManifest(config2), null, 2)}
7978
+ `,
7979
+ "utf-8"
7980
+ );
7981
+ };
7982
+
7731
7983
  // src/vite/output.ts
7732
7984
  init_package_json();
7733
7985
  init_joinUrl();
7734
7986
  import assert from "node:assert";
7735
- import { cp, mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
7736
- import path17 from "node:path";
7987
+ import { cp, mkdir as mkdir3, writeFile as writeFile4 } from "node:fs/promises";
7988
+ import path18 from "node:path";
7737
7989
  var pkgJson = getZudokuPackageJson();
7738
7990
  function generateOutput({
7739
7991
  config: config2,
@@ -7790,10 +8042,10 @@ async function writeOutput(dir, {
7790
8042
  rewrites
7791
8043
  }) {
7792
8044
  const output = generateOutput({ config: config2, redirects, rewrites });
7793
- const outputDir = process.env.VERCEL ? path17.join(dir, ".vercel/output") : path17.join(dir, "dist/.output");
8045
+ const outputDir = process.env.VERCEL ? path18.join(dir, ".vercel/output") : path18.join(dir, "dist/.output");
7794
8046
  await mkdir3(outputDir, { recursive: true });
7795
- const outputFile = path17.join(outputDir, "config.json");
7796
- await writeFile3(outputFile, JSON.stringify(output, null, 2), "utf-8");
8047
+ const outputFile = path18.join(outputDir, "config.json");
8048
+ await writeFile4(outputFile, JSON.stringify(output, null, 2), "utf-8");
7797
8049
  if (process.env.VERCEL) {
7798
8050
  console.log("Wrote Vercel output to", outputDir);
7799
8051
  }
@@ -7805,7 +8057,7 @@ init_file_exists();
7805
8057
  import { readFileSync as readFileSync2 } from "node:fs";
7806
8058
  import { readFile as readFile2, rm } from "node:fs/promises";
7807
8059
  import os from "node:os";
7808
- import path20 from "node:path";
8060
+ import path21 from "node:path";
7809
8061
  import { pathToFileURL } from "node:url";
7810
8062
  import { createIndex } from "pagefind";
7811
8063
  import colors7 from "picocolors";
@@ -7847,7 +8099,7 @@ function throttle(fn) {
7847
8099
  init_joinUrl();
7848
8100
  import { createWriteStream, existsSync } from "node:fs";
7849
8101
  import { mkdir as mkdir4 } from "node:fs/promises";
7850
- import path18 from "node:path";
8102
+ import path19 from "node:path";
7851
8103
  import colors5 from "picocolors";
7852
8104
  import { SitemapStream } from "sitemap";
7853
8105
  async function generateSitemap({
@@ -7861,11 +8113,11 @@ async function generateSitemap({
7861
8113
  return;
7862
8114
  }
7863
8115
  const sitemap = new SitemapStream({ hostname: config2.siteUrl });
7864
- const outputDir = path18.resolve(baseOutputDir, config2.outDir ?? "");
8116
+ const outputDir = path19.resolve(baseOutputDir, config2.outDir ?? "");
7865
8117
  if (!existsSync(outputDir)) {
7866
8118
  await mkdir4(outputDir, { recursive: true });
7867
8119
  }
7868
- const sitemapOutputPath = path18.join(outputDir, "sitemap.xml");
8120
+ const sitemapOutputPath = path19.join(outputDir, "sitemap.xml");
7869
8121
  const writeStream = createWriteStream(sitemapOutputPath);
7870
8122
  sitemap.pipe(writeStream);
7871
8123
  let lastmod;
@@ -7895,14 +8147,14 @@ async function generateSitemap({
7895
8147
 
7896
8148
  // src/vite/prerender/utils.ts
7897
8149
  init_joinUrl();
7898
- var resolveRoutePath = (path28) => {
7899
- const segments = path28.split("/");
8150
+ var resolveRoutePath = (path30) => {
8151
+ const segments = path30.split("/");
7900
8152
  if (segments.some((s) => s.startsWith(":") && !s.endsWith("?"))) {
7901
8153
  return void 0;
7902
8154
  }
7903
8155
  return segments.filter((s) => !s.startsWith(":")).join("/") || void 0;
7904
8156
  };
7905
- var isSkipped = (path28) => path28.includes("*") || /^\d+$/.test(path28);
8157
+ var isSkipped = (path30) => path30.includes("*") || /^\d+$/.test(path30);
7906
8158
  var resolveRoutes = (routes, parentPath = "") => routes.flatMap((route) => {
7907
8159
  if (route.path && isSkipped(route.path)) return [];
7908
8160
  const routePath = route.path ? resolveRoutePath(route.path) : void 0;
@@ -7951,12 +8203,12 @@ var prerender = async ({
7951
8203
  serverConfigFilename,
7952
8204
  writeRedirects = true
7953
8205
  }) => {
7954
- const distDir = path20.join(dir, "dist", basePath);
8206
+ const distDir = path21.join(dir, "dist", basePath);
7955
8207
  const serverConfigPath = pathToFileURL(
7956
- path20.join(distDir, "server", serverConfigFilename)
8208
+ path21.join(distDir, "server", serverConfigFilename)
7957
8209
  ).href;
7958
8210
  const entryServerPath = pathToFileURL(
7959
- path20.join(distDir, "server/entry.server.js")
8211
+ path21.join(distDir, "server/entry.server.js")
7960
8212
  ).href;
7961
8213
  const rawConfig = await import(serverConfigPath).then(
7962
8214
  (m) => m.default
@@ -8068,7 +8320,7 @@ var prerender = async ({
8068
8320
  }
8069
8321
  if (isTTY()) writeLine("");
8070
8322
  const { outputPath } = await pagefindIndex.writeFiles({
8071
- outputPath: path20.join(distDir, "pagefind")
8323
+ outputPath: path21.join(distDir, "pagefind")
8072
8324
  });
8073
8325
  if (outputPath) {
8074
8326
  const duration = (performance.now() - pagefindStart) / 1e3;
@@ -8092,7 +8344,7 @@ var prerender = async ({
8092
8344
  const { generateLlmsTxtFiles: generateLlmsTxtFiles2 } = await Promise.resolve().then(() => (init_llms(), llms_exports));
8093
8345
  const docsConfig = DocsConfigSchema2.parse(config2.docs);
8094
8346
  const llmsConfig = docsConfig.llms ?? {};
8095
- const markdownInfoPath = path20.join(
8347
+ const markdownInfoPath = path21.join(
8096
8348
  dir,
8097
8349
  "node_modules/.zudoku/markdown-info.json"
8098
8350
  );
@@ -8117,7 +8369,7 @@ var prerender = async ({
8117
8369
  await Promise.all(
8118
8370
  markdownFileInfos.map((info) => {
8119
8371
  const outputPath = getMarkdownOutputPath(distDir, info.routePath);
8120
- if (!path20.resolve(outputPath).startsWith(path20.resolve(distDir))) {
8372
+ if (!path21.resolve(outputPath).startsWith(path21.resolve(distDir))) {
8121
8373
  return;
8122
8374
  }
8123
8375
  return rm(outputPath).catch(() => {
@@ -8175,19 +8427,123 @@ var getContainerMemoryLimitMb = () => {
8175
8427
  return void 0;
8176
8428
  };
8177
8429
 
8430
+ // src/vite/protected/build.ts
8431
+ import { mkdir as mkdir5, readdir, readFile as readFile3, rename, rm as rm2 } from "node:fs/promises";
8432
+ import path22 from "node:path";
8433
+ init_joinUrl();
8434
+ var assertProtectedPatternsCovered = (config2) => {
8435
+ const { patterns } = getProtectedSourceMatcher(config2);
8436
+ const unmatched = findUnmatchedProtectedPatterns(patterns);
8437
+ if (unmatched.length === 0) return;
8438
+ throw new Error(
8439
+ `[zudoku] protectedRoutes patterns with no matching content: ${unmatched.map((p) => `"${p}"`).join(", ")}.
8440
+ Either the pattern is a typo, or the route uses an inline element / dynamic path that isn't code-split. Load the route via dynamic import so it gets its own chunk, otherwise its JS ships in the public bundle.`
8441
+ );
8442
+ };
8443
+ var findProtectedLeaks = (output) => {
8444
+ const isProtected = (fileName) => fileName.startsWith(`${PROTECTED_CHUNK_DIR}/`);
8445
+ const chunks = output.filter((o) => o.type === "chunk");
8446
+ const byFileName = new Map(chunks.map((c) => [c.fileName, c]));
8447
+ const leaks = [];
8448
+ for (const entry of chunks.filter(
8449
+ (c) => c.isEntry && !isProtected(c.fileName)
8450
+ )) {
8451
+ const visited = /* @__PURE__ */ new Set();
8452
+ const stack = [{ fileName: entry.fileName, path: [entry.fileName] }];
8453
+ while (stack.length > 0) {
8454
+ const { fileName, path: path30 } = stack.pop();
8455
+ if (visited.has(fileName)) continue;
8456
+ visited.add(fileName);
8457
+ for (const imp of byFileName.get(fileName)?.imports ?? []) {
8458
+ const next = [...path30, imp];
8459
+ if (isProtected(imp)) {
8460
+ leaks.push(next.join(" -> "));
8461
+ continue;
8462
+ }
8463
+ stack.push({ fileName: imp, path: next });
8464
+ }
8465
+ }
8466
+ }
8467
+ return leaks;
8468
+ };
8469
+ var assertNoProtectedLeaks = (output) => {
8470
+ const protectedEntries = output.filter((o) => o.type === "chunk").filter(
8471
+ (c) => c.isEntry && c.fileName.startsWith(`${PROTECTED_CHUNK_DIR}/`)
8472
+ ).map((c) => c.fileName);
8473
+ if (protectedEntries.length > 0) {
8474
+ throw new Error(
8475
+ `Protected chunk(s) marked as entries:
8476
+ ${protectedEntries.join("\n ")}
8477
+ Entry chunks are loaded outside the gated import path. Move the entry to a public chunk that dynamically imports the protected one.`
8478
+ );
8479
+ }
8480
+ const leaks = findProtectedLeaks(output);
8481
+ if (leaks.length === 0) return;
8482
+ throw new Error(
8483
+ `Protected chunk(s) statically reachable from public entry:
8484
+ ${leaks.join("\n ")}
8485
+ This eagerly pulls gated content into the public bundle. Check that nothing in non-protected entry code statically imports the protected module.`
8486
+ );
8487
+ };
8488
+ var moveProtectedChunks = async (clientOutDir, serverOutDir) => {
8489
+ const srcDir = path22.join(clientOutDir, PROTECTED_CHUNK_DIR);
8490
+ const files = await readdir(srcDir).catch((err) => {
8491
+ if (err.code === "ENOENT") return null;
8492
+ throw err;
8493
+ });
8494
+ if (!files) return;
8495
+ const destDir = path22.join(serverOutDir, PROTECTED_CHUNK_DIR);
8496
+ await mkdir5(destDir, { recursive: true });
8497
+ await Promise.all(
8498
+ files.map(
8499
+ (file) => rename(path22.join(srcDir, file), path22.join(destDir, file))
8500
+ )
8501
+ );
8502
+ const leftover = await readdir(srcDir).catch(() => []);
8503
+ if (leftover.length > 0) {
8504
+ throw new Error(
8505
+ `moveProtectedChunks left ${leftover.length} file(s) in ${srcDir}: ${leftover.join(", ")}.
8506
+ These would be served publicly. Aborting build.`
8507
+ );
8508
+ }
8509
+ await rm2(srcDir, { recursive: true, force: true });
8510
+ };
8511
+ var assertCloudflareWranglerGatesProtected = async (dir, config2) => {
8512
+ const { enabled } = getProtectedSourceMatcher(config2);
8513
+ if (!enabled) return;
8514
+ const protectedPrefix = `${joinUrl(config2.basePath, PROTECTED_CHUNK_DIR)}/`;
8515
+ const candidates = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
8516
+ for (const name of candidates) {
8517
+ const file = await readFile3(path22.join(dir, name), "utf-8").catch(
8518
+ () => void 0
8519
+ );
8520
+ if (file === void 0) continue;
8521
+ if (file.includes("run_worker_first") && file.includes(protectedPrefix)) {
8522
+ return;
8523
+ }
8524
+ throw new Error(
8525
+ `[zudoku] ${name} must configure \`run_worker_first\` to include \`${protectedPrefix}*\` so the auth gate runs before the assets binding serves protected chunks. Without it, ${protectedPrefix}* is publicly readable. See https://developers.cloudflare.com/workers/static-assets/binding/#run_worker_first.`
8526
+ );
8527
+ }
8528
+ throw new Error(
8529
+ `[zudoku] No wrangler config found in ${dir} (looked for ${candidates.join(", ")}). Cloudflare adapter requires wrangler config with \`run_worker_first\` covering \`${protectedPrefix}*\`.`
8530
+ );
8531
+ };
8532
+
8178
8533
  // src/vite/build.ts
8179
8534
  var DIST_DIR = "dist";
8180
8535
  async function runBuild(options) {
8181
8536
  const { dir, ssr, adapter = "node" } = options;
8182
- const viteConfig = await getViteConfig(dir, {
8183
- mode: "production",
8184
- command: "build"
8185
- });
8537
+ const viteConfig = await getViteConfig(
8538
+ dir,
8539
+ { mode: "production", command: "build" },
8540
+ { adapter, ssr }
8541
+ );
8186
8542
  const builder2 = await createBuilder(viteConfig);
8187
8543
  invariant(builder2.environments.client, "Client environment is missing");
8188
8544
  invariant(builder2.environments.ssr, "SSR environment is missing");
8189
- const distDir = path21.resolve(path21.join(dir, "dist"));
8190
- await rm2(distDir, { recursive: true, force: true });
8545
+ const distDir = path23.resolve(path23.join(dir, "dist"));
8546
+ await rm3(distDir, { recursive: true, force: true });
8191
8547
  const [clientResult, serverResult] = await Promise.all([
8192
8548
  builder2.build(builder2.environments.client),
8193
8549
  builder2.build(builder2.environments.ssr)
@@ -8226,10 +8582,23 @@ async function runBuild(options) {
8226
8582
  dir,
8227
8583
  adapter,
8228
8584
  serverOutDir,
8229
- html,
8230
- basePath: config2.basePath
8585
+ html
8231
8586
  });
8232
- await rm2(path21.join(clientOutDir, "index.html"), { force: true });
8587
+ assertProtectedPatternsCovered(config2);
8588
+ assertNoProtectedLeaks(clientResult.output);
8589
+ if (adapter !== "cloudflare") {
8590
+ await moveProtectedChunks(clientOutDir, serverOutDir);
8591
+ } else {
8592
+ await assertCloudflareWranglerGatesProtected(dir, config2);
8593
+ }
8594
+ await writeFile6(
8595
+ path23.join(distDir, "package.json"),
8596
+ `${JSON.stringify({ type: "module" }, null, 2)}
8597
+ `,
8598
+ "utf-8"
8599
+ );
8600
+ await writeManifest(distDir, config2);
8601
+ await rm3(path23.join(clientOutDir, "index.html"), { force: true });
8233
8602
  } else {
8234
8603
  await runPrerender({
8235
8604
  dir,
@@ -8260,25 +8629,25 @@ var runPrerender = async (options) => {
8260
8629
  serverConfigFilename,
8261
8630
  writeRedirects: process.env.VERCEL === void 0
8262
8631
  });
8263
- const indexHtml = path21.join(clientOutDir, "index.html");
8632
+ const indexHtml = path23.join(clientOutDir, "index.html");
8264
8633
  if (!workerResults.find((r) => r.outputPath === indexHtml)) {
8265
- await writeFile5(indexHtml, html, "utf-8");
8634
+ await writeFile6(indexHtml, html, "utf-8");
8266
8635
  }
8267
8636
  const statusPages = workerResults.flatMap(
8268
- (r) => /^(400|404|500)\.html$/.test(path21.basename(r.outputPath)) ? r.outputPath : []
8637
+ (r) => /^(400|404|500)\.html$/.test(path23.basename(r.outputPath)) ? r.outputPath : []
8269
8638
  );
8270
8639
  for (const statusPage of statusPages) {
8271
- await rename(
8640
+ await rename2(
8272
8641
  statusPage,
8273
- path21.join(dir, DIST_DIR, path21.basename(statusPage))
8642
+ path23.join(dir, DIST_DIR, path23.basename(statusPage))
8274
8643
  );
8275
8644
  }
8276
- await rm2(serverOutDir, { recursive: true, force: true });
8645
+ await rm3(serverOutDir, { recursive: true, force: true });
8277
8646
  if (process.env.VERCEL) {
8278
- await mkdir5(path21.join(dir, ".vercel/output/static"), { recursive: true });
8279
- await rename(
8280
- path21.join(dir, DIST_DIR),
8281
- path21.join(dir, ".vercel/output/static")
8647
+ await mkdir6(path23.join(dir, ".vercel/output/static"), { recursive: true });
8648
+ await rename2(
8649
+ path23.join(dir, DIST_DIR),
8650
+ path23.join(dir, ".vercel/output/static")
8282
8651
  );
8283
8652
  }
8284
8653
  await writeOutput(dir, {
@@ -8288,8 +8657,8 @@ var runPrerender = async (options) => {
8288
8657
  });
8289
8658
  if (ZuploEnv.isZuplo && issuer) {
8290
8659
  const provider = config2.authentication?.type;
8291
- await writeFile5(
8292
- path21.join(dir, DIST_DIR, ".output/zuplo.json"),
8660
+ await writeFile6(
8661
+ path23.join(dir, DIST_DIR, ".output/zuplo.json"),
8293
8662
  JSON.stringify({ issuer, provider }, null, 2),
8294
8663
  "utf-8"
8295
8664
  );
@@ -8299,33 +8668,63 @@ var runPrerender = async (options) => {
8299
8668
  throw e;
8300
8669
  }
8301
8670
  };
8671
+ var findUserEntry = (dir) => {
8672
+ for (const ext of ["ts", "tsx", "js", "mjs"]) {
8673
+ const candidate = path23.join(dir, `zudoku.server.${ext}`);
8674
+ if (existsSync2(candidate)) return candidate;
8675
+ }
8676
+ };
8302
8677
  var bundleSSREntry = async (options) => {
8303
- const { dir, adapter, serverOutDir, html, basePath } = options;
8304
- const tempEntryPath = path21.join(dir, "__ssr-entry.ts");
8678
+ const { dir, adapter, serverOutDir, html } = options;
8305
8679
  const packageRoot = getZudokuRootDir();
8306
- const templateContent = await readFile3(
8307
- path21.join(packageRoot, "src/vite/ssr-templates", `${adapter}.ts`),
8308
- "utf-8"
8309
- );
8310
- const entryContent = templateContent.replace('"__TEMPLATE__"', JSON.stringify(html)).replace(
8311
- '"__BASE_PATH__"',
8312
- basePath ? JSON.stringify(basePath) : "undefined"
8313
- );
8314
- await writeFile5(tempEntryPath, entryContent, "utf-8");
8680
+ const userEntry = findUserEntry(dir);
8681
+ let entryPoint = userEntry;
8682
+ let tempEntryPath;
8683
+ if (!entryPoint) {
8684
+ tempEntryPath = path23.join(dir, "__ssr-entry.ts");
8685
+ const templateContent = await readFile4(
8686
+ path23.join(packageRoot, "src/vite/ssr-templates", `${adapter}.ts`),
8687
+ "utf-8"
8688
+ );
8689
+ await writeFile6(tempEntryPath, templateContent, "utf-8");
8690
+ entryPoint = tempEntryPath;
8691
+ }
8692
+ const frameworkPath = path23.join(serverOutDir, "entry.server.js");
8315
8693
  try {
8316
8694
  await esbuild({
8317
- entryPoints: [tempEntryPath],
8695
+ entryPoints: [entryPoint],
8318
8696
  bundle: true,
8319
- platform: adapter === "node" ? "node" : "neutral",
8697
+ platform: ["node", "lambda"].includes(adapter) ? "node" : "neutral",
8320
8698
  target: "es2022",
8321
8699
  format: "esm",
8322
- outfile: path21.join(serverOutDir, "entry.js"),
8323
- external: ["./entry.server.js", "./zudoku.config.js"],
8324
- nodePaths: [path21.join(packageRoot, "node_modules")],
8325
- banner: { js: "// Bundled SSR entry" }
8700
+ outfile: path23.join(serverOutDir, "entry.js"),
8701
+ external: ["./zudoku.config.js"],
8702
+ nodePaths: [path23.join(packageRoot, "node_modules")],
8703
+ banner: { js: "// Bundled SSR entry" },
8704
+ define: {
8705
+ __ZUDOKU_TEMPLATE__: JSON.stringify(html)
8706
+ },
8707
+ plugins: [
8708
+ {
8709
+ name: "zudoku-ssr-entry",
8710
+ setup(build2) {
8711
+ build2.onResolve({ filter: /^zudoku\/server$/ }, () => ({
8712
+ path: frameworkPath
8713
+ }));
8714
+ }
8715
+ }
8716
+ ]
8326
8717
  });
8718
+ await Promise.all([
8719
+ rm3(frameworkPath, { force: true }),
8720
+ rm3(`${frameworkPath}.map`, { force: true }),
8721
+ rm3(path23.join(serverOutDir, "assets"), {
8722
+ recursive: true,
8723
+ force: true
8724
+ })
8725
+ ]);
8327
8726
  } finally {
8328
- await rm2(tempEntryPath, { force: true });
8727
+ if (tempEntryPath) await rm3(tempEntryPath, { force: true });
8329
8728
  }
8330
8729
  };
8331
8730
 
@@ -8355,11 +8754,11 @@ function printWarningToConsole(message) {
8355
8754
  init_package_json();
8356
8755
 
8357
8756
  // src/cli/preview/handler.ts
8358
- import path22 from "node:path";
8757
+ import path24 from "node:path";
8359
8758
  import { preview as vitePreview } from "vite";
8360
8759
  var DEFAULT_PREVIEW_PORT = 4e3;
8361
8760
  async function preview(argv) {
8362
- const dir = path22.resolve(process.cwd(), argv.dir);
8761
+ const dir = path24.resolve(process.cwd(), argv.dir);
8363
8762
  const viteConfig = await getViteConfig(dir, {
8364
8763
  command: "serve",
8365
8764
  mode: "production",
@@ -8397,7 +8796,7 @@ async function build(argv) {
8397
8796
  printDiagnosticsToConsole(`Starting Zudoku build v${packageJson2.version}`);
8398
8797
  printDiagnosticsToConsole("");
8399
8798
  printDiagnosticsToConsole("");
8400
- const dir = path23.resolve(process.cwd(), argv.dir);
8799
+ const dir = path25.resolve(process.cwd(), argv.dir);
8401
8800
  try {
8402
8801
  await runBuild({
8403
8802
  dir,
@@ -8538,8 +8937,8 @@ var build_default = {
8538
8937
  default: false
8539
8938
  }).option("adapter", {
8540
8939
  type: "string",
8541
- describe: "SSR adapter (node, cloudflare, vercel)",
8542
- choices: ["node", "cloudflare", "vercel"],
8940
+ describe: "SSR adapter (node, cloudflare, vercel, lambda)",
8941
+ choices: ["node", "cloudflare", "vercel", "lambda"],
8543
8942
  default: "node"
8544
8943
  }),
8545
8944
  handler: async (argv) => {
@@ -8551,14 +8950,14 @@ var build_default = {
8551
8950
 
8552
8951
  // src/cli/dev/handler.ts
8553
8952
  init_joinUrl();
8554
- import path26 from "node:path";
8953
+ import path28 from "node:path";
8555
8954
 
8556
8955
  // src/vite/dev-server.ts
8557
8956
  init_logger();
8558
8957
  import fs3 from "node:fs/promises";
8559
8958
  import http from "node:http";
8560
8959
  import https from "node:https";
8561
- import path25 from "node:path";
8960
+ import path27 from "node:path";
8562
8961
  import { createHttpTerminator } from "http-terminator";
8563
8962
  import {
8564
8963
  createServer as createViteServer,
@@ -8587,11 +8986,12 @@ async function findAvailablePort(startPort) {
8587
8986
 
8588
8987
  // src/vite/dev-server.ts
8589
8988
  init_loader();
8989
+ init_joinUrl();
8590
8990
 
8591
8991
  // src/vite/pagefind-dev-index.ts
8592
8992
  init_invariant();
8593
8993
  init_joinUrl();
8594
- import path24 from "node:path";
8994
+ import path26 from "node:path";
8595
8995
  import { createIndex as createIndex2 } from "pagefind";
8596
8996
  import { isRunnableDevEnvironment } from "vite";
8597
8997
  async function* buildPagefindDevIndex(vite, config2) {
@@ -8644,7 +9044,7 @@ async function* buildPagefindDevIndex(vite, config2) {
8644
9044
  path: urlPath
8645
9045
  };
8646
9046
  }
8647
- const outputPath = path24.join(vite.config.publicDir, "pagefind");
9047
+ const outputPath = path26.join(vite.config.publicDir, "pagefind");
8648
9048
  await pagefindIndex.writeFiles({ outputPath });
8649
9049
  yield { type: "complete", success: true, indexed };
8650
9050
  }
@@ -8664,9 +9064,9 @@ var DevServer = class {
8664
9064
  this.protocol = "https";
8665
9065
  const { dir } = this.#options;
8666
9066
  const [key, cert, ca] = await Promise.all([
8667
- fs3.readFile(path25.resolve(dir, config2.https.key)),
8668
- fs3.readFile(path25.resolve(dir, config2.https.cert)),
8669
- config2.https.ca ? fs3.readFile(path25.resolve(dir, config2.https.ca)) : void 0
9067
+ fs3.readFile(path27.resolve(dir, config2.https.key)),
9068
+ fs3.readFile(path27.resolve(dir, config2.https.cert)),
9069
+ config2.https.ca ? fs3.readFile(path27.resolve(dir, config2.https.ca)) : void 0
8670
9070
  ]);
8671
9071
  return https.createServer({ key, cert, ca });
8672
9072
  }
@@ -8692,7 +9092,7 @@ var DevServer = class {
8692
9092
  // built-in transform middleware which would treat the path as a static asset.
8693
9093
  name: "zudoku:entry-client",
8694
9094
  configureServer(server2) {
8695
- const entryPath = path25.posix.join(
9095
+ const entryPath = path27.posix.join(
8696
9096
  server2.config.base,
8697
9097
  "/__z/entry.client.tsx"
8698
9098
  );
@@ -8723,6 +9123,46 @@ var DevServer = class {
8723
9123
  next();
8724
9124
  });
8725
9125
  vite.middlewares.use(graphql.graphqlEndpoint, graphql);
9126
+ const sessionEndpoint = joinUrl(config2.basePath, "/__z/auth/session");
9127
+ vite.middlewares.use(sessionEndpoint, async (req, res) => {
9128
+ if (req.method !== "POST" && req.method !== "DELETE") {
9129
+ res.writeHead(405, { Allow: "POST, DELETE" });
9130
+ res.end();
9131
+ return;
9132
+ }
9133
+ const ssrEnvironment = vite.environments.ssr;
9134
+ if (!isRunnableDevEnvironment2(ssrEnvironment)) {
9135
+ res.writeHead(500);
9136
+ res.end("SSR environment not available");
9137
+ return;
9138
+ }
9139
+ const entryServer = await ssrEnvironment.runner.import(
9140
+ getAppServerEntryPath()
9141
+ );
9142
+ const url = `${this.protocol}://${req.headers.host}${req.originalUrl ?? req.url}`;
9143
+ const body = req.method === "POST" ? await new Promise((resolve) => {
9144
+ let data = "";
9145
+ req.on("data", (chunk) => data += chunk);
9146
+ req.on("end", () => resolve(data));
9147
+ }) : void 0;
9148
+ const request = new Request(url, {
9149
+ method: req.method,
9150
+ headers: req.headers,
9151
+ body
9152
+ });
9153
+ const app = entryServer.createServer({ template: "" });
9154
+ const response = await app.fetch(request);
9155
+ for (const [name, value] of response.headers) {
9156
+ if (name.toLowerCase() === "set-cookie") continue;
9157
+ res.setHeader(name, value);
9158
+ }
9159
+ for (const cookie of response.headers.getSetCookie()) {
9160
+ res.appendHeader("Set-Cookie", cookie);
9161
+ }
9162
+ res.writeHead(response.status);
9163
+ const text = await response.text();
9164
+ res.end(text);
9165
+ });
8726
9166
  vite.middlewares.use("/__z/pagefind-reindex", async (_req, res) => {
8727
9167
  res.writeHead(200, {
8728
9168
  "Content-Type": "text/event-stream",
@@ -8765,13 +9205,13 @@ var DevServer = class {
8765
9205
  `Server-side rendering ${this.#options.ssr ? "enabled" : "disabled"}`
8766
9206
  );
8767
9207
  if (config2.search?.type === "pagefind") {
8768
- const pagefindPath = path25.join(
9208
+ const pagefindPath = path27.join(
8769
9209
  vite.config.publicDir,
8770
9210
  "pagefind/pagefind.js"
8771
9211
  );
8772
9212
  const exists = await fs3.stat(pagefindPath).catch(() => false);
8773
9213
  if (!exists) {
8774
- await fs3.mkdir(path25.dirname(pagefindPath), { recursive: true });
9214
+ await fs3.mkdir(path27.dirname(pagefindPath), { recursive: true });
8775
9215
  await fs3.writeFile(pagefindPath, 'throw new Error("NOT_BUILT_YET");');
8776
9216
  }
8777
9217
  }
@@ -8813,14 +9253,15 @@ var DevServer = class {
8813
9253
  duplex: hasBody ? "half" : void 0
8814
9254
  }
8815
9255
  );
8816
- const response = await entryServer.handleRequest({
8817
- template,
8818
- request,
8819
- routes: entryServer.getRoutesByConfig(currentConfig),
8820
- basePath: currentConfig.basePath
9256
+ const app = entryServer.createServer({ template });
9257
+ const response = await app.fetch(request);
9258
+ response.headers.forEach((value, key) => {
9259
+ if (key.toLowerCase() !== "set-cookie") {
9260
+ res.setHeader(key, value);
9261
+ }
8821
9262
  });
8822
- for (const [key, value] of response.headers) {
8823
- res.appendHeader(key, value);
9263
+ for (const cookie of response.headers.getSetCookie()) {
9264
+ res.appendHeader("Set-Cookie", cookie);
8824
9265
  }
8825
9266
  res.writeHead(response.status);
8826
9267
  for await (const chunk of response.body ?? []) {
@@ -8869,7 +9310,7 @@ init_package_json();
8869
9310
  async function dev(argv) {
8870
9311
  const packageJson2 = getZudokuPackageJson();
8871
9312
  process.env.NODE_ENV = "development";
8872
- const dir = path26.resolve(process.cwd(), argv.dir);
9313
+ const dir = path28.resolve(process.cwd(), argv.dir);
8873
9314
  const server = new DevServer({
8874
9315
  dir,
8875
9316
  argPort: argv.port,
@@ -8974,8 +9415,8 @@ var previewCommand = {
8974
9415
  var preview_default = previewCommand;
8975
9416
 
8976
9417
  // src/cli/common/outdated.ts
8977
- import { existsSync as existsSync2, mkdirSync } from "node:fs";
8978
- import { readFile as readFile4, writeFile as writeFile6 } from "node:fs/promises";
9418
+ import { existsSync as existsSync3, mkdirSync } from "node:fs";
9419
+ import { readFile as readFile5, writeFile as writeFile7 } from "node:fs/promises";
8979
9420
  import { join } from "node:path";
8980
9421
  import colors10 from "picocolors";
8981
9422
  import { gt } from "semver";
@@ -9025,12 +9466,12 @@ function box(message, {
9025
9466
 
9026
9467
  // src/cli/common/xdg/lib.ts
9027
9468
  import { homedir } from "node:os";
9028
- import path27 from "node:path";
9469
+ import path29 from "node:path";
9029
9470
  function defineDirectoryWithFallback(xdgName, fallback) {
9030
9471
  if (process.env[xdgName]) {
9031
9472
  return process.env[xdgName];
9032
9473
  } else {
9033
- return path27.join(homedir(), fallback);
9474
+ return path29.join(homedir(), fallback);
9034
9475
  }
9035
9476
  }
9036
9477
  var XDG_CONFIG_HOME = defineDirectoryWithFallback(
@@ -9045,15 +9486,15 @@ var XDG_STATE_HOME = defineDirectoryWithFallback(
9045
9486
  "XDG_DATA_HOME",
9046
9487
  ".local/state"
9047
9488
  );
9048
- var ZUDOKU_XDG_CONFIG_HOME = path27.join(
9489
+ var ZUDOKU_XDG_CONFIG_HOME = path29.join(
9049
9490
  XDG_CONFIG_HOME,
9050
9491
  CLI_XDG_FOLDER_NAME
9051
9492
  );
9052
- var ZUDOKU_XDG_DATA_HOME = path27.join(
9493
+ var ZUDOKU_XDG_DATA_HOME = path29.join(
9053
9494
  XDG_DATA_HOME,
9054
9495
  CLI_XDG_FOLDER_NAME
9055
9496
  );
9056
- var ZUDOKU_XDG_STATE_HOME = path27.join(
9497
+ var ZUDOKU_XDG_STATE_HOME = path29.join(
9057
9498
  XDG_STATE_HOME,
9058
9499
  CLI_XDG_FOLDER_NAME
9059
9500
  );
@@ -9095,14 +9536,14 @@ async function getLatestVersion() {
9095
9536
  return void 0;
9096
9537
  }
9097
9538
  async function getVersionCheckInfo() {
9098
- if (!existsSync2(ZUDOKU_XDG_STATE_HOME)) {
9539
+ if (!existsSync3(ZUDOKU_XDG_STATE_HOME)) {
9099
9540
  mkdirSync(ZUDOKU_XDG_STATE_HOME, { recursive: true });
9100
9541
  }
9101
9542
  const versionCheckPath = join(ZUDOKU_XDG_STATE_HOME, VERSION_CHECK_FILE);
9102
9543
  let versionCheckInfo;
9103
- if (existsSync2(versionCheckPath)) {
9544
+ if (existsSync3(versionCheckPath)) {
9104
9545
  try {
9105
- versionCheckInfo = await readFile4(versionCheckPath, "utf-8").then(
9546
+ versionCheckInfo = await readFile5(versionCheckPath, "utf-8").then(
9106
9547
  JSON.parse
9107
9548
  );
9108
9549
  } catch {
@@ -9127,7 +9568,7 @@ async function getVersionCheckInfo() {
9127
9568
  lastCheck: Date.now(),
9128
9569
  latestVersion
9129
9570
  };
9130
- await writeFile6(
9571
+ await writeFile7(
9131
9572
  versionCheckPath,
9132
9573
  JSON.stringify(versionCheckInfo),
9133
9574
  "utf-8"