naider 1.7.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 (359) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +884 -0
  3. package/SPEC-X.nx +276 -0
  4. package/SPEC.naide +431 -0
  5. package/bin/naide.js +519 -0
  6. package/examples/ai-app.naide +21 -0
  7. package/examples/ai-app.nx +21 -0
  8. package/examples/async.naide +50 -0
  9. package/examples/async.nx +40 -0
  10. package/examples/crud.naide +79 -0
  11. package/examples/crud.nx +64 -0
  12. package/examples/fullapp.naide +74 -0
  13. package/examples/fullapp.nx +74 -0
  14. package/examples/hello.naide +33 -0
  15. package/examples/hello.nx +29 -0
  16. package/examples/model.naide +44 -0
  17. package/examples/server.naide +28 -0
  18. package/examples/server.nx +27 -0
  19. package/examples/sql-app.naide +23 -0
  20. package/examples/sql-app.nx +23 -0
  21. package/examples/todo-api.naide +34 -0
  22. package/examples/todo-api.nx +31 -0
  23. package/lsp/server.js +172 -0
  24. package/package.json +56 -0
  25. package/src/generator.js +1313 -0
  26. package/src/index.js +41 -0
  27. package/src/lexer.js +402 -0
  28. package/src/parser.js +1671 -0
  29. package/src/preprocess.js +308 -0
  30. package/src/runtime.js +969 -0
  31. package/src/tokens.js +218 -0
  32. package/vscode-naide/README.md +38 -0
  33. package/vscode-naide/extension.js +41 -0
  34. package/vscode-naide/language-configuration-naide.json +32 -0
  35. package/vscode-naide/language-configuration-nx.json +32 -0
  36. package/vscode-naide/naide-lang-1.1.0.vsix +0 -0
  37. package/vscode-naide/node_modules/.bin/semver +16 -0
  38. package/vscode-naide/node_modules/.bin/semver.cmd +17 -0
  39. package/vscode-naide/node_modules/.bin/semver.ps1 +28 -0
  40. package/vscode-naide/node_modules/.package-lock.json +86 -0
  41. package/vscode-naide/node_modules/balanced-match/.github/FUNDING.yml +2 -0
  42. package/vscode-naide/node_modules/balanced-match/LICENSE.md +21 -0
  43. package/vscode-naide/node_modules/balanced-match/README.md +97 -0
  44. package/vscode-naide/node_modules/balanced-match/index.js +62 -0
  45. package/vscode-naide/node_modules/balanced-match/package.json +48 -0
  46. package/vscode-naide/node_modules/brace-expansion/.github/FUNDING.yml +2 -0
  47. package/vscode-naide/node_modules/brace-expansion/LICENSE +21 -0
  48. package/vscode-naide/node_modules/brace-expansion/README.md +157 -0
  49. package/vscode-naide/node_modules/brace-expansion/index.js +394 -0
  50. package/vscode-naide/node_modules/brace-expansion/package.json +49 -0
  51. package/vscode-naide/node_modules/minimatch/LICENSE +15 -0
  52. package/vscode-naide/node_modules/minimatch/README.md +296 -0
  53. package/vscode-naide/node_modules/minimatch/changelog.md +35 -0
  54. package/vscode-naide/node_modules/minimatch/lib/path.js +4 -0
  55. package/vscode-naide/node_modules/minimatch/minimatch.js +996 -0
  56. package/vscode-naide/node_modules/minimatch/package.json +35 -0
  57. package/vscode-naide/node_modules/semver/LICENSE +15 -0
  58. package/vscode-naide/node_modules/semver/README.md +680 -0
  59. package/vscode-naide/node_modules/semver/bin/semver.js +195 -0
  60. package/vscode-naide/node_modules/semver/classes/comparator.js +143 -0
  61. package/vscode-naide/node_modules/semver/classes/index.js +7 -0
  62. package/vscode-naide/node_modules/semver/classes/range.js +577 -0
  63. package/vscode-naide/node_modules/semver/classes/semver.js +350 -0
  64. package/vscode-naide/node_modules/semver/functions/clean.js +8 -0
  65. package/vscode-naide/node_modules/semver/functions/cmp.js +54 -0
  66. package/vscode-naide/node_modules/semver/functions/coerce.js +62 -0
  67. package/vscode-naide/node_modules/semver/functions/compare-build.js +9 -0
  68. package/vscode-naide/node_modules/semver/functions/compare-loose.js +5 -0
  69. package/vscode-naide/node_modules/semver/functions/compare.js +7 -0
  70. package/vscode-naide/node_modules/semver/functions/diff.js +60 -0
  71. package/vscode-naide/node_modules/semver/functions/eq.js +5 -0
  72. package/vscode-naide/node_modules/semver/functions/gt.js +5 -0
  73. package/vscode-naide/node_modules/semver/functions/gte.js +5 -0
  74. package/vscode-naide/node_modules/semver/functions/inc.js +21 -0
  75. package/vscode-naide/node_modules/semver/functions/lt.js +5 -0
  76. package/vscode-naide/node_modules/semver/functions/lte.js +5 -0
  77. package/vscode-naide/node_modules/semver/functions/major.js +5 -0
  78. package/vscode-naide/node_modules/semver/functions/minor.js +5 -0
  79. package/vscode-naide/node_modules/semver/functions/neq.js +5 -0
  80. package/vscode-naide/node_modules/semver/functions/parse.js +18 -0
  81. package/vscode-naide/node_modules/semver/functions/patch.js +5 -0
  82. package/vscode-naide/node_modules/semver/functions/prerelease.js +8 -0
  83. package/vscode-naide/node_modules/semver/functions/rcompare.js +5 -0
  84. package/vscode-naide/node_modules/semver/functions/rsort.js +5 -0
  85. package/vscode-naide/node_modules/semver/functions/satisfies.js +12 -0
  86. package/vscode-naide/node_modules/semver/functions/sort.js +5 -0
  87. package/vscode-naide/node_modules/semver/functions/truncate.js +48 -0
  88. package/vscode-naide/node_modules/semver/functions/valid.js +8 -0
  89. package/vscode-naide/node_modules/semver/index.js +93 -0
  90. package/vscode-naide/node_modules/semver/internal/constants.js +37 -0
  91. package/vscode-naide/node_modules/semver/internal/debug.js +11 -0
  92. package/vscode-naide/node_modules/semver/internal/identifiers.js +29 -0
  93. package/vscode-naide/node_modules/semver/internal/lrucache.js +42 -0
  94. package/vscode-naide/node_modules/semver/internal/parse-options.js +17 -0
  95. package/vscode-naide/node_modules/semver/internal/re.js +223 -0
  96. package/vscode-naide/node_modules/semver/package.json +78 -0
  97. package/vscode-naide/node_modules/semver/preload.js +4 -0
  98. package/vscode-naide/node_modules/semver/range.bnf +17 -0
  99. package/vscode-naide/node_modules/semver/ranges/gtr.js +6 -0
  100. package/vscode-naide/node_modules/semver/ranges/intersects.js +9 -0
  101. package/vscode-naide/node_modules/semver/ranges/ltr.js +6 -0
  102. package/vscode-naide/node_modules/semver/ranges/max-satisfying.js +27 -0
  103. package/vscode-naide/node_modules/semver/ranges/min-satisfying.js +26 -0
  104. package/vscode-naide/node_modules/semver/ranges/min-version.js +63 -0
  105. package/vscode-naide/node_modules/semver/ranges/outside.js +82 -0
  106. package/vscode-naide/node_modules/semver/ranges/simplify.js +49 -0
  107. package/vscode-naide/node_modules/semver/ranges/subset.js +249 -0
  108. package/vscode-naide/node_modules/semver/ranges/to-comparators.js +10 -0
  109. package/vscode-naide/node_modules/semver/ranges/valid.js +13 -0
  110. package/vscode-naide/node_modules/vscode-jsonrpc/License.txt +11 -0
  111. package/vscode-naide/node_modules/vscode-jsonrpc/README.md +69 -0
  112. package/vscode-naide/node_modules/vscode-jsonrpc/browser.d.ts +6 -0
  113. package/vscode-naide/node_modules/vscode-jsonrpc/browser.js +7 -0
  114. package/vscode-naide/node_modules/vscode-jsonrpc/lib/browser/main.d.ts +17 -0
  115. package/vscode-naide/node_modules/vscode-jsonrpc/lib/browser/main.js +76 -0
  116. package/vscode-naide/node_modules/vscode-jsonrpc/lib/browser/ril.d.ts +12 -0
  117. package/vscode-naide/node_modules/vscode-jsonrpc/lib/browser/ril.js +156 -0
  118. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/api.d.ts +14 -0
  119. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/api.js +81 -0
  120. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/cancellation.d.ts +32 -0
  121. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/cancellation.js +96 -0
  122. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/connection.d.ts +358 -0
  123. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/connection.js +1212 -0
  124. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/disposable.d.ts +9 -0
  125. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/disposable.js +16 -0
  126. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/encoding.d.ts +52 -0
  127. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/encoding.js +70 -0
  128. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/events.d.ts +39 -0
  129. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/events.js +128 -0
  130. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/is.d.ts +7 -0
  131. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/is.js +35 -0
  132. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/linkedMap.d.ts +53 -0
  133. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/linkedMap.js +398 -0
  134. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/messageBuffer.d.ts +18 -0
  135. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/messageBuffer.js +152 -0
  136. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/messageReader.d.ts +77 -0
  137. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/messageReader.js +197 -0
  138. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/messageWriter.d.ts +60 -0
  139. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/messageWriter.js +115 -0
  140. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/messages.d.ts +369 -0
  141. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/messages.js +306 -0
  142. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/ral.d.ts +74 -0
  143. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/ral.js +23 -0
  144. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/semaphore.d.ts +10 -0
  145. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/semaphore.js +68 -0
  146. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/sharedArrayCancellation.d.ts +15 -0
  147. package/vscode-naide/node_modules/vscode-jsonrpc/lib/common/sharedArrayCancellation.js +76 -0
  148. package/vscode-naide/node_modules/vscode-jsonrpc/lib/node/main.d.ts +63 -0
  149. package/vscode-naide/node_modules/vscode-jsonrpc/lib/node/main.js +257 -0
  150. package/vscode-naide/node_modules/vscode-jsonrpc/lib/node/ril.d.ts +13 -0
  151. package/vscode-naide/node_modules/vscode-jsonrpc/lib/node/ril.js +161 -0
  152. package/vscode-naide/node_modules/vscode-jsonrpc/node.cmd +5 -0
  153. package/vscode-naide/node_modules/vscode-jsonrpc/node.d.ts +6 -0
  154. package/vscode-naide/node_modules/vscode-jsonrpc/node.js +7 -0
  155. package/vscode-naide/node_modules/vscode-jsonrpc/package.json +45 -0
  156. package/vscode-naide/node_modules/vscode-jsonrpc/thirdpartynotices.txt +16 -0
  157. package/vscode-naide/node_modules/vscode-jsonrpc/typings/thenable.d.ts +5 -0
  158. package/vscode-naide/node_modules/vscode-languageclient/License.txt +11 -0
  159. package/vscode-naide/node_modules/vscode-languageclient/README.md +17 -0
  160. package/vscode-naide/node_modules/vscode-languageclient/browser.d.ts +6 -0
  161. package/vscode-naide/node_modules/vscode-languageclient/browser.js +7 -0
  162. package/vscode-naide/node_modules/vscode-languageclient/lib/browser/main.d.ts +8 -0
  163. package/vscode-naide/node_modules/vscode-languageclient/lib/browser/main.js +37 -0
  164. package/vscode-naide/node_modules/vscode-languageclient/lib/common/api.d.ts +36 -0
  165. package/vscode-naide/node_modules/vscode-languageclient/lib/common/api.js +27 -0
  166. package/vscode-naide/node_modules/vscode-languageclient/lib/common/callHierarchy.d.ts +37 -0
  167. package/vscode-naide/node_modules/vscode-languageclient/lib/common/callHierarchy.js +97 -0
  168. package/vscode-naide/node_modules/vscode-languageclient/lib/common/client.d.ts +476 -0
  169. package/vscode-naide/node_modules/vscode-languageclient/lib/common/client.js +1600 -0
  170. package/vscode-naide/node_modules/vscode-languageclient/lib/common/codeAction.d.ts +19 -0
  171. package/vscode-naide/node_modules/vscode-languageclient/lib/common/codeAction.js +99 -0
  172. package/vscode-naide/node_modules/vscode-languageclient/lib/common/codeConverter.d.ts +78 -0
  173. package/vscode-naide/node_modules/vscode-languageclient/lib/common/codeConverter.js +876 -0
  174. package/vscode-naide/node_modules/vscode-languageclient/lib/common/codeLens.d.ts +23 -0
  175. package/vscode-naide/node_modules/vscode-languageclient/lib/common/codeLens.js +78 -0
  176. package/vscode-naide/node_modules/vscode-languageclient/lib/common/colorProvider.d.ts +25 -0
  177. package/vscode-naide/node_modules/vscode-languageclient/lib/common/colorProvider.js +74 -0
  178. package/vscode-naide/node_modules/vscode-languageclient/lib/common/completion.d.ts +20 -0
  179. package/vscode-naide/node_modules/vscode-languageclient/lib/common/completion.js +126 -0
  180. package/vscode-naide/node_modules/vscode-languageclient/lib/common/configuration.d.ts +69 -0
  181. package/vscode-naide/node_modules/vscode-languageclient/lib/common/configuration.js +209 -0
  182. package/vscode-naide/node_modules/vscode-languageclient/lib/common/declaration.d.ts +16 -0
  183. package/vscode-naide/node_modules/vscode-languageclient/lib/common/declaration.js +54 -0
  184. package/vscode-naide/node_modules/vscode-languageclient/lib/common/definition.d.ts +16 -0
  185. package/vscode-naide/node_modules/vscode-languageclient/lib/common/definition.js +55 -0
  186. package/vscode-naide/node_modules/vscode-languageclient/lib/common/diagnostic.d.ts +122 -0
  187. package/vscode-naide/node_modules/vscode-languageclient/lib/common/diagnostic.js +814 -0
  188. package/vscode-naide/node_modules/vscode-languageclient/lib/common/documentHighlight.d.ts +15 -0
  189. package/vscode-naide/node_modules/vscode-languageclient/lib/common/documentHighlight.js +50 -0
  190. package/vscode-naide/node_modules/vscode-languageclient/lib/common/documentLink.d.ts +19 -0
  191. package/vscode-naide/node_modules/vscode-languageclient/lib/common/documentLink.js +71 -0
  192. package/vscode-naide/node_modules/vscode-languageclient/lib/common/documentSymbol.d.ts +17 -0
  193. package/vscode-naide/node_modules/vscode-languageclient/lib/common/documentSymbol.js +104 -0
  194. package/vscode-naide/node_modules/vscode-languageclient/lib/common/executeCommand.d.ts +21 -0
  195. package/vscode-naide/node_modules/vscode-languageclient/lib/common/executeCommand.js +72 -0
  196. package/vscode-naide/node_modules/vscode-languageclient/lib/common/features.d.ts +418 -0
  197. package/vscode-naide/node_modules/vscode-languageclient/lib/common/features.js +291 -0
  198. package/vscode-naide/node_modules/vscode-languageclient/lib/common/fileOperations.d.ts +116 -0
  199. package/vscode-naide/node_modules/vscode-languageclient/lib/common/fileOperations.js +333 -0
  200. package/vscode-naide/node_modules/vscode-languageclient/lib/common/fileSystemWatcher.d.ts +18 -0
  201. package/vscode-naide/node_modules/vscode-languageclient/lib/common/fileSystemWatcher.js +95 -0
  202. package/vscode-naide/node_modules/vscode-languageclient/lib/common/foldingRange.d.ts +19 -0
  203. package/vscode-naide/node_modules/vscode-languageclient/lib/common/foldingRange.js +65 -0
  204. package/vscode-naide/node_modules/vscode-languageclient/lib/common/formatting.d.ts +39 -0
  205. package/vscode-naide/node_modules/vscode-languageclient/lib/common/formatting.js +182 -0
  206. package/vscode-naide/node_modules/vscode-languageclient/lib/common/hover.d.ts +16 -0
  207. package/vscode-naide/node_modules/vscode-languageclient/lib/common/hover.js +58 -0
  208. package/vscode-naide/node_modules/vscode-languageclient/lib/common/implementation.d.ts +16 -0
  209. package/vscode-naide/node_modules/vscode-languageclient/lib/common/implementation.js +54 -0
  210. package/vscode-naide/node_modules/vscode-languageclient/lib/common/inlayHint.d.ts +20 -0
  211. package/vscode-naide/node_modules/vscode-languageclient/lib/common/inlayHint.js +92 -0
  212. package/vscode-naide/node_modules/vscode-languageclient/lib/common/inlineCompletion.d.ts +18 -0
  213. package/vscode-naide/node_modules/vscode-languageclient/lib/common/inlineCompletion.js +54 -0
  214. package/vscode-naide/node_modules/vscode-languageclient/lib/common/inlineValue.d.ts +18 -0
  215. package/vscode-naide/node_modules/vscode-languageclient/lib/common/inlineValue.js +65 -0
  216. package/vscode-naide/node_modules/vscode-languageclient/lib/common/linkedEditingRange.d.ts +21 -0
  217. package/vscode-naide/node_modules/vscode-languageclient/lib/common/linkedEditingRange.js +53 -0
  218. package/vscode-naide/node_modules/vscode-languageclient/lib/common/notebook.d.ts +96 -0
  219. package/vscode-naide/node_modules/vscode-languageclient/lib/common/notebook.js +851 -0
  220. package/vscode-naide/node_modules/vscode-languageclient/lib/common/progress.d.ts +11 -0
  221. package/vscode-naide/node_modules/vscode-languageclient/lib/common/progress.js +44 -0
  222. package/vscode-naide/node_modules/vscode-languageclient/lib/common/progressPart.d.ts +24 -0
  223. package/vscode-naide/node_modules/vscode-languageclient/lib/common/progressPart.js +96 -0
  224. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolCallHierarchyItem.d.ts +6 -0
  225. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolCallHierarchyItem.js +16 -0
  226. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolCodeAction.d.ts +6 -0
  227. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolCodeAction.js +14 -0
  228. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolCodeLens.d.ts +5 -0
  229. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolCodeLens.js +13 -0
  230. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolCompletionItem.d.ts +11 -0
  231. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolCompletionItem.js +13 -0
  232. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolConverter.d.ts +167 -0
  233. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolConverter.js +1134 -0
  234. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolDiagnostic.d.ts +18 -0
  235. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolDiagnostic.js +25 -0
  236. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolDocumentLink.d.ts +5 -0
  237. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolDocumentLink.js +13 -0
  238. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolInlayHint.d.ts +5 -0
  239. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolInlayHint.js +13 -0
  240. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolTypeHierarchyItem.d.ts +6 -0
  241. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolTypeHierarchyItem.js +16 -0
  242. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolWorkspaceSymbol.d.ts +7 -0
  243. package/vscode-naide/node_modules/vscode-languageclient/lib/common/protocolWorkspaceSymbol.js +18 -0
  244. package/vscode-naide/node_modules/vscode-languageclient/lib/common/reference.d.ts +20 -0
  245. package/vscode-naide/node_modules/vscode-languageclient/lib/common/reference.js +53 -0
  246. package/vscode-naide/node_modules/vscode-languageclient/lib/common/rename.d.ts +27 -0
  247. package/vscode-naide/node_modules/vscode-languageclient/lib/common/rename.js +113 -0
  248. package/vscode-naide/node_modules/vscode-languageclient/lib/common/selectionRange.d.ts +16 -0
  249. package/vscode-naide/node_modules/vscode-languageclient/lib/common/selectionRange.js +57 -0
  250. package/vscode-naide/node_modules/vscode-languageclient/lib/common/semanticTokens.d.ts +33 -0
  251. package/vscode-naide/node_modules/vscode-languageclient/lib/common/semanticTokens.js +179 -0
  252. package/vscode-naide/node_modules/vscode-languageclient/lib/common/signatureHelp.d.ts +16 -0
  253. package/vscode-naide/node_modules/vscode-languageclient/lib/common/signatureHelp.js +71 -0
  254. package/vscode-naide/node_modules/vscode-languageclient/lib/common/textSynchronization.d.ts +101 -0
  255. package/vscode-naide/node_modules/vscode-languageclient/lib/common/textSynchronization.js +402 -0
  256. package/vscode-naide/node_modules/vscode-languageclient/lib/common/typeDefinition.d.ts +16 -0
  257. package/vscode-naide/node_modules/vscode-languageclient/lib/common/typeDefinition.js +55 -0
  258. package/vscode-naide/node_modules/vscode-languageclient/lib/common/typeHierarchy.d.ts +31 -0
  259. package/vscode-naide/node_modules/vscode-languageclient/lib/common/typeHierarchy.js +96 -0
  260. package/vscode-naide/node_modules/vscode-languageclient/lib/common/utils/async.d.ts +41 -0
  261. package/vscode-naide/node_modules/vscode-languageclient/lib/common/utils/async.js +276 -0
  262. package/vscode-naide/node_modules/vscode-languageclient/lib/common/utils/is.d.ts +12 -0
  263. package/vscode-naide/node_modules/vscode-languageclient/lib/common/utils/is.js +57 -0
  264. package/vscode-naide/node_modules/vscode-languageclient/lib/common/utils/uuid.d.ts +22 -0
  265. package/vscode-naide/node_modules/vscode-languageclient/lib/common/utils/uuid.js +97 -0
  266. package/vscode-naide/node_modules/vscode-languageclient/lib/common/workspaceFolder.d.ts +30 -0
  267. package/vscode-naide/node_modules/vscode-languageclient/lib/common/workspaceFolder.js +148 -0
  268. package/vscode-naide/node_modules/vscode-languageclient/lib/common/workspaceSymbol.d.ts +19 -0
  269. package/vscode-naide/node_modules/vscode-languageclient/lib/common/workspaceSymbol.js +79 -0
  270. package/vscode-naide/node_modules/vscode-languageclient/lib/node/main.d.ts +100 -0
  271. package/vscode-naide/node_modules/vscode-languageclient/lib/node/main.js +570 -0
  272. package/vscode-naide/node_modules/vscode-languageclient/lib/node/processes.d.ts +6 -0
  273. package/vscode-naide/node_modules/vscode-languageclient/lib/node/processes.js +47 -0
  274. package/vscode-naide/node_modules/vscode-languageclient/lib/node/terminateProcess.sh +16 -0
  275. package/vscode-naide/node_modules/vscode-languageclient/node.cmd +5 -0
  276. package/vscode-naide/node_modules/vscode-languageclient/node.d.ts +6 -0
  277. package/vscode-naide/node_modules/vscode-languageclient/node.js +7 -0
  278. package/vscode-naide/node_modules/vscode-languageclient/package.json +50 -0
  279. package/vscode-naide/node_modules/vscode-languageserver-protocol/License.txt +11 -0
  280. package/vscode-naide/node_modules/vscode-languageserver-protocol/README.md +16 -0
  281. package/vscode-naide/node_modules/vscode-languageserver-protocol/browser.d.ts +6 -0
  282. package/vscode-naide/node_modules/vscode-languageserver-protocol/browser.js +7 -0
  283. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/browser/main.d.ts +4 -0
  284. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/browser/main.js +28 -0
  285. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/api.d.ts +58 -0
  286. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/api.js +77 -0
  287. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/connection.d.ts +187 -0
  288. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/connection.js +15 -0
  289. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/messages.d.ts +51 -0
  290. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/messages.js +44 -0
  291. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.$.d.ts +1 -0
  292. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.$.js +43 -0
  293. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.callHierarchy.d.ts +86 -0
  294. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.callHierarchy.js +42 -0
  295. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.colorProvider.d.ts +66 -0
  296. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.colorProvider.js +32 -0
  297. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.configuration.d.ts +35 -0
  298. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.configuration.js +24 -0
  299. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.d.ts +3252 -0
  300. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.declaration.d.ts +37 -0
  301. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.declaration.js +22 -0
  302. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.diagnostic.d.ts +341 -0
  303. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.diagnostic.js +74 -0
  304. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.fileOperations.d.ts +306 -0
  305. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.fileOperations.js +101 -0
  306. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.foldingRange.d.ts +109 -0
  307. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.foldingRange.js +30 -0
  308. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.implementation.d.ts +38 -0
  309. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.implementation.js +21 -0
  310. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlayHint.d.ts +110 -0
  311. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlayHint.js +43 -0
  312. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineCompletion.d.ts +57 -0
  313. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineCompletion.js +22 -0
  314. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineValue.d.ts +86 -0
  315. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineValue.js +30 -0
  316. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.js +943 -0
  317. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.linkedEditingRange.d.ts +52 -0
  318. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.linkedEditingRange.js +19 -0
  319. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.moniker.d.ts +106 -0
  320. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.moniker.js +68 -0
  321. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.notebook.d.ts +400 -0
  322. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.notebook.js +214 -0
  323. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.progress.d.ts +107 -0
  324. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.progress.js +37 -0
  325. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.selectionRange.d.ts +41 -0
  326. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.selectionRange.js +20 -0
  327. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.semanticTokens.d.ts +223 -0
  328. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.semanticTokens.js +57 -0
  329. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.showDocument.d.ts +72 -0
  330. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.showDocument.js +22 -0
  331. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.typeDefinition.d.ts +38 -0
  332. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.typeDefinition.js +21 -0
  333. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.typeHierarchy.d.ts +83 -0
  334. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.typeHierarchy.js +42 -0
  335. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.workspaceFolder.d.ts +74 -0
  336. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/protocol.workspaceFolder.js +27 -0
  337. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/utils/is.d.ts +9 -0
  338. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/common/utils/is.js +46 -0
  339. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/node/main.d.ts +6 -0
  340. package/vscode-naide/node_modules/vscode-languageserver-protocol/lib/node/main.js +28 -0
  341. package/vscode-naide/node_modules/vscode-languageserver-protocol/metaModel.schema.json +783 -0
  342. package/vscode-naide/node_modules/vscode-languageserver-protocol/node.cmd +5 -0
  343. package/vscode-naide/node_modules/vscode-languageserver-protocol/node.d.ts +6 -0
  344. package/vscode-naide/node_modules/vscode-languageserver-protocol/node.js +7 -0
  345. package/vscode-naide/node_modules/vscode-languageserver-protocol/package.json +45 -0
  346. package/vscode-naide/node_modules/vscode-languageserver-protocol/thirdpartynotices.txt +31 -0
  347. package/vscode-naide/node_modules/vscode-languageserver-types/License.txt +11 -0
  348. package/vscode-naide/node_modules/vscode-languageserver-types/README.md +17 -0
  349. package/vscode-naide/node_modules/vscode-languageserver-types/lib/esm/main.d.ts +3139 -0
  350. package/vscode-naide/node_modules/vscode-languageserver-types/lib/esm/main.js +2222 -0
  351. package/vscode-naide/node_modules/vscode-languageserver-types/lib/esm/package.json +3 -0
  352. package/vscode-naide/node_modules/vscode-languageserver-types/lib/umd/main.d.ts +3139 -0
  353. package/vscode-naide/node_modules/vscode-languageserver-types/lib/umd/main.js +2272 -0
  354. package/vscode-naide/node_modules/vscode-languageserver-types/package.json +38 -0
  355. package/vscode-naide/node_modules/vscode-languageserver-types/thirdpartynotices.txt +16 -0
  356. package/vscode-naide/package-lock.json +96 -0
  357. package/vscode-naide/package.json +59 -0
  358. package/vscode-naide/syntaxes/naide.tmLanguage.json +194 -0
  359. package/vscode-naide/syntaxes/naidex.tmLanguage.json +287 -0
package/src/runtime.js ADDED
@@ -0,0 +1,969 @@
1
+ import { createHmac, randomUUID, timingSafeEqual, scryptSync, randomBytes } from 'crypto';
2
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
3
+ import { dirname } from 'path';
4
+
5
+ // ===== Password Hashing (zero-dep, Node crypto) =====
6
+ export function hash(password) {
7
+ const salt = randomBytes(16).toString('hex');
8
+ const derived = scryptSync(password, salt, 64).toString('hex');
9
+ return `${salt}:${derived}`;
10
+ }
11
+
12
+ export function verify(password, stored) {
13
+ const [salt, h] = stored.split(':');
14
+ const hashBuf = Buffer.from(h, 'hex');
15
+ const testBuf = scryptSync(password, salt, 64);
16
+ return timingSafeEqual(hashBuf, testBuf);
17
+ }
18
+
19
+ // ===== UUID =====
20
+ export function uuid() {
21
+ return randomUUID();
22
+ }
23
+
24
+ // ===== Schema + Validation =====
25
+ export function createSchema(name, fieldDefs) {
26
+ const schema = {
27
+ name,
28
+ fields: fieldDefs,
29
+ validate(data) {
30
+ const errors = [];
31
+ const result = {};
32
+ for (const [field, rules] of Object.entries(fieldDefs)) {
33
+ let val = data[field];
34
+ if (rules.auto && rules.type === 'id' && val === undefined) { result[field] = randomUUID(); continue; }
35
+ if (rules.auto && rules.type === 'timestamp' && val === undefined) { result[field] = new Date().toISOString(); continue; }
36
+ if (val === undefined && rules.default !== undefined) val = rules.default;
37
+ if (rules.required && (val === undefined || val === null || val === '')) { errors.push(`${field} is required`); continue; }
38
+ if (val === undefined || val === null) continue;
39
+ if (rules.type === 'string') {
40
+ if (typeof val !== 'string') { errors.push(`${field} must be a string`); continue; }
41
+ if (rules.min !== undefined && val.length < rules.min) errors.push(`${field} must be at least ${rules.min} characters`);
42
+ if (rules.max !== undefined && val.length > rules.max) errors.push(`${field} must be at most ${rules.max} characters`);
43
+ if (rules.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val)) errors.push(`${field} must be a valid email`);
44
+ if (rules.url && !/^https?:\/\/.+/.test(val)) errors.push(`${field} must be a valid URL`);
45
+ if (rules.match && !rules.match.test(val)) errors.push(`${field} format is invalid`);
46
+ }
47
+ if (rules.type === 'number' || rules.type === 'integer') {
48
+ const n = Number(val);
49
+ if (isNaN(n)) { errors.push(`${field} must be a number`); continue; }
50
+ if (rules.type === 'integer' && !Number.isInteger(n)) errors.push(`${field} must be an integer`);
51
+ if (rules.min !== undefined && n < rules.min) errors.push(`${field} must be at least ${rules.min}`);
52
+ if (rules.max !== undefined && n > rules.max) errors.push(`${field} must be at most ${rules.max}`);
53
+ val = n;
54
+ }
55
+ if (rules.type === 'boolean') val = Boolean(val);
56
+ if (rules.type === 'enum' && !rules.values.includes(val)) errors.push(`${field} must be one of: ${rules.values.join(', ')}`);
57
+ result[field] = val;
58
+ }
59
+ return errors.length > 0 ? { valid: false, errors } : { valid: true, data: result };
60
+ },
61
+ defaults() {
62
+ const d = {};
63
+ for (const [field, rules] of Object.entries(fieldDefs)) {
64
+ if (rules.default !== undefined) d[field] = rules.default;
65
+ if (rules.auto && rules.type === 'id') d[field] = randomUUID();
66
+ if (rules.auto && rules.type === 'timestamp') d[field] = new Date().toISOString();
67
+ }
68
+ return d;
69
+ }
70
+ };
71
+ return schema;
72
+ }
73
+
74
+ // ===== In-Memory Store =====
75
+ export function createStore(schema) {
76
+ const items = new Map();
77
+ let _idField = null;
78
+ for (const [f, r] of Object.entries(schema.fields)) {
79
+ if (r.auto && r.type === 'id') { _idField = f; break; }
80
+ }
81
+ const idField = _idField || 'id';
82
+
83
+ return {
84
+ getAll() { return [...items.values()]; },
85
+ getById(id) { return items.get(String(id)) || null; },
86
+ count() { return items.size; },
87
+ create(data) {
88
+ const { valid, errors, data: validated } = schema.validate(data);
89
+ if (!valid) return { error: errors };
90
+ const id = validated[idField] || randomUUID();
91
+ validated[idField] = id;
92
+ items.set(String(id), validated);
93
+ return validated;
94
+ },
95
+ update(id, data) {
96
+ const existing = items.get(String(id));
97
+ if (!existing) return null;
98
+ const merged = { ...existing, ...data, [idField]: existing[idField] };
99
+ items.set(String(id), merged);
100
+ return merged;
101
+ },
102
+ delete(id) {
103
+ return items.delete(String(id));
104
+ },
105
+ where(conditions) {
106
+ return [...items.values()].filter(item => {
107
+ for (const [k, v] of Object.entries(conditions)) {
108
+ if (item[k] !== v) return false;
109
+ }
110
+ return true;
111
+ });
112
+ },
113
+ clear() { items.clear(); }
114
+ };
115
+ }
116
+
117
+ // ===== File-Based Persistent Store =====
118
+ export function createFileStore(schema, filePath) {
119
+ let _idField = null;
120
+ for (const [f, r] of Object.entries(schema.fields)) {
121
+ if (r.auto && r.type === 'id') { _idField = f; break; }
122
+ }
123
+ const idField = _idField || 'id';
124
+
125
+ const dir = dirname(filePath);
126
+ if (dir && dir !== '.' && !existsSync(dir)) mkdirSync(dir, { recursive: true });
127
+
128
+ const items = new Map();
129
+ try {
130
+ const data = JSON.parse(readFileSync(filePath, 'utf-8'));
131
+ for (const item of data) items.set(String(item[idField] || item.id), item);
132
+ } catch {}
133
+
134
+ function save() {
135
+ writeFileSync(filePath, JSON.stringify([...items.values()], null, 2));
136
+ }
137
+
138
+ return {
139
+ getAll() { return [...items.values()]; },
140
+ getById(id) { return items.get(String(id)) || null; },
141
+ count() { return items.size; },
142
+ create(data) {
143
+ const { valid, errors, data: validated } = schema.validate(data);
144
+ if (!valid) return { error: errors };
145
+ const id = validated[idField] || randomUUID();
146
+ validated[idField] = id;
147
+ items.set(String(id), validated);
148
+ save();
149
+ return validated;
150
+ },
151
+ update(id, data) {
152
+ const existing = items.get(String(id));
153
+ if (!existing) return null;
154
+ const merged = { ...existing, ...data, [idField]: existing[idField] };
155
+ items.set(String(id), merged);
156
+ save();
157
+ return merged;
158
+ },
159
+ delete(id) {
160
+ const result = items.delete(String(id));
161
+ if (result) save();
162
+ return result;
163
+ },
164
+ where(conditions) {
165
+ return [...items.values()].filter(item => {
166
+ for (const [k, v] of Object.entries(conditions)) {
167
+ if (item[k] !== v) return false;
168
+ }
169
+ return true;
170
+ });
171
+ },
172
+ clear() { items.clear(); save(); }
173
+ };
174
+ }
175
+
176
+ // ===== CRUD Route Registration (with pagination, search, sort) =====
177
+ export function registerCrud(app, basePath, schema, store, eventBus) {
178
+ app.get(basePath, (req, res) => {
179
+ let items = store.getAll();
180
+
181
+ const q = req.query.q;
182
+ if (q) {
183
+ const lower = q.toLowerCase();
184
+ items = items.filter(item =>
185
+ Object.values(item).some(v =>
186
+ typeof v === 'string' && v.toLowerCase().includes(lower)
187
+ )
188
+ );
189
+ }
190
+
191
+ if (req.query.sort) {
192
+ const field = req.query.sort;
193
+ const order = req.query.order === 'desc' ? -1 : 1;
194
+ items.sort((a, b) => {
195
+ if (a[field] < b[field]) return -order;
196
+ if (a[field] > b[field]) return order;
197
+ return 0;
198
+ });
199
+ }
200
+
201
+ const total = items.length;
202
+ const page = parseInt(req.query.page) || 1;
203
+ const limit = Math.min(parseInt(req.query.limit) || 20, 100);
204
+ items = items.slice((page - 1) * limit, page * limit);
205
+
206
+ res.json({ data: items, total, page, limit, pages: Math.ceil(total / limit) });
207
+ });
208
+
209
+ app.get(`${basePath}/:id`, (req, res) => {
210
+ const item = store.getById(req.params.id);
211
+ if (!item) return res.status(404).json({ error: `${schema.name} not found` });
212
+ res.json(item);
213
+ });
214
+
215
+ app.post(basePath, (req, res) => {
216
+ const result = store.create(req.body);
217
+ if (result.error) return res.status(400).json({ errors: result.error });
218
+ if (eventBus) eventBus.emit(`${schema.name}.create`, result);
219
+ res.status(201).json(result);
220
+ });
221
+
222
+ app.put(`${basePath}/:id`, (req, res) => {
223
+ const item = store.getById(req.params.id);
224
+ if (!item) return res.status(404).json({ error: `${schema.name} not found` });
225
+ const updated = store.update(req.params.id, req.body);
226
+ if (eventBus) eventBus.emit(`${schema.name}.update`, updated);
227
+ res.json(updated);
228
+ });
229
+
230
+ app.delete(`${basePath}/:id`, (req, res) => {
231
+ const item = store.getById(req.params.id);
232
+ if (!item) return res.status(404).json({ error: `${schema.name} not found` });
233
+ store.delete(req.params.id);
234
+ if (eventBus) eventBus.emit(`${schema.name}.delete`, { id: req.params.id });
235
+ res.json({ deleted: true });
236
+ });
237
+ }
238
+
239
+ // ===== JWT Auth =====
240
+ function base64url(buf) {
241
+ return Buffer.from(buf).toString('base64url');
242
+ }
243
+
244
+ export function jwtSign(payload, secret, expiresIn = '24h') {
245
+ const header = base64url(JSON.stringify({ alg: 'HS256', typ: 'JWT' }));
246
+ const ms = typeof expiresIn === 'number' ? expiresIn : parseMs(expiresIn);
247
+ const body = base64url(JSON.stringify({ ...payload, iat: Math.floor(Date.now() / 1000), exp: Math.floor((Date.now() + ms) / 1000) }));
248
+ const sig = createHmac('sha256', secret).update(`${header}.${body}`).digest('base64url');
249
+ return `${header}.${body}.${sig}`;
250
+ }
251
+
252
+ export function jwtVerify(token, secret) {
253
+ const parts = token.split('.');
254
+ if (parts.length !== 3) throw new Error('Invalid token');
255
+ const sig = createHmac('sha256', secret).update(`${parts[0]}.${parts[1]}`).digest('base64url');
256
+ const sigBuf = Buffer.from(sig);
257
+ const tokenSigBuf = Buffer.from(parts[2]);
258
+ if (sigBuf.length !== tokenSigBuf.length || !timingSafeEqual(sigBuf, tokenSigBuf)) throw new Error('Invalid signature');
259
+ const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString());
260
+ if (payload.exp && payload.exp < Math.floor(Date.now() / 1000)) throw new Error('Token expired');
261
+ return payload;
262
+ }
263
+
264
+ export function jwtAuth(secret, options = {}) {
265
+ const publicPaths = (options.public || []).map(p => new RegExp('^' + p.replace(/\*/g, '.*') + '$'));
266
+ return (req, res, next) => {
267
+ const isPublic = publicPaths.some(re => re.test(req.path));
268
+ if (isPublic) return next();
269
+ const authHeader = req.headers.authorization;
270
+ if (!authHeader || !authHeader.startsWith('Bearer ')) return res.status(401).json({ error: 'No token provided' });
271
+ try {
272
+ req.user = jwtVerify(authHeader.slice(7), secret);
273
+ next();
274
+ } catch (e) {
275
+ res.status(403).json({ error: e.message });
276
+ }
277
+ };
278
+ }
279
+
280
+ // ===== CORS Middleware =====
281
+ export function corsMiddleware(origins = ['*']) {
282
+ const allowAll = origins.includes('*');
283
+ const originSet = new Set(origins.map(o => o.replace(/^https?:\/\//, '')));
284
+ return (req, res, next) => {
285
+ const reqOrigin = req.headers.origin || '';
286
+ const host = reqOrigin.replace(/^https?:\/\//, '');
287
+ if (allowAll || originSet.has(host)) {
288
+ res.setHeader('Access-Control-Allow-Origin', reqOrigin || '*');
289
+ res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,PATCH,OPTIONS');
290
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');
291
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
292
+ }
293
+ if (req.method === 'OPTIONS') return res.status(204).end();
294
+ next();
295
+ };
296
+ }
297
+
298
+ // ===== Rate Limiting =====
299
+ export function rateLimit(max, window = '1m') {
300
+ const windowMs = parseMs(window);
301
+ const hits = new Map();
302
+ setInterval(() => hits.clear(), windowMs);
303
+ return (req, res, next) => {
304
+ const key = req.ip;
305
+ const count = (hits.get(key) || 0) + 1;
306
+ hits.set(key, count);
307
+ res.setHeader('X-RateLimit-Limit', max);
308
+ res.setHeader('X-RateLimit-Remaining', Math.max(0, max - count));
309
+ if (count > max) return res.status(429).json({ error: 'Too many requests' });
310
+ next();
311
+ };
312
+ }
313
+
314
+ // ===== Env =====
315
+ export function loadEnv(spec) {
316
+ const env = {};
317
+ for (const [key, rules] of Object.entries(spec)) {
318
+ let val = process.env[key];
319
+ if (val === undefined && rules.default !== undefined) val = String(rules.default);
320
+ if (rules.required && val === undefined) {
321
+ console.error(`[NAIDE] Missing required env var: ${key}`);
322
+ process.exit(1);
323
+ }
324
+ if (val !== undefined) {
325
+ if (rules.type === 'number' || rules.type === 'integer') val = Number(val);
326
+ if (rules.type === 'boolean') val = val === 'true' || val === '1';
327
+ }
328
+ env[key] = val;
329
+ }
330
+ return env;
331
+ }
332
+
333
+ // ===== Cron / Scheduler =====
334
+ export function scheduleEvery(interval, fn) {
335
+ const ms = parseMs(interval);
336
+ const timer = setInterval(async () => {
337
+ try { await fn(); } catch (e) { console.error('[NAIDE Cron]', e.message); }
338
+ }, ms);
339
+ fn();
340
+ return timer;
341
+ }
342
+
343
+ // ===== Event Bus (for watch) =====
344
+ export function createEventBus() {
345
+ const listeners = new Map();
346
+ return {
347
+ on(event, fn) {
348
+ if (!listeners.has(event)) listeners.set(event, []);
349
+ listeners.get(event).push(fn);
350
+ },
351
+ emit(event, data) {
352
+ const fns = listeners.get(event) || [];
353
+ for (const fn of fns) {
354
+ try { fn({ event, data, timestamp: new Date().toISOString() }); } catch (e) { console.error('[NAIDE Event]', e.message); }
355
+ }
356
+ }
357
+ };
358
+ }
359
+
360
+ // ===== HTTP Client (zero-dep, Node 18+ fetch) =====
361
+ async function jsonOrText(res) {
362
+ const ct = res.headers.get('content-type') || '';
363
+ return ct.includes('json') ? res.json() : res.text();
364
+ }
365
+
366
+ export const api = {
367
+ async get(url, opts = {}) {
368
+ const res = await fetch(url, { ...opts, method: 'GET' });
369
+ if (!res.ok) throw Object.assign(new Error(`HTTP ${res.status}`), { status: res.status, response: res });
370
+ return jsonOrText(res);
371
+ },
372
+ async post(url, body, opts = {}) {
373
+ const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', ...opts.headers }, body: JSON.stringify(body), ...opts });
374
+ if (!res.ok) throw Object.assign(new Error(`HTTP ${res.status}`), { status: res.status, response: res });
375
+ return jsonOrText(res);
376
+ },
377
+ async put(url, body, opts = {}) {
378
+ const res = await fetch(url, { method: 'PUT', headers: { 'Content-Type': 'application/json', ...opts.headers }, body: JSON.stringify(body), ...opts });
379
+ if (!res.ok) throw Object.assign(new Error(`HTTP ${res.status}`), { status: res.status, response: res });
380
+ return jsonOrText(res);
381
+ },
382
+ async del(url, opts = {}) {
383
+ const res = await fetch(url, { method: 'DELETE', ...opts });
384
+ if (!res.ok) throw Object.assign(new Error(`HTTP ${res.status}`), { status: res.status, response: res });
385
+ return jsonOrText(res);
386
+ },
387
+ async raw(url, opts = {}) {
388
+ return fetch(url, opts);
389
+ }
390
+ };
391
+
392
+ // ===== Cookie Parser =====
393
+ export function cookieParser() {
394
+ return (req, res, next) => {
395
+ req.cookies = {};
396
+ const header = req.headers.cookie;
397
+ if (header) {
398
+ for (const pair of header.split(';')) {
399
+ const idx = pair.indexOf('=');
400
+ if (idx > 0) {
401
+ const k = pair.slice(0, idx).trim();
402
+ const v = pair.slice(idx + 1).trim();
403
+ try { req.cookies[k] = decodeURIComponent(v); } catch { req.cookies[k] = v; }
404
+ }
405
+ }
406
+ }
407
+ next();
408
+ };
409
+ }
410
+
411
+ // ===== Session Middleware (zero-dep, cookie-based) =====
412
+ export function sessionMiddleware(secret) {
413
+ const store = new Map();
414
+ const maxAge = 86400000;
415
+ return (req, res, next) => {
416
+ const cookies = req.headers.cookie || '';
417
+ const sidMatch = cookies.match(/(?:^|;\s*)naide_sid=([^;]+)/);
418
+ let sid = sidMatch ? sidMatch[1] : null;
419
+ if (!sid || !store.has(sid)) {
420
+ sid = randomUUID();
421
+ store.set(sid, {});
422
+ }
423
+ req.session = store.get(sid);
424
+ req.sessionId = sid;
425
+ req.session.destroy = () => { store.delete(sid); };
426
+ const origWriteHead = res.writeHead;
427
+ res.writeHead = function(...args) {
428
+ res.setHeader('Set-Cookie', `naide_sid=${sid}; HttpOnly; Path=/; Max-Age=${maxAge / 1000}; SameSite=Lax`);
429
+ origWriteHead.apply(res, args);
430
+ };
431
+ for (const [id, data] of store) {
432
+ if (data.__ts && Date.now() - data.__ts > maxAge) store.delete(id);
433
+ }
434
+ req.session.__ts = Date.now();
435
+ next();
436
+ };
437
+ }
438
+
439
+ // ===== Template Renderer (zero-dep) =====
440
+ export function createRenderer(viewsDir) {
441
+ return (name, data = {}) => {
442
+ const filePath = viewsDir.replace(/\/$/, '') + '/' + name + (name.includes('.') ? '' : '.html');
443
+ let template = readFileSync(filePath, 'utf-8');
444
+ template = template.replace(/\{\{\s*each\s+(\w+)\s+in\s+(\w+)\s*\}\}([\s\S]*?)\{\{\s*\/each\s*\}\}/g, (_, item, list, block) => {
445
+ const arr = data[list] || [];
446
+ return arr.map(val => block.replace(new RegExp(`\\{\\{\\s*${item}\\b[^}]*\\}\\}`, 'g'), m => {
447
+ const prop = m.match(/\{\{\s*\w+\.(\w+)\s*\}\}/);
448
+ return prop ? String(val[prop[1]] ?? '') : String(val ?? '');
449
+ })).join('');
450
+ });
451
+ template = template.replace(/\{\{\s*if\s+(\w+)\s*\}\}([\s\S]*?)\{\{\s*\/if\s*\}\}/g, (_, key, block) => data[key] ? block : '');
452
+ for (const [key, value] of Object.entries(data)) {
453
+ template = template.replace(new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, 'g'), String(value ?? ''));
454
+ }
455
+ return template;
456
+ };
457
+ }
458
+
459
+ // ===== Cache Middleware (zero-dep) =====
460
+ export function cacheMiddleware(duration) {
461
+ const maxAge = parseMs(duration);
462
+ const cache = new Map();
463
+ return (req, res, next) => {
464
+ if (req.method !== 'GET') return next();
465
+ const key = req.originalUrl || req.url;
466
+ const cached = cache.get(key);
467
+ if (cached && Date.now() - cached.time < maxAge) {
468
+ res.setHeader('X-Cache', 'HIT');
469
+ const ct = cached.contentType || 'application/json';
470
+ res.setHeader('Content-Type', ct);
471
+ return res.end(cached.body);
472
+ }
473
+ const origEnd = res.end;
474
+ const origJson = res.json ? res.json.bind(res) : null;
475
+ if (origJson) {
476
+ res.json = (data) => {
477
+ cache.set(key, { body: JSON.stringify(data), contentType: 'application/json', time: Date.now() });
478
+ res.setHeader('X-Cache', 'MISS');
479
+ origJson(data);
480
+ };
481
+ }
482
+ const origSend = res.send ? res.send.bind(res) : null;
483
+ if (origSend) {
484
+ res.send = (body) => {
485
+ cache.set(key, { body: String(body), contentType: res.getHeader('content-type'), time: Date.now() });
486
+ res.setHeader('X-Cache', 'MISS');
487
+ origSend(body);
488
+ };
489
+ }
490
+ next();
491
+ };
492
+ }
493
+
494
+ // ===== Upload Middleware (zero-dep multipart parser) =====
495
+ export function uploadMiddleware(fieldName, opts = {}) {
496
+ const maxSize = opts.maxSize || 10 * 1024 * 1024;
497
+ return (req, res, next) => {
498
+ const contentType = req.headers['content-type'] || '';
499
+ if (!contentType.startsWith('multipart/form-data')) return next();
500
+ const boundaryMatch = contentType.match(/boundary=(?:"([^"]+)"|([^\s;]+))/);
501
+ if (!boundaryMatch) return next();
502
+ const boundary = boundaryMatch[1] || boundaryMatch[2];
503
+ const chunks = [];
504
+ let size = 0;
505
+ req.on('data', chunk => {
506
+ size += chunk.length;
507
+ if (size > maxSize) { req.destroy(); return res.status(413).json({ error: 'File too large' }); }
508
+ chunks.push(chunk);
509
+ });
510
+ req.on('end', () => {
511
+ try {
512
+ const buffer = Buffer.concat(chunks);
513
+ const { files, fields } = _parseMultipart(buffer, boundary);
514
+ req.files = files;
515
+ req.file = files[fieldName] || files[Object.keys(files)[0]] || null;
516
+ if (!req.body) req.body = {};
517
+ Object.assign(req.body, fields);
518
+ next();
519
+ } catch { res.status(400).json({ error: 'Invalid multipart data' }); }
520
+ });
521
+ req.on('error', () => res.status(400).json({ error: 'Upload failed' }));
522
+ };
523
+ }
524
+
525
+ function _parseMultipart(buffer, boundary) {
526
+ const files = {}, fields = {};
527
+ const delim = Buffer.from(`--${boundary}`);
528
+ let start = buffer.indexOf(delim);
529
+ if (start === -1) return { files, fields };
530
+ start += delim.length + 2;
531
+ const endDelim = Buffer.from(`--${boundary}--`);
532
+ while (start < buffer.length) {
533
+ let end = buffer.indexOf(delim, start);
534
+ if (end === -1) break;
535
+ const part = buffer.slice(start, end - 2);
536
+ const headerEnd = part.indexOf('\r\n\r\n');
537
+ if (headerEnd !== -1) {
538
+ const header = part.slice(0, headerEnd).toString('utf-8');
539
+ const body = part.slice(headerEnd + 4);
540
+ const nameMatch = header.match(/name="([^"]+)"/);
541
+ if (nameMatch) {
542
+ const filenameMatch = header.match(/filename="([^"]+)"/);
543
+ if (filenameMatch) {
544
+ const ctMatch = header.match(/Content-Type:\s*(.+)/i);
545
+ files[nameMatch[1]] = { filename: filenameMatch[1], contentType: ctMatch ? ctMatch[1].trim() : 'application/octet-stream', data: body, size: body.length };
546
+ } else {
547
+ fields[nameMatch[1]] = body.toString('utf-8');
548
+ }
549
+ }
550
+ }
551
+ start = end + delim.length;
552
+ if (buffer.slice(end, end + endDelim.length).equals(endDelim)) break;
553
+ start += 2;
554
+ }
555
+ return { files, fields };
556
+ }
557
+
558
+ // ===== SSE Manager (zero-dep) =====
559
+ export function createSseManager() {
560
+ const clients = new Set();
561
+ return {
562
+ handler() {
563
+ return (req, res) => {
564
+ res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Access-Control-Allow-Origin': '*' });
565
+ res.write(':\n\n');
566
+ const client = { res, id: randomUUID() };
567
+ clients.add(client);
568
+ req.on('close', () => clients.delete(client));
569
+ };
570
+ },
571
+ send(data, event) {
572
+ const payload = typeof data === 'string' ? data : JSON.stringify(data);
573
+ for (const client of clients) {
574
+ if (event) client.res.write(`event: ${event}\n`);
575
+ client.res.write(`data: ${payload}\n\n`);
576
+ }
577
+ },
578
+ broadcast(data, event) { this.send(data, event); },
579
+ get count() { return clients.size; }
580
+ };
581
+ }
582
+
583
+ // ===== Validate Middleware =====
584
+ export function validateMiddleware(schema) {
585
+ return (req, res, next) => {
586
+ if (['POST', 'PUT', 'PATCH'].includes(req.method)) {
587
+ const result = schema.validate(req.body || {});
588
+ if (!result.valid) {
589
+ return res.status(400).json({ errors: result.errors });
590
+ }
591
+ req.body = result.data;
592
+ }
593
+ next();
594
+ };
595
+ }
596
+
597
+ // ===== Job Queue (in-memory async) =====
598
+ export function createQueue() {
599
+ const handlers = new Map();
600
+ const pending = [];
601
+ let running = false;
602
+
603
+ async function process() {
604
+ if (running) return;
605
+ running = true;
606
+ while (pending.length > 0) {
607
+ const { name, data, resolve, reject } = pending.shift();
608
+ const handler = handlers.get(name);
609
+ if (handler) {
610
+ try { await handler(data); resolve(); } catch (e) { console.error('[NAIDE Queue]', e.message); reject(e); }
611
+ } else {
612
+ reject(new Error(`No handler for job: ${name}`));
613
+ }
614
+ }
615
+ running = false;
616
+ }
617
+
618
+ return {
619
+ register(name, fn) { handlers.set(name, fn); },
620
+ add(name, data) {
621
+ return new Promise((resolve, reject) => {
622
+ pending.push({ name, data, resolve, reject });
623
+ process();
624
+ });
625
+ },
626
+ get size() { return pending.length; }
627
+ };
628
+ }
629
+
630
+ // ===== OpenAPI Spec Builder =====
631
+ export function buildOpenApiSpec(schemas) {
632
+ const spec = {
633
+ openapi: '3.1.0',
634
+ info: { title: 'API', version: '1.0.0' },
635
+ paths: {},
636
+ components: { schemas: {} }
637
+ };
638
+ for (const schema of schemas) {
639
+ const properties = {};
640
+ const required = [];
641
+ for (const [fieldName, fieldDef] of Object.entries(schema.fields)) {
642
+ const prop = {};
643
+ switch (fieldDef.type) {
644
+ case 'id': prop.type = 'string'; prop.format = 'uuid'; break;
645
+ case 'string': prop.type = 'string'; break;
646
+ case 'integer': prop.type = 'integer'; break;
647
+ case 'number': prop.type = 'number'; break;
648
+ case 'boolean': prop.type = 'boolean'; break;
649
+ case 'timestamp': prop.type = 'string'; prop.format = 'date-time'; break;
650
+ case 'enum':
651
+ prop.type = 'string';
652
+ if (fieldDef.values) prop.enum = fieldDef.values;
653
+ break;
654
+ default: prop.type = 'string';
655
+ }
656
+ if (fieldDef.min !== undefined) prop.minimum = fieldDef.min;
657
+ if (fieldDef.max !== undefined) prop.maximum = fieldDef.max;
658
+ if (fieldDef.email) prop.format = 'email';
659
+ if (fieldDef.url) prop.format = 'uri';
660
+ properties[fieldName] = prop;
661
+ if (fieldDef.required) required.push(fieldName);
662
+ }
663
+ spec.components.schemas[schema.name] = { type: 'object', properties };
664
+ if (required.length > 0) spec.components.schemas[schema.name].required = required;
665
+ }
666
+ return spec;
667
+ }
668
+
669
+ // ===== AI Integration (zero-dep, Node 18+ fetch) =====
670
+ export const ai = {
671
+ async ask(prompt, options = {}) {
672
+ const apiKey = options.key || process.env.AI_KEY || process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY;
673
+ if (!apiKey) throw new Error('AI requires API key: set AI_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY env var');
674
+ if (apiKey.startsWith('sk-ant-')) {
675
+ const res = await fetch('https://api.anthropic.com/v1/messages', {
676
+ method: 'POST',
677
+ headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
678
+ body: JSON.stringify({
679
+ model: options.model || process.env.AI_MODEL || 'claude-sonnet-4-20250514',
680
+ max_tokens: options.maxTokens || 1024,
681
+ system: options.system || undefined,
682
+ messages: [{ role: 'user', content: prompt }]
683
+ })
684
+ });
685
+ if (!res.ok) throw new Error(`AI error: ${res.status}`);
686
+ const data = await res.json();
687
+ return data.content[0].text;
688
+ }
689
+ const baseUrl = options.baseUrl || process.env.AI_BASE_URL || 'https://api.openai.com/v1';
690
+ const messages = [];
691
+ if (options.system) messages.push({ role: 'system', content: options.system });
692
+ messages.push({ role: 'user', content: prompt });
693
+ const res = await fetch(`${baseUrl}/chat/completions`, {
694
+ method: 'POST',
695
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
696
+ body: JSON.stringify({
697
+ model: options.model || process.env.AI_MODEL || 'gpt-4o-mini',
698
+ messages, max_tokens: options.maxTokens || 1024, temperature: options.temperature
699
+ })
700
+ });
701
+ if (!res.ok) throw new Error(`AI error: ${res.status}`);
702
+ const data = await res.json();
703
+ return data.choices[0].message.content;
704
+ },
705
+
706
+ async json(prompt, schema, options = {}) {
707
+ const schemaStr = typeof schema === 'string' ? schema : JSON.stringify(schema);
708
+ const result = await ai.ask(`${prompt}\n\nRespond ONLY with valid JSON matching: ${schemaStr}`, options);
709
+ try { return JSON.parse(result); } catch {
710
+ const m = result.match(/\{[\s\S]*\}/) || result.match(/\[[\s\S]*\]/);
711
+ if (m) return JSON.parse(m[0]);
712
+ throw new Error('AI did not return valid JSON');
713
+ }
714
+ },
715
+
716
+ async stream(prompt, options = {}) {
717
+ const apiKey = options.key || process.env.AI_KEY || process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY;
718
+ if (!apiKey) throw new Error('AI requires API key');
719
+ if (apiKey.startsWith('sk-ant-')) {
720
+ const res = await fetch('https://api.anthropic.com/v1/messages', {
721
+ method: 'POST',
722
+ headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
723
+ body: JSON.stringify({
724
+ model: options.model || process.env.AI_MODEL || 'claude-sonnet-4-20250514',
725
+ max_tokens: options.maxTokens || 1024,
726
+ system: options.system || undefined,
727
+ messages: [{ role: 'user', content: prompt }],
728
+ stream: true
729
+ })
730
+ });
731
+ if (!res.ok) throw new Error(`AI error: ${res.status}`);
732
+ return _sseStream(res, 'anthropic');
733
+ }
734
+ const baseUrl = options.baseUrl || process.env.AI_BASE_URL || 'https://api.openai.com/v1';
735
+ const messages = [];
736
+ if (options.system) messages.push({ role: 'system', content: options.system });
737
+ messages.push({ role: 'user', content: prompt });
738
+ const res = await fetch(`${baseUrl}/chat/completions`, {
739
+ method: 'POST',
740
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
741
+ body: JSON.stringify({
742
+ model: options.model || process.env.AI_MODEL || 'gpt-4o-mini',
743
+ messages, max_tokens: options.maxTokens || 1024, temperature: options.temperature,
744
+ stream: true
745
+ })
746
+ });
747
+ if (!res.ok) throw new Error(`AI error: ${res.status}`);
748
+ return _sseStream(res, 'openai');
749
+ },
750
+
751
+ async embed(text, options = {}) {
752
+ const apiKey = options.key || process.env.AI_KEY || process.env.OPENAI_API_KEY;
753
+ if (!apiKey) throw new Error('AI embed requires API key (OpenAI-compatible)');
754
+ const baseUrl = options.baseUrl || process.env.AI_BASE_URL || 'https://api.openai.com/v1';
755
+ const input = Array.isArray(text) ? text : [text];
756
+ const res = await fetch(`${baseUrl}/embeddings`, {
757
+ method: 'POST',
758
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
759
+ body: JSON.stringify({
760
+ model: options.model || process.env.AI_EMBED_MODEL || 'text-embedding-3-small',
761
+ input
762
+ })
763
+ });
764
+ if (!res.ok) throw new Error(`AI embed error: ${res.status}`);
765
+ const data = await res.json();
766
+ const embeddings = data.data.map(d => d.embedding);
767
+ return Array.isArray(text) ? embeddings : embeddings[0];
768
+ },
769
+
770
+ similarity(a, b) {
771
+ let dot = 0, normA = 0, normB = 0;
772
+ for (let i = 0; i < a.length; i++) {
773
+ dot += a[i] * b[i];
774
+ normA += a[i] * a[i];
775
+ normB += b[i] * b[i];
776
+ }
777
+ return dot / (Math.sqrt(normA) * Math.sqrt(normB));
778
+ },
779
+
780
+ async chat(messages, options = {}) {
781
+ const apiKey = options.key || process.env.AI_KEY || process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY;
782
+ if (!apiKey) throw new Error('AI requires API key');
783
+ if (apiKey.startsWith('sk-ant-')) {
784
+ const system = messages.find(m => m.role === 'system')?.content;
785
+ const msgs = messages.filter(m => m.role !== 'system');
786
+ const res = await fetch('https://api.anthropic.com/v1/messages', {
787
+ method: 'POST',
788
+ headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
789
+ body: JSON.stringify({
790
+ model: options.model || process.env.AI_MODEL || 'claude-sonnet-4-20250514',
791
+ max_tokens: options.maxTokens || 1024,
792
+ system: system || undefined, messages: msgs
793
+ })
794
+ });
795
+ if (!res.ok) throw new Error(`AI error: ${res.status}`);
796
+ const data = await res.json();
797
+ return data.content[0].text;
798
+ }
799
+ const baseUrl = options.baseUrl || process.env.AI_BASE_URL || 'https://api.openai.com/v1';
800
+ const res = await fetch(`${baseUrl}/chat/completions`, {
801
+ method: 'POST',
802
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
803
+ body: JSON.stringify({
804
+ model: options.model || process.env.AI_MODEL || 'gpt-4o-mini',
805
+ messages, max_tokens: options.maxTokens || 1024, temperature: options.temperature
806
+ })
807
+ });
808
+ if (!res.ok) throw new Error(`AI error: ${res.status}`);
809
+ const data = await res.json();
810
+ return data.choices[0].message.content;
811
+ }
812
+ };
813
+
814
+ // ===== SQL Store — SQLite (via better-sqlite3) =====
815
+ export function createSqliteStore(db, tableName, schema) {
816
+ const fields = Object.entries(schema.fields);
817
+ const idField = fields.find(([_, r]) => r.auto && r.type === 'id')?.[0] || 'id';
818
+
819
+ const columns = fields.map(([name, rules]) => {
820
+ let type = 'TEXT';
821
+ if (rules.type === 'integer') type = 'INTEGER';
822
+ if (rules.type === 'number') type = 'REAL';
823
+ if (rules.type === 'boolean') type = 'INTEGER';
824
+ let col = `"${name}" ${type}`;
825
+ if (rules.auto && rules.type === 'id') col += ' PRIMARY KEY';
826
+ if (rules.required && !(rules.auto && rules.type === 'id')) col += ' NOT NULL';
827
+ if (rules.default !== undefined) {
828
+ const def = typeof rules.default === 'boolean' ? (rules.default ? 1 : 0) :
829
+ typeof rules.default === 'string' ? `'${rules.default}'` : rules.default;
830
+ col += ` DEFAULT ${def}`;
831
+ }
832
+ return col;
833
+ }).join(', ');
834
+
835
+ db.exec(`CREATE TABLE IF NOT EXISTS "${tableName}" (${columns})`);
836
+
837
+ function toRow(data) {
838
+ const row = { ...data };
839
+ for (const [name, rules] of fields) {
840
+ if (rules.type === 'boolean' && name in row) row[name] = row[name] ? 1 : 0;
841
+ }
842
+ return row;
843
+ }
844
+
845
+ function fromRow(row) {
846
+ if (!row) return null;
847
+ const result = { ...row };
848
+ for (const [name, rules] of fields) {
849
+ if (rules.type === 'boolean' && name in result) result[name] = !!result[name];
850
+ }
851
+ return result;
852
+ }
853
+
854
+ return {
855
+ getAll() { return db.prepare(`SELECT * FROM "${tableName}"`).all().map(fromRow); },
856
+ getById(id) { return fromRow(db.prepare(`SELECT * FROM "${tableName}" WHERE "${idField}" = ?`).get(id)); },
857
+ count() { return db.prepare(`SELECT COUNT(*) as c FROM "${tableName}"`).get().c; },
858
+ create(data) {
859
+ const { valid, errors, data: validated } = schema.validate(data);
860
+ if (!valid) return { error: errors };
861
+ const row = toRow(validated);
862
+ const cols = Object.keys(row);
863
+ const placeholders = cols.map(() => '?').join(', ');
864
+ db.prepare(`INSERT INTO "${tableName}" (${cols.map(c => `"${c}"`).join(', ')}) VALUES (${placeholders})`).run(...cols.map(c => row[c]));
865
+ return validated;
866
+ },
867
+ update(id, data) {
868
+ const existing = this.getById(id);
869
+ if (!existing) return null;
870
+ const merged = { ...existing, ...data, [idField]: existing[idField] };
871
+ const row = toRow(merged);
872
+ const sets = Object.keys(row).filter(k => k !== idField).map(k => `"${k}" = ?`).join(', ');
873
+ const vals = Object.keys(row).filter(k => k !== idField).map(k => row[k]);
874
+ db.prepare(`UPDATE "${tableName}" SET ${sets} WHERE "${idField}" = ?`).run(...vals, id);
875
+ return merged;
876
+ },
877
+ delete(id) {
878
+ return db.prepare(`DELETE FROM "${tableName}" WHERE "${idField}" = ?`).run(id).changes > 0;
879
+ },
880
+ where(conditions) {
881
+ const keys = Object.keys(conditions);
882
+ if (keys.length === 0) return this.getAll();
883
+ const where = keys.map(k => `"${k}" = ?`).join(' AND ');
884
+ return db.prepare(`SELECT * FROM "${tableName}" WHERE ${where}`).all(...keys.map(k => conditions[k])).map(fromRow);
885
+ },
886
+ clear() { db.exec(`DELETE FROM "${tableName}"`); }
887
+ };
888
+ }
889
+
890
+ // ===== SSE Stream Parser (for ai.stream) =====
891
+ async function* _sseStream(res, provider) {
892
+ const decoder = new TextDecoder();
893
+ let buffer = '';
894
+ for await (const chunk of res.body) {
895
+ buffer += decoder.decode(chunk, { stream: true });
896
+ const lines = buffer.split('\n');
897
+ buffer = lines.pop();
898
+ for (const line of lines) {
899
+ if (!line.startsWith('data: ')) continue;
900
+ const data = line.slice(6).trim();
901
+ if (data === '[DONE]') return;
902
+ try {
903
+ const parsed = JSON.parse(data);
904
+ if (provider === 'anthropic') {
905
+ if (parsed.type === 'content_block_delta' && parsed.delta?.text) yield parsed.delta.text;
906
+ } else {
907
+ const content = parsed.choices?.[0]?.delta?.content;
908
+ if (content) yield content;
909
+ }
910
+ } catch {}
911
+ }
912
+ }
913
+ }
914
+
915
+ // ===== Vector Store (in-memory, cosine similarity) =====
916
+ export function createVectorStore() {
917
+ const items = [];
918
+
919
+ return {
920
+ add(id, embedding, metadata = {}) {
921
+ const existing = items.findIndex(i => i.id === id);
922
+ if (existing >= 0) items[existing] = { id, embedding, metadata };
923
+ else items.push({ id, embedding, metadata });
924
+ },
925
+
926
+ search(queryEmbedding, topK = 5) {
927
+ return items
928
+ .map(item => ({ ...item, score: ai.similarity(queryEmbedding, item.embedding) }))
929
+ .sort((a, b) => b.score - a.score)
930
+ .slice(0, topK);
931
+ },
932
+
933
+ remove(id) {
934
+ const idx = items.findIndex(i => i.id === id);
935
+ if (idx >= 0) { items.splice(idx, 1); return true; }
936
+ return false;
937
+ },
938
+
939
+ get size() { return items.length; },
940
+ clear() { items.length = 0; }
941
+ };
942
+ }
943
+
944
+ // ===== Prompt Template =====
945
+ export function createPrompt(template, defaults = {}) {
946
+ return function(vars = {}) {
947
+ const merged = { ...defaults, ...vars };
948
+ return template.replace(/\{(\w+)\}/g, (_, key) => {
949
+ if (key in merged) return String(merged[key]);
950
+ return `{${key}}`;
951
+ });
952
+ };
953
+ }
954
+
955
+ // ===== Helpers =====
956
+ function parseMs(str) {
957
+ if (typeof str === 'number') return str;
958
+ const m = str.match(/^(\d+)(ms|s|m|h|d)$/);
959
+ if (!m) return 60000;
960
+ const n = parseInt(m[1]);
961
+ switch (m[2]) {
962
+ case 'ms': return n;
963
+ case 's': return n * 1000;
964
+ case 'm': return n * 60000;
965
+ case 'h': return n * 3600000;
966
+ case 'd': return n * 86400000;
967
+ default: return 60000;
968
+ }
969
+ }