@hkonda/loco-translate 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +284 -0
  2. package/bin/loco.js +5 -0
  3. package/dist/assets/index-CGo6e-bA.js +59 -0
  4. package/dist/assets/index-DBcQDZ75.css +1 -0
  5. package/dist/index.html +13 -0
  6. package/dist-server/app.d.ts +3 -0
  7. package/dist-server/app.d.ts.map +1 -0
  8. package/dist-server/app.js +154 -0
  9. package/dist-server/app.js.map +1 -0
  10. package/dist-server/config.d.ts +16 -0
  11. package/dist-server/config.d.ts.map +1 -0
  12. package/dist-server/config.js +41 -0
  13. package/dist-server/config.js.map +1 -0
  14. package/dist-server/db/index.d.ts +8 -0
  15. package/dist-server/db/index.d.ts.map +1 -0
  16. package/dist-server/db/index.js +28 -0
  17. package/dist-server/db/index.js.map +1 -0
  18. package/dist-server/db/schema.d.ts +851 -0
  19. package/dist-server/db/schema.d.ts.map +1 -0
  20. package/dist-server/db/schema.js +65 -0
  21. package/dist-server/db/schema.js.map +1 -0
  22. package/dist-server/db/seed.d.ts +14 -0
  23. package/dist-server/db/seed.d.ts.map +1 -0
  24. package/dist-server/db/seed.js +229 -0
  25. package/dist-server/db/seed.js.map +1 -0
  26. package/dist-server/index.d.ts +2 -0
  27. package/dist-server/index.d.ts.map +1 -0
  28. package/dist-server/index.js +31 -0
  29. package/dist-server/index.js.map +1 -0
  30. package/dist-server/routes/ai-jobs.d.ts +5 -0
  31. package/dist-server/routes/ai-jobs.d.ts.map +1 -0
  32. package/dist-server/routes/ai-jobs.js +141 -0
  33. package/dist-server/routes/ai-jobs.js.map +1 -0
  34. package/dist-server/routes/backup.d.ts +5 -0
  35. package/dist-server/routes/backup.d.ts.map +1 -0
  36. package/dist-server/routes/backup.js +125 -0
  37. package/dist-server/routes/backup.js.map +1 -0
  38. package/dist-server/routes/chrome-extension.d.ts +5 -0
  39. package/dist-server/routes/chrome-extension.d.ts.map +1 -0
  40. package/dist-server/routes/chrome-extension.js +140 -0
  41. package/dist-server/routes/chrome-extension.js.map +1 -0
  42. package/dist-server/routes/export.d.ts +5 -0
  43. package/dist-server/routes/export.d.ts.map +1 -0
  44. package/dist-server/routes/export.js +95 -0
  45. package/dist-server/routes/export.js.map +1 -0
  46. package/dist-server/routes/languages.d.ts +5 -0
  47. package/dist-server/routes/languages.d.ts.map +1 -0
  48. package/dist-server/routes/languages.js +36 -0
  49. package/dist-server/routes/languages.js.map +1 -0
  50. package/dist-server/routes/project.d.ts +5 -0
  51. package/dist-server/routes/project.d.ts.map +1 -0
  52. package/dist-server/routes/project.js +151 -0
  53. package/dist-server/routes/project.js.map +1 -0
  54. package/dist-server/routes/prompts.d.ts +5 -0
  55. package/dist-server/routes/prompts.d.ts.map +1 -0
  56. package/dist-server/routes/prompts.js +90 -0
  57. package/dist-server/routes/prompts.js.map +1 -0
  58. package/dist-server/routes/screenshots.d.ts +5 -0
  59. package/dist-server/routes/screenshots.d.ts.map +1 -0
  60. package/dist-server/routes/screenshots.js +71 -0
  61. package/dist-server/routes/screenshots.js.map +1 -0
  62. package/dist-server/routes/textnodes.d.ts +5 -0
  63. package/dist-server/routes/textnodes.d.ts.map +1 -0
  64. package/dist-server/routes/textnodes.js +318 -0
  65. package/dist-server/routes/textnodes.js.map +1 -0
  66. package/dist-server/routes/translations.d.ts +5 -0
  67. package/dist-server/routes/translations.d.ts.map +1 -0
  68. package/dist-server/routes/translations.js +224 -0
  69. package/dist-server/routes/translations.js.map +1 -0
  70. package/dist-server/scripts/backup.d.ts +2 -0
  71. package/dist-server/scripts/backup.d.ts.map +1 -0
  72. package/dist-server/scripts/backup.js +26 -0
  73. package/dist-server/scripts/backup.js.map +1 -0
  74. package/dist-server/services/ai-translation.d.ts +21 -0
  75. package/dist-server/services/ai-translation.d.ts.map +1 -0
  76. package/dist-server/services/ai-translation.js +137 -0
  77. package/dist-server/services/ai-translation.js.map +1 -0
  78. package/dist-server/services/job-manager.d.ts +67 -0
  79. package/dist-server/services/job-manager.d.ts.map +1 -0
  80. package/dist-server/services/job-manager.js +159 -0
  81. package/dist-server/services/job-manager.js.map +1 -0
  82. package/dist-server/services/slot-pattern.d.ts +16 -0
  83. package/dist-server/services/slot-pattern.d.ts.map +1 -0
  84. package/dist-server/services/slot-pattern.js +68 -0
  85. package/dist-server/services/slot-pattern.js.map +1 -0
  86. package/dist-server/utils/network.d.ts +2 -0
  87. package/dist-server/utils/network.d.ts.map +1 -0
  88. package/dist-server/utils/network.js +16 -0
  89. package/dist-server/utils/network.js.map +1 -0
  90. package/package.json +47 -0
  91. package/public/loco.js +2386 -0
  92. package/public/loco.min.js +4 -0
@@ -0,0 +1 @@
1
+ /*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-amber-50:oklch(98.7% .022 95.277);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-600:oklch(68.1% .162 75.834);--color-yellow-700:oklch(55.4% .135 66.442);--color-green-50:oklch(98.2% .018 155.826);--color-green-300:oklch(87.1% .15 154.449);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-800:oklch(42.4% .199 265.638);--color-indigo-50:oklch(96.2% .018 272.314);--color-indigo-100:oklch(93% .034 272.788);--color-indigo-200:oklch(87% .065 274.039);--color-indigo-300:oklch(78.5% .115 274.713);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-600:oklch(51.1% .262 276.966);--color-indigo-700:oklch(45.7% .24 277.023);--color-indigo-800:oklch(39.8% .195 277.366);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xl:36rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-1\/2{top:50%}.top-2\.5{top:calc(var(--spacing) * 2.5)}.right-0{right:calc(var(--spacing) * 0)}.right-2{right:calc(var(--spacing) * 2)}.left-2\.5{left:calc(var(--spacing) * 2.5)}.z-40{z-index:40}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.my-4{margin-block:calc(var(--spacing) * 4)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.-mb-px{margin-bottom:-1px}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-4{margin-left:calc(var(--spacing) * 4)}.block{display:block}.contents{display:contents}.flex{display:flex}.flow-root{display:flow-root}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.inline-grid{display:inline-grid}.inline-table{display:inline-table}.list-item{display:list-item}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.table-column{display:table-column}.table-column-group{display:table-column-group}.table-footer-group{display:table-footer-group}.table-header-group{display:table-header-group}.table-row{display:table-row}.table-row-group{display:table-row-group}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-\[160px\]{height:160px}.h-full{height:100%}.max-h-24{max-height:calc(var(--spacing) * 24)}.max-h-64{max-height:calc(var(--spacing) * 64)}.min-h-screen{min-height:100vh}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-7{width:calc(var(--spacing) * 7)}.w-10{width:calc(var(--spacing) * 10)}.w-11{width:calc(var(--spacing) * 11)}.w-14{width:calc(var(--spacing) * 14)}.w-56{width:calc(var(--spacing) * 56)}.w-\[280px\]{width:280px}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-\[180px\]{max-width:180px}.max-w-\[250px\]{max-width:250px}.max-w-\[280px\]{max-width:280px}.max-w-xl{max-width:var(--container-xl)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[90px\]{min-width:90px}.min-w-\[220px\]{min-width:220px}.flex-1{flex:1}.flex-\[2\]{flex:2}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.translate-x-1{--tw-translate-x:calc(var(--spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-6{--tw-translate-x:calc(var(--spacing) * 6);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-y{resize:vertical}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0{gap:calc(var(--spacing) * 0)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-md{border-top-left-radius:var(--radius-md);border-top-right-radius:var(--radius-md)}.rounded-l-md{border-top-left-radius:var(--radius-md);border-bottom-left-radius:var(--radius-md)}.rounded-r-md{border-top-right-radius:var(--radius-md);border-bottom-right-radius:var(--radius-md)}.rounded-b-md{border-bottom-right-radius:var(--radius-md);border-bottom-left-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r-0{border-right-style:var(--tw-border-style);border-right-width:0}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l-0{border-left-style:var(--tw-border-style);border-left-width:0}.border-blue-200{border-color:var(--color-blue-200)}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-700{border-color:var(--color-gray-700)}.border-green-300{border-color:var(--color-green-300)}.border-indigo-200{border-color:var(--color-indigo-200)}.border-indigo-300{border-color:var(--color-indigo-300)}.border-indigo-600{border-color:var(--color-indigo-600)}.border-red-100{border-color:var(--color-red-100)}.border-red-200{border-color:var(--color-red-200)}.border-red-300{border-color:var(--color-red-300)}.border-transparent{border-color:#0000}.bg-amber-50{background-color:var(--color-amber-50)}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab,red,red)){.bg-black\/40{background-color:color-mix(in oklab,var(--color-black) 40%,transparent)}}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-blue-500{background-color:var(--color-blue-500)}.bg-blue-600{background-color:var(--color-blue-600)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-300{background-color:var(--color-gray-300)}.bg-gray-900{background-color:var(--color-gray-900)}.bg-green-50{background-color:var(--color-green-50)}.bg-green-600{background-color:var(--color-green-600)}.bg-indigo-50{background-color:var(--color-indigo-50)}.bg-indigo-100{background-color:var(--color-indigo-100)}.bg-indigo-600{background-color:var(--color-indigo-600)}.bg-red-600{background-color:var(--color-red-600)}.bg-red-700{background-color:var(--color-red-700)}.bg-white{background-color:var(--color-white)}.bg-yellow-600{background-color:var(--color-yellow-600)}.bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-blue-500{--tw-gradient-from:var(--color-blue-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-yellow-500{--tw-gradient-to:var(--color-yellow-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-10{padding-inline:calc(var(--spacing) * 10)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-10{padding-right:calc(var(--spacing) * 10)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-8{padding-left:calc(var(--spacing) * 8)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-blue-600{color:var(--color-blue-600)}.text-blue-700{color:var(--color-blue-700)}.text-blue-800{color:var(--color-blue-800)}.text-gray-300{color:var(--color-gray-300)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-green-600{color:var(--color-green-600)}.text-green-700{color:var(--color-green-700)}.text-indigo-600{color:var(--color-indigo-600)}.text-indigo-700{color:var(--color-indigo-700)}.text-red-600{color:var(--color-red-600)}.text-white{color:var(--color-white)}.text-yellow-600{color:var(--color-yellow-600)}.text-yellow-700{color:var(--color-yellow-700)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.line-through{text-decoration-line:line-through}.overline{text-decoration-line:overline}.underline{text-decoration-line:underline}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.select-all{-webkit-user-select:all;user-select:all}@media (hover:hover){.hover\:border-gray-300:hover{border-color:var(--color-gray-300)}.hover\:border-indigo-200:hover{border-color:var(--color-indigo-200)}.hover\:border-red-300:hover{border-color:var(--color-red-300)}.hover\:bg-blue-700:hover{background-color:var(--color-blue-700)}.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-100:hover{background-color:var(--color-gray-100)}.hover\:bg-gray-800:hover{background-color:var(--color-gray-800)}.hover\:bg-green-700:hover{background-color:var(--color-green-700)}.hover\:bg-indigo-700:hover{background-color:var(--color-indigo-700)}.hover\:bg-red-50:hover{background-color:var(--color-red-50)}.hover\:bg-red-700:hover{background-color:var(--color-red-700)}.hover\:bg-red-800:hover{background-color:var(--color-red-800)}.hover\:bg-yellow-700:hover{background-color:var(--color-yellow-700)}.hover\:text-gray-600:hover{color:var(--color-gray-600)}.hover\:text-gray-700:hover{color:var(--color-gray-700)}.hover\:text-indigo-500:hover{color:var(--color-indigo-500)}.hover\:text-indigo-800:hover{color:var(--color-indigo-800)}.hover\:text-red-500:hover{color:var(--color-red-500)}.hover\:text-white:hover{color:var(--color-white)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}}.focus\:border-indigo-500:focus{border-color:var(--color-indigo-500)}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-indigo-300:focus{--tw-ring-color:var(--color-indigo-300)}.focus\:ring-indigo-500:focus{--tw-ring-color:var(--color-indigo-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}.pve.svelte-19itaxc.svelte-19itaxc{display:flex;flex-direction:column;gap:14px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.pve-header.svelte-19itaxc.svelte-19itaxc{display:flex;align-items:center;gap:8px}.pve-title.svelte-19itaxc.svelte-19itaxc{font-size:14px;font-weight:600;color:#111827}.pve-badge.svelte-19itaxc.svelte-19itaxc{padding:2px 8px;background:#e0e7ff;color:#4338ca;border-radius:999px;font-size:11px;font-weight:700;letter-spacing:.02em}.pve-canvas.svelte-19itaxc.svelte-19itaxc{padding:10px 12px;border:1px solid #d1d5db;border-radius:8px;background:#fff;min-height:48px;line-height:2.1;word-break:break-all;cursor:text;-webkit-user-select:text;user-select:text}.pve-text-seg.svelte-19itaxc.svelte-19itaxc{white-space:pre-wrap;color:#374151;font-family:Menlo,Courier New,monospace;font-size:13px;border-radius:2px}.pve-text-seg--active.svelte-19itaxc.svelte-19itaxc{background:#fef9c3}.pve-chip.svelte-19itaxc.svelte-19itaxc{display:inline-flex;align-items:center;gap:3px;padding:2px 5px 2px 8px;margin:0 2px;border:1.5px solid;border-radius:999px;font-family:Menlo,Courier New,monospace;font-size:12px;vertical-align:middle;line-height:1.5}.pve-chip--text.svelte-19itaxc.svelte-19itaxc{border-color:#3b82f6;background:#eff6ff;color:#1d4ed8}.pve-chip--number.svelte-19itaxc.svelte-19itaxc{border-color:#10b981;background:#ecfdf5;color:#065f46}.pve-chip--decimal.svelte-19itaxc.svelte-19itaxc{border-color:#06b6d4;background:#ecfeff;color:#155e75}.pve-chip--date.svelte-19itaxc.svelte-19itaxc{border-color:#f59e0b;background:#fffbeb;color:#b45309}.pve-chip-label.svelte-19itaxc.svelte-19itaxc{font-weight:600}.pve-chip-remove.svelte-19itaxc.svelte-19itaxc{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:none;font-size:15px;cursor:pointer;border-radius:50%;line-height:1;transition:background .12s,color .12s}.pve-chip--text.svelte-19itaxc .pve-chip-remove.svelte-19itaxc{color:#60a5fa}.pve-chip--text.svelte-19itaxc .pve-chip-remove.svelte-19itaxc:hover{background:#bfdbfe;color:#1e3a8a}.pve-chip--number.svelte-19itaxc .pve-chip-remove.svelte-19itaxc{color:#34d399}.pve-chip--number.svelte-19itaxc .pve-chip-remove.svelte-19itaxc:hover{background:#a7f3d0;color:#064e3b}.pve-chip--decimal.svelte-19itaxc .pve-chip-remove.svelte-19itaxc{color:#22d3ee}.pve-chip--decimal.svelte-19itaxc .pve-chip-remove.svelte-19itaxc:hover{background:#a5f3fc;color:#164e63}.pve-chip--date.svelte-19itaxc .pve-chip-remove.svelte-19itaxc{color:#fbbf24}.pve-chip--date.svelte-19itaxc .pve-chip-remove.svelte-19itaxc:hover{background:#fde68a;color:#78350f}.pve-action-bar.svelte-19itaxc.svelte-19itaxc{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 12px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;flex-wrap:wrap}.pve-sel-preview.svelte-19itaxc.svelte-19itaxc{font-size:13px;color:#374151;min-width:0;flex:1}.pve-sel-code.svelte-19itaxc.svelte-19itaxc{background:#d1fae5;color:#065f46;padding:1px 5px;border-radius:4px;font-family:Menlo,Courier New,monospace;font-size:12px;max-width:220px;display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pve-action-bar-btns.svelte-19itaxc.svelte-19itaxc{display:flex;gap:8px;flex-shrink:0}.pve-preview.svelte-19itaxc.svelte-19itaxc{display:flex;flex-direction:column;gap:4px}.pve-preview-label.svelte-19itaxc.svelte-19itaxc{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#9ca3af}.pve-preview-code.svelte-19itaxc.svelte-19itaxc{display:block;padding:8px 10px;background:#f3f4f6;border-radius:6px;font-family:Menlo,Courier New,monospace;font-size:12px;color:#374151;word-break:break-all;white-space:pre-wrap}.pve-footer.svelte-19itaxc.svelte-19itaxc{display:flex;justify-content:flex-end}.pve-btn.svelte-19itaxc.svelte-19itaxc{padding:7px 16px;border-radius:6px;font-size:13px;font-weight:500;cursor:pointer;border:1px solid transparent;transition:background .12s}.pve-btn-primary.svelte-19itaxc.svelte-19itaxc{background:#4f46e5;color:#fff;border-color:#4f46e5}.pve-btn-primary.svelte-19itaxc.svelte-19itaxc:hover{background:#4338ca;border-color:#4338ca}.pve-btn-text.svelte-19itaxc.svelte-19itaxc{background:#3b82f6;color:#fff;border-color:#3b82f6}.pve-btn-text.svelte-19itaxc.svelte-19itaxc:hover{background:#2563eb;border-color:#2563eb}.pve-btn-number.svelte-19itaxc.svelte-19itaxc{background:#10b981;color:#fff;border-color:#10b981}.pve-btn-number.svelte-19itaxc.svelte-19itaxc:hover{background:#059669;border-color:#059669}.pve-btn-decimal.svelte-19itaxc.svelte-19itaxc{background:#06b6d4;color:#fff;border-color:#06b6d4}.pve-btn-decimal.svelte-19itaxc.svelte-19itaxc:hover{background:#0891b2;border-color:#0891b2}.pve-btn-date.svelte-19itaxc.svelte-19itaxc{background:#f59e0b;color:#fff;border-color:#f59e0b}.pve-btn-date.svelte-19itaxc.svelte-19itaxc:hover{background:#d97706;border-color:#d97706}.pve-btn-ghost.svelte-19itaxc.svelte-19itaxc{background:transparent;color:#6b7280;border-color:#d1d5db}.pve-btn-ghost.svelte-19itaxc.svelte-19itaxc:hover{background:#f9fafb}
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Loco — Translation Manager</title>
7
+ <script type="module" crossorigin src="/loco/dashboard/assets/index-CGo6e-bA.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/loco/dashboard/assets/index-DBcQDZ75.css">
9
+ </head>
10
+ <body>
11
+ <div id="app"></div>
12
+ </body>
13
+ </html>
@@ -0,0 +1,3 @@
1
+ import Fastify from 'fastify';
2
+ export declare function buildApp(project: any): Promise<Fastify.FastifyInstance<import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>, import("node:http").IncomingMessage, import("node:http").ServerResponse<import("node:http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>>;
3
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../server/app.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAqB9B,wBAAsB,QAAQ,CAAC,OAAO,EAAE,GAAG,oUA0I1C"}
@@ -0,0 +1,154 @@
1
+ import Fastify from 'fastify';
2
+ import cors from '@fastify/cors';
3
+ import fastifyStatic from '@fastify/static';
4
+ import fastifySwagger from '@fastify/swagger';
5
+ import fastifySwaggerUi from '@fastify/swagger-ui';
6
+ import { join } from 'path';
7
+ import { existsSync } from 'fs';
8
+ import { PROJECT_ROOT, BASE_PATH } from './config.js';
9
+ // Route plugins
10
+ import projectRoutes from './routes/project.js';
11
+ import textnodesRoutes from './routes/textnodes.js';
12
+ import translationsRoutes from './routes/translations.js';
13
+ import languagesRoutes from './routes/languages.js';
14
+ import screenshotsRoutes from './routes/screenshots.js';
15
+ import exportRoutes from './routes/export.js';
16
+ import promptsRoutes from './routes/prompts.js';
17
+ import aiJobsRoutes from './routes/ai-jobs.js';
18
+ import chromeExtensionRoutes from './routes/chrome-extension.js';
19
+ import backupRoutes from './routes/backup.js';
20
+ export async function buildApp(project) {
21
+ const app = Fastify({
22
+ logger: false,
23
+ // Strip BASE_PATH prefix so Vite-built assets and relative API calls work
24
+ // behind a reverse proxy (e.g. /loco/api/... → /api/...).
25
+ rewriteUrl: BASE_PATH
26
+ ? (req) => {
27
+ const url = req.url || '';
28
+ if (url.startsWith(BASE_PATH + '/'))
29
+ return url.slice(BASE_PATH.length);
30
+ return url;
31
+ }
32
+ : undefined,
33
+ });
34
+ // ── CORS
35
+ await app.register(cors, { origin: '*' });
36
+ // ── Swagger / OpenAPI
37
+ await app.register(fastifySwagger, {
38
+ openapi: {
39
+ openapi: '3.0.3',
40
+ info: {
41
+ title: 'Loco Translation API',
42
+ description: 'API for the Loco translation management system',
43
+ version: '1.0.0',
44
+ },
45
+ components: {
46
+ securitySchemes: {
47
+ ApiKeyAuth: {
48
+ type: 'apiKey',
49
+ in: 'header',
50
+ name: 'X-API-Key',
51
+ },
52
+ },
53
+ },
54
+ security: [{ ApiKeyAuth: [] }],
55
+ tags: [
56
+ { name: 'Project', description: 'Project management and health check' },
57
+ { name: 'Text Nodes', description: 'Text node registration and management' },
58
+ { name: 'Translations', description: 'Translation CRUD and CDN fetch' },
59
+ { name: 'Languages', description: 'Available language listing' },
60
+ { name: 'Screenshots', description: 'Page screenshot storage' },
61
+ { name: 'Export', description: 'Translation export' },
62
+ { name: 'Prompts', description: 'AI prompt template management' },
63
+ { name: 'AI Jobs', description: 'Bulk AI translation jobs' },
64
+ { name: 'Chrome Extension', description: 'Chrome extension sidepanel API' },
65
+ { name: 'Backup', description: 'Database backup' },
66
+ ],
67
+ },
68
+ });
69
+ await app.register(fastifySwaggerUi, {
70
+ routePrefix: '/api/docs',
71
+ ...(BASE_PATH ? { indexPrefix: BASE_PATH } : {}),
72
+ uiConfig: {
73
+ docExpansion: 'list',
74
+ deepLinking: true,
75
+ },
76
+ });
77
+ // ── Register route plugins
78
+ // routeOpts is shared across all route plugins and the auth hook.
79
+ // When project.ts regenerates the API key, it updates routeOpts.project,
80
+ // so the auth hook always reads the latest api_key.
81
+ const routeOpts = { project };
82
+ // ── API key auth for all /api/* routes
83
+ app.addHook('onRequest', (req, reply, done) => {
84
+ if (!req.url.startsWith('/api') && !req.url.startsWith('/api/'))
85
+ return done();
86
+ // Allow unauthenticated access to health check, project bootstrap, and Swagger docs
87
+ if (req.url === '/api' || req.url === '/api/' || req.url === '/api/project')
88
+ return done();
89
+ if (req.url.startsWith('/api/docs'))
90
+ return done();
91
+ const key = req.headers['x-api-key'];
92
+ if (!key || key !== routeOpts.project.api_key) {
93
+ reply.code(401).send({ error: 'Unauthorized — missing or invalid X-API-Key header' });
94
+ return;
95
+ }
96
+ done();
97
+ });
98
+ await app.register(projectRoutes, routeOpts);
99
+ await app.register(textnodesRoutes, routeOpts);
100
+ await app.register(translationsRoutes, routeOpts);
101
+ await app.register(languagesRoutes, routeOpts);
102
+ await app.register(screenshotsRoutes, routeOpts);
103
+ await app.register(exportRoutes, routeOpts);
104
+ await app.register(promptsRoutes, routeOpts);
105
+ await app.register(aiJobsRoutes, routeOpts);
106
+ await app.register(chromeExtensionRoutes, routeOpts);
107
+ await app.register(backupRoutes, routeOpts);
108
+ // ── Static: CDN (public/)
109
+ const publicDir = join(PROJECT_ROOT, 'public');
110
+ await app.register(fastifyStatic, {
111
+ root: publicDir,
112
+ prefix: '/cdn/',
113
+ decorateReply: false,
114
+ setHeaders: (res, path) => {
115
+ res.setHeader('Access-Control-Allow-Origin', '*');
116
+ res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');
117
+ if (path.endsWith('.js')) {
118
+ res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
119
+ }
120
+ else if (path.endsWith('.json')) {
121
+ res.setHeader('Content-Type', 'application/json; charset=utf-8');
122
+ }
123
+ },
124
+ });
125
+ // ── Static: Test pages (test-pages/ → /test-pages/)
126
+ const testPagesDir = join(PROJECT_ROOT, 'test-pages');
127
+ if (existsSync(testPagesDir)) {
128
+ await app.register(async function testPagesPlugin(scope) {
129
+ scope.register(fastifyStatic, {
130
+ root: testPagesDir,
131
+ prefix: '/test-pages/',
132
+ decorateReply: false,
133
+ });
134
+ });
135
+ }
136
+ // ── Static: Dashboard (dist/) — production only
137
+ const distDir = join(PROJECT_ROOT, 'dist');
138
+ if (existsSync(distDir)) {
139
+ await app.register(fastifyStatic, {
140
+ root: distDir,
141
+ prefix: '/dashboard/',
142
+ decorateReply: false,
143
+ wildcard: true,
144
+ });
145
+ app.setNotFoundHandler((req, reply) => {
146
+ if (req.url.startsWith('/dashboard')) {
147
+ return reply.sendFile('index.html', distDir);
148
+ }
149
+ reply.code(404).send({ error: 'Not found' });
150
+ });
151
+ }
152
+ return app;
153
+ }
154
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../server/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export declare const PROJECT_ROOT: string;
2
+ export declare const PORT: number;
3
+ export declare const BASE_PATH: string;
4
+ export declare const DATA_DIR: string;
5
+ export declare const AI_CONFIG: {
6
+ readonly HOSTNAME: "ai.bluehive.com";
7
+ readonly PORT: 443;
8
+ readonly PATH: "/api/v1/completion";
9
+ };
10
+ export declare const LIMITS: {
11
+ readonly MAX_URL_LENGTH: 2048;
12
+ readonly MAX_SCREENSHOT_SIZE: 500000;
13
+ readonly MAX_JOB_HISTORY: 50;
14
+ readonly API_KEY_LENGTH: 24;
15
+ };
16
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../server/config.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,YAAY,QAAwB,CAAC;AAalD,eAAO,MAAM,IAAI,QAA2C,CAAC;AAC7D,eAAO,MAAM,SAAS,QAA8B,CAAC;AAUrD,eAAO,MAAM,QAAQ,QAA+C,CAAC;AAErE,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AAEX,eAAO,MAAM,MAAM;;;;;CAKT,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { join, dirname } from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import { existsSync, readFileSync } from 'fs';
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+ // Project root is one level up from server/ (or dist-server/ when compiled).
7
+ // When installed as an npm package this resolves to the package root inside node_modules.
8
+ export const PROJECT_ROOT = join(__dirname, '..');
9
+ // Load .env file (from user's cwd, not package root)
10
+ const envPath = join(process.cwd(), '.env');
11
+ if (existsSync(envPath)) {
12
+ for (const line of readFileSync(envPath, 'utf8').split('\n')) {
13
+ const match = line.match(/^([^#=]+)=(.*)$/);
14
+ if (match && !process.env[match[1].trim()]) {
15
+ process.env[match[1].trim()] = match[2].trim();
16
+ }
17
+ }
18
+ }
19
+ export const PORT = parseInt(process.env.PORT || '6101', 10);
20
+ export const BASE_PATH = process.env.BASE_PATH || ''; // e.g. '/loco' for reverse-proxy deployments
21
+ // Data directory for the SQLite database and backups.
22
+ // When running from source (dev), use server/data/ inside the repo.
23
+ // When installed as an npm package, default to .loco/ in the user's cwd.
24
+ // Always overridable via LOCO_DATA_DIR env var.
25
+ const _isDevSource = existsSync(join(PROJECT_ROOT, 'server', 'index.ts'));
26
+ const _defaultDataDir = _isDevSource
27
+ ? join(PROJECT_ROOT, 'server', 'data')
28
+ : join(process.cwd(), '.loco');
29
+ export const DATA_DIR = process.env.LOCO_DATA_DIR || _defaultDataDir;
30
+ export const AI_CONFIG = {
31
+ HOSTNAME: 'ai.bluehive.com',
32
+ PORT: 443,
33
+ PATH: '/api/v1/completion',
34
+ };
35
+ export const LIMITS = {
36
+ MAX_URL_LENGTH: 2048,
37
+ MAX_SCREENSHOT_SIZE: 500000,
38
+ MAX_JOB_HISTORY: 50,
39
+ API_KEY_LENGTH: 24,
40
+ };
41
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAE9C,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,6EAA6E;AAC7E,0FAA0F;AAC1F,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAElD,qDAAqD;AACrD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;AAC5C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACxB,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC5C,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjD,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;AAC7D,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,6CAA6C;AAEnG,sDAAsD;AACtD,oEAAoE;AACpE,yEAAyE;AACzE,gDAAgD;AAChD,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;AAC1E,MAAM,eAAe,GAAG,YAAY;IAClC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,MAAM,CAAC;IACtC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,eAAe,CAAC;AAErE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,QAAQ,EAAE,iBAAiB;IAC3B,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,oBAAoB;CAClB,CAAC;AAEX,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,cAAc,EAAE,IAAI;IACpB,mBAAmB,EAAE,MAAM;IAC3B,eAAe,EAAE,EAAE;IACnB,cAAc,EAAE,EAAE;CACV,CAAC"}
@@ -0,0 +1,8 @@
1
+ import Database, { type Database as DatabaseType } from 'better-sqlite3';
2
+ import * as schema from './schema.js';
3
+ export declare const db: import("drizzle-orm/better-sqlite3").BetterSQLite3Database<typeof schema> & {
4
+ $client: Database.Database;
5
+ };
6
+ export declare const rawDb: DatabaseType;
7
+ export { schema };
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../server/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,EAAE,EAAE,KAAK,QAAQ,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAIzE,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAuBtC,eAAO,MAAM,EAAE;;CAA8B,CAAC;AAC9C,eAAO,MAAM,KAAK,EAAE,YAAqB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -0,0 +1,28 @@
1
+ import Database from 'better-sqlite3';
2
+ import { drizzle } from 'drizzle-orm/better-sqlite3';
3
+ import { join } from 'path';
4
+ import { existsSync, copyFileSync, mkdirSync } from 'fs';
5
+ import * as schema from './schema.js';
6
+ import { DATA_DIR } from '../config.js';
7
+ const dataDir = DATA_DIR;
8
+ const dbPath = join(dataDir, 'loco.db');
9
+ // Ensure data directory exists
10
+ mkdirSync(dataDir, { recursive: true });
11
+ // Auto-migrate: if loco.db exists in cwd (old location) but not yet in the new data dir
12
+ const oldDbPath = join(process.cwd(), 'loco.db');
13
+ if (!existsSync(dbPath) && existsSync(oldDbPath)) {
14
+ console.log(`[db] Migrating database from ${oldDbPath} to ${dbPath}`);
15
+ copyFileSync(oldDbPath, dbPath);
16
+ // Also copy WAL and SHM files if they exist
17
+ if (existsSync(oldDbPath + '-wal'))
18
+ copyFileSync(oldDbPath + '-wal', dbPath + '-wal');
19
+ if (existsSync(oldDbPath + '-shm'))
20
+ copyFileSync(oldDbPath + '-shm', dbPath + '-shm');
21
+ console.log(`[db] Migration complete. You can safely delete the old ${oldDbPath}`);
22
+ }
23
+ const sqlite = new Database(dbPath);
24
+ sqlite.pragma('journal_mode = WAL');
25
+ export const db = drizzle(sqlite, { schema });
26
+ export const rawDb = sqlite;
27
+ export { schema };
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAA2C,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,OAAO,GAAG,QAAQ,CAAC;AACzB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAExC,+BAA+B;AAC/B,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAExC,wFAAwF;AACxF,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;AACjD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,gCAAgC,SAAS,OAAO,MAAM,EAAE,CAAC,CAAC;IACtE,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChC,4CAA4C;IAC5C,IAAI,UAAU,CAAC,SAAS,GAAG,MAAM,CAAC;QAAE,YAAY,CAAC,SAAS,GAAG,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IACtF,IAAI,UAAU,CAAC,SAAS,GAAG,MAAM,CAAC;QAAE,YAAY,CAAC,SAAS,GAAG,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IACtF,OAAO,CAAC,GAAG,CAAC,0DAA0D,SAAS,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAEpC,MAAM,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAC9C,MAAM,CAAC,MAAM,KAAK,GAAiB,MAAM,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,CAAC"}