@nuraly/lumenjs 0.1.3 → 0.2.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 (306) hide show
  1. package/README.md +62 -282
  2. package/dist/auth/config.d.ts +23 -0
  3. package/dist/auth/config.js +115 -0
  4. package/dist/auth/guard.d.ts +12 -0
  5. package/dist/auth/guard.js +28 -0
  6. package/dist/auth/index.d.ts +3 -0
  7. package/dist/auth/index.js +1 -0
  8. package/dist/auth/middleware.d.ts +23 -0
  9. package/dist/auth/middleware.js +89 -0
  10. package/dist/auth/native-auth.d.ts +82 -0
  11. package/dist/auth/native-auth.js +340 -0
  12. package/dist/auth/oidc-client.d.ts +17 -0
  13. package/dist/auth/oidc-client.js +123 -0
  14. package/dist/auth/providers/google.d.ts +23 -0
  15. package/dist/auth/providers/google.js +25 -0
  16. package/dist/auth/providers/index.d.ts +2 -0
  17. package/dist/auth/providers/index.js +1 -0
  18. package/dist/auth/routes/login.d.ts +8 -0
  19. package/dist/auth/routes/login.js +121 -0
  20. package/dist/auth/routes/logout.d.ts +4 -0
  21. package/dist/auth/routes/logout.js +79 -0
  22. package/dist/auth/routes/oidc-callback.d.ts +3 -0
  23. package/dist/auth/routes/oidc-callback.js +70 -0
  24. package/dist/auth/routes/password.d.ts +5 -0
  25. package/dist/auth/routes/password.js +149 -0
  26. package/dist/auth/routes/signup.d.ts +3 -0
  27. package/dist/auth/routes/signup.js +81 -0
  28. package/dist/auth/routes/token.d.ts +4 -0
  29. package/dist/auth/routes/token.js +70 -0
  30. package/dist/auth/routes/totp.d.ts +22 -0
  31. package/dist/auth/routes/totp.js +232 -0
  32. package/dist/auth/routes/utils.d.ts +7 -0
  33. package/dist/auth/routes/utils.js +35 -0
  34. package/dist/auth/routes/verify.d.ts +3 -0
  35. package/dist/auth/routes/verify.js +26 -0
  36. package/dist/auth/routes.d.ts +8 -0
  37. package/dist/auth/routes.js +124 -0
  38. package/dist/auth/session.d.ts +8 -0
  39. package/dist/auth/session.js +54 -0
  40. package/dist/auth/token.d.ts +33 -0
  41. package/dist/auth/token.js +90 -0
  42. package/dist/auth/types.d.ts +156 -0
  43. package/dist/auth/types.js +2 -0
  44. package/dist/build/build-client.d.ts +15 -0
  45. package/dist/build/build-client.js +45 -0
  46. package/dist/build/build-prerender.d.ts +11 -0
  47. package/dist/build/build-prerender.js +159 -0
  48. package/dist/build/build-server.d.ts +18 -0
  49. package/dist/build/build-server.js +107 -0
  50. package/dist/build/build.js +60 -123
  51. package/dist/build/scan.d.ts +18 -0
  52. package/dist/build/scan.js +77 -6
  53. package/dist/build/serve-api.js +8 -2
  54. package/dist/build/serve-loaders.d.ts +4 -4
  55. package/dist/build/serve-loaders.js +26 -18
  56. package/dist/build/serve-ssr.js +38 -11
  57. package/dist/build/serve-static.js +3 -3
  58. package/dist/build/serve.js +341 -18
  59. package/dist/cli.js +37 -6
  60. package/dist/communication/encryption.d.ts +35 -0
  61. package/dist/communication/encryption.js +90 -0
  62. package/dist/communication/handlers/context.d.ts +27 -0
  63. package/dist/communication/handlers/context.js +1 -0
  64. package/dist/communication/handlers/conversation.d.ts +24 -0
  65. package/dist/communication/handlers/conversation.js +113 -0
  66. package/dist/communication/handlers/file-upload.d.ts +17 -0
  67. package/dist/communication/handlers/file-upload.js +62 -0
  68. package/dist/communication/handlers/messaging.d.ts +30 -0
  69. package/dist/communication/handlers/messaging.js +237 -0
  70. package/dist/communication/handlers/presence.d.ts +15 -0
  71. package/dist/communication/handlers/presence.js +76 -0
  72. package/dist/communication/handlers.d.ts +5 -0
  73. package/dist/communication/handlers.js +5 -0
  74. package/dist/communication/index.d.ts +9 -0
  75. package/dist/communication/index.js +7 -0
  76. package/dist/communication/link-preview.d.ts +18 -0
  77. package/dist/communication/link-preview.js +115 -0
  78. package/dist/communication/schema.d.ts +10 -0
  79. package/dist/communication/schema.js +101 -0
  80. package/dist/communication/server.d.ts +86 -0
  81. package/dist/communication/server.js +212 -0
  82. package/dist/communication/signaling.d.ts +43 -0
  83. package/dist/communication/signaling.js +271 -0
  84. package/dist/communication/store.d.ts +71 -0
  85. package/dist/communication/store.js +289 -0
  86. package/dist/communication/types.d.ts +454 -0
  87. package/dist/communication/types.js +1 -0
  88. package/dist/create.d.ts +1 -0
  89. package/dist/create.js +55 -0
  90. package/dist/db/auto-migrate.d.ts +3 -0
  91. package/dist/db/auto-migrate.js +100 -0
  92. package/dist/db/client.d.ts +3 -0
  93. package/dist/db/client.js +18 -0
  94. package/dist/db/index.d.ts +17 -13
  95. package/dist/db/index.js +205 -26
  96. package/dist/db/seed.d.ts +12 -0
  97. package/dist/db/seed.js +88 -0
  98. package/dist/db/table.d.ts +10 -0
  99. package/dist/db/table.js +12 -0
  100. package/dist/dev-server/config.d.ts +11 -0
  101. package/dist/dev-server/config.js +40 -20
  102. package/dist/dev-server/index-html.d.ts +4 -0
  103. package/dist/dev-server/index-html.js +21 -6
  104. package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
  105. package/dist/dev-server/nuralyui-aliases.js +115 -94
  106. package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
  107. package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
  108. package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
  109. package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
  110. package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
  111. package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
  112. package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
  113. package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
  114. package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
  115. package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
  116. package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
  117. package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
  118. package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
  119. package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
  120. package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
  121. package/dist/dev-server/plugins/vite-plugin-loaders.js +146 -13
  122. package/dist/dev-server/plugins/vite-plugin-routes.js +16 -5
  123. package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
  124. package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
  125. package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
  126. package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
  127. package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
  128. package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
  129. package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +140 -3
  130. package/dist/dev-server/server.js +242 -70
  131. package/dist/dev-server/ssr-render.d.ts +2 -1
  132. package/dist/dev-server/ssr-render.js +117 -50
  133. package/dist/editor/ai/backend.d.ts +20 -0
  134. package/dist/editor/ai/backend.js +113 -0
  135. package/dist/editor/ai/claude-code-client.d.ts +20 -0
  136. package/dist/editor/ai/claude-code-client.js +145 -0
  137. package/dist/editor/ai/deepseek-client.d.ts +7 -0
  138. package/dist/editor/ai/deepseek-client.js +113 -0
  139. package/dist/editor/ai/opencode-client.d.ts +14 -0
  140. package/dist/editor/ai/opencode-client.js +99 -0
  141. package/dist/editor/ai/snapshot-store.d.ts +22 -0
  142. package/dist/editor/ai/snapshot-store.js +35 -0
  143. package/dist/editor/ai/types.d.ts +30 -0
  144. package/dist/editor/ai/types.js +136 -0
  145. package/dist/editor/ai-chat-panel.d.ts +13 -0
  146. package/dist/editor/ai-chat-panel.js +613 -0
  147. package/dist/editor/ai-markdown.d.ts +10 -0
  148. package/dist/editor/ai-markdown.js +70 -0
  149. package/dist/editor/ai-project-panel.d.ts +11 -0
  150. package/dist/editor/ai-project-panel.js +332 -0
  151. package/dist/editor/ast-modification.d.ts +11 -0
  152. package/dist/editor/ast-modification.js +1 -0
  153. package/dist/editor/ast-service.d.ts +30 -0
  154. package/dist/editor/ast-service.js +180 -0
  155. package/dist/editor/css-rules.d.ts +54 -0
  156. package/dist/editor/css-rules.js +423 -0
  157. package/dist/editor/editor-api-client.d.ts +51 -0
  158. package/dist/editor/editor-api-client.js +162 -0
  159. package/dist/editor/editor-bridge.d.ts +1 -0
  160. package/dist/editor/editor-bridge.js +18 -8
  161. package/dist/editor/editor-toolbar.d.ts +14 -0
  162. package/dist/editor/editor-toolbar.js +115 -0
  163. package/dist/editor/file-editor.d.ts +9 -0
  164. package/dist/editor/file-editor.js +236 -0
  165. package/dist/editor/file-service.d.ts +16 -0
  166. package/dist/editor/file-service.js +52 -0
  167. package/dist/editor/i18n-key-gen.d.ts +1 -0
  168. package/dist/editor/i18n-key-gen.js +7 -0
  169. package/dist/editor/inline-text-edit.d.ts +5 -0
  170. package/dist/editor/inline-text-edit.js +173 -92
  171. package/dist/editor/overlay-events.d.ts +5 -0
  172. package/dist/editor/overlay-events.js +364 -0
  173. package/dist/editor/overlay-hmr.d.ts +2 -0
  174. package/dist/editor/overlay-hmr.js +76 -0
  175. package/dist/editor/overlay-selection.d.ts +29 -0
  176. package/dist/editor/overlay-selection.js +148 -0
  177. package/dist/editor/overlay-utils.d.ts +12 -0
  178. package/dist/editor/overlay-utils.js +59 -0
  179. package/dist/editor/properties-panel-persist.d.ts +14 -0
  180. package/dist/editor/properties-panel-persist.js +70 -0
  181. package/dist/editor/properties-panel-rows.d.ts +10 -0
  182. package/dist/editor/properties-panel-rows.js +349 -0
  183. package/dist/editor/properties-panel-styles.d.ts +4 -0
  184. package/dist/editor/properties-panel-styles.js +174 -0
  185. package/dist/editor/properties-panel.d.ts +4 -0
  186. package/dist/editor/properties-panel.js +148 -0
  187. package/dist/editor/property-registry.d.ts +16 -0
  188. package/dist/editor/property-registry.js +303 -0
  189. package/dist/editor/standalone-file-panel.d.ts +0 -0
  190. package/dist/editor/standalone-file-panel.js +1 -0
  191. package/dist/editor/standalone-overlay-dom.d.ts +0 -0
  192. package/dist/editor/standalone-overlay-dom.js +1 -0
  193. package/dist/editor/standalone-overlay-styles.d.ts +0 -0
  194. package/dist/editor/standalone-overlay-styles.js +1 -0
  195. package/dist/editor/standalone-overlay.d.ts +1 -0
  196. package/dist/editor/standalone-overlay.js +76 -0
  197. package/dist/editor/syntax-highlighter.d.ts +4 -0
  198. package/dist/editor/syntax-highlighter.js +81 -0
  199. package/dist/editor/text-toolbar.d.ts +11 -0
  200. package/dist/editor/text-toolbar.js +327 -0
  201. package/dist/editor/toolbar-styles.d.ts +4 -0
  202. package/dist/editor/toolbar-styles.js +198 -0
  203. package/dist/email/index.d.ts +32 -0
  204. package/dist/email/index.js +154 -0
  205. package/dist/email/providers/resend.d.ts +2 -0
  206. package/dist/email/providers/resend.js +24 -0
  207. package/dist/email/providers/sendgrid.d.ts +2 -0
  208. package/dist/email/providers/sendgrid.js +31 -0
  209. package/dist/email/providers/smtp.d.ts +13 -0
  210. package/dist/email/providers/smtp.js +125 -0
  211. package/dist/email/template-engine.d.ts +18 -0
  212. package/dist/email/template-engine.js +116 -0
  213. package/dist/email/templates/base.d.ts +9 -0
  214. package/dist/email/templates/base.js +65 -0
  215. package/dist/email/templates/password-reset.d.ts +5 -0
  216. package/dist/email/templates/password-reset.js +15 -0
  217. package/dist/email/templates/verify-email.d.ts +5 -0
  218. package/dist/email/templates/verify-email.js +15 -0
  219. package/dist/email/templates/welcome.d.ts +5 -0
  220. package/dist/email/templates/welcome.js +13 -0
  221. package/dist/email/types.d.ts +49 -0
  222. package/dist/email/types.js +1 -0
  223. package/dist/llms/generate.d.ts +46 -0
  224. package/dist/llms/generate.js +185 -0
  225. package/dist/permissions/guard.d.ts +28 -0
  226. package/dist/permissions/guard.js +30 -0
  227. package/dist/permissions/index.d.ts +6 -0
  228. package/dist/permissions/index.js +3 -0
  229. package/dist/permissions/service.d.ts +80 -0
  230. package/dist/permissions/service.js +210 -0
  231. package/dist/permissions/tables.d.ts +5 -0
  232. package/dist/permissions/tables.js +68 -0
  233. package/dist/permissions/types.d.ts +33 -0
  234. package/dist/permissions/types.js +1 -0
  235. package/dist/runtime/app-shell.d.ts +1 -1
  236. package/dist/runtime/app-shell.js +164 -0
  237. package/dist/runtime/auth.d.ts +10 -0
  238. package/dist/runtime/auth.js +30 -0
  239. package/dist/runtime/communication.d.ts +137 -0
  240. package/dist/runtime/communication.js +228 -0
  241. package/dist/runtime/error-boundary.d.ts +23 -0
  242. package/dist/runtime/error-boundary.js +120 -0
  243. package/dist/runtime/i18n.d.ts +6 -1
  244. package/dist/runtime/i18n.js +42 -21
  245. package/dist/runtime/island.d.ts +16 -0
  246. package/dist/runtime/island.js +80 -0
  247. package/dist/runtime/router-data.d.ts +3 -0
  248. package/dist/runtime/router-data.js +102 -17
  249. package/dist/runtime/router-hydration.js +34 -2
  250. package/dist/runtime/router.d.ts +19 -2
  251. package/dist/runtime/router.js +237 -43
  252. package/dist/runtime/socket-client.d.ts +2 -0
  253. package/dist/runtime/socket-client.js +30 -0
  254. package/dist/runtime/webrtc.d.ts +91 -0
  255. package/dist/runtime/webrtc.js +428 -0
  256. package/dist/shared/dom-shims.js +4 -2
  257. package/dist/shared/graceful-shutdown.d.ts +8 -0
  258. package/dist/shared/graceful-shutdown.js +36 -0
  259. package/dist/shared/health.d.ts +8 -0
  260. package/dist/shared/health.js +25 -0
  261. package/dist/shared/llms-txt.d.ts +31 -0
  262. package/dist/shared/llms-txt.js +85 -0
  263. package/dist/shared/logger.d.ts +32 -0
  264. package/dist/shared/logger.js +93 -0
  265. package/dist/shared/meta.d.ts +27 -0
  266. package/dist/shared/meta.js +71 -0
  267. package/dist/shared/middleware-runner.d.ts +9 -0
  268. package/dist/shared/middleware-runner.js +29 -0
  269. package/dist/shared/rate-limit.d.ts +18 -0
  270. package/dist/shared/rate-limit.js +71 -0
  271. package/dist/shared/request-id.d.ts +5 -0
  272. package/dist/shared/request-id.js +18 -0
  273. package/dist/shared/route-matching.js +16 -1
  274. package/dist/shared/security-headers.d.ts +18 -0
  275. package/dist/shared/security-headers.js +38 -0
  276. package/dist/shared/socket-io-setup.d.ts +11 -0
  277. package/dist/shared/socket-io-setup.js +51 -0
  278. package/dist/shared/types.d.ts +15 -0
  279. package/dist/shared/utils.d.ts +33 -7
  280. package/dist/shared/utils.js +164 -27
  281. package/dist/storage/adapters/local.d.ts +44 -0
  282. package/dist/storage/adapters/local.js +85 -0
  283. package/dist/storage/adapters/s3.d.ts +32 -0
  284. package/dist/storage/adapters/s3.js +119 -0
  285. package/dist/storage/adapters/types.d.ts +53 -0
  286. package/dist/storage/adapters/types.js +1 -0
  287. package/dist/storage/index.d.ts +76 -0
  288. package/dist/storage/index.js +83 -0
  289. package/package.json +45 -7
  290. package/templates/blog/api/posts.ts +4 -18
  291. package/templates/blog/data/migrations/001_init.sql +6 -5
  292. package/templates/blog/lumenjs.config.ts +3 -0
  293. package/templates/blog/package.json +14 -0
  294. package/templates/blog/pages/_layout.ts +25 -0
  295. package/templates/blog/pages/index.ts +48 -22
  296. package/templates/blog/pages/posts/[slug].ts +45 -20
  297. package/templates/blog/pages/tag/[tag].ts +44 -0
  298. package/templates/dashboard/api/stats.ts +8 -5
  299. package/templates/dashboard/lumenjs.config.ts +3 -0
  300. package/templates/dashboard/package.json +14 -0
  301. package/templates/dashboard/pages/_layout.ts +25 -0
  302. package/templates/dashboard/pages/index.ts +54 -23
  303. package/templates/dashboard/pages/settings/index.ts +29 -0
  304. package/templates/default/lumenjs.config.ts +3 -0
  305. package/templates/default/package.json +14 -0
  306. package/templates/default/pages/index.ts +24 -0
@@ -0,0 +1,454 @@
1
+ import type { StorageAdapter } from '../storage/adapters/types.js';
2
+ export interface CommunicationConfig {
3
+ /** Socket.io namespace for communication events (default: '/nk/communication') */
4
+ namespace?: string;
5
+ /** WebRTC ICE/TURN server configuration */
6
+ iceServers?: RTCIceServerConfig[];
7
+ /** Default media constraints for calls */
8
+ mediaConstraints?: MediaConstraintDefaults;
9
+ /** Maximum message length in characters */
10
+ maxMessageLength?: number;
11
+ /** Enable read receipts globally */
12
+ readReceipts?: boolean;
13
+ /** Enable typing indicators globally */
14
+ typingIndicators?: boolean;
15
+ /** Message history page size */
16
+ pageSize?: number;
17
+ /** End-to-end encryption settings */
18
+ encryption?: EncryptionConfig;
19
+ /** Rate limiting for message sends */
20
+ rateLimit?: RateLimitConfig;
21
+ /** File upload constraints */
22
+ fileUpload?: FileUploadConfig;
23
+ /** Typing indicator timeout in ms. Default: 5000 */
24
+ typingTimeoutMs?: number;
25
+ /** Message retention in days. 0 = keep forever. Default: 0 */
26
+ messageRetentionDays?: number;
27
+ /** Socket reconnection config */
28
+ reconnection?: ReconnectionConfig;
29
+ /** Storage adapter for chat file uploads. Required for file:request-upload support. */
30
+ storage?: StorageAdapter;
31
+ }
32
+ export interface RateLimitConfig {
33
+ /** Max messages per window. Default: 30 */
34
+ maxMessages: number;
35
+ /** Window duration in seconds. Default: 60 */
36
+ windowSeconds: number;
37
+ }
38
+ export interface FileUploadConfig {
39
+ /** Maximum file size in bytes. Default: 25MB (26214400) */
40
+ maxFileSize: number;
41
+ /** Maximum attachments per message. Default: 10 */
42
+ maxAttachmentsPerMessage: number;
43
+ /** Allowed MIME types. Empty array = allow all. Default: common image/video/document types */
44
+ allowedMimeTypes?: string[];
45
+ }
46
+ export interface ReconnectionConfig {
47
+ /** Max reconnection attempts. Default: 10 */
48
+ maxRetries: number;
49
+ /** Base delay between retries in ms. Default: 1000 */
50
+ baseDelayMs: number;
51
+ /** Max delay cap in ms. Default: 30000 */
52
+ maxDelayMs: number;
53
+ }
54
+ export interface EncryptionConfig {
55
+ /** Enable E2E encryption for messages */
56
+ enabled: boolean;
57
+ /** How often clients should rotate pre-keys (ms). Default: 7 days */
58
+ keyRotationInterval?: number;
59
+ /** Number of one-time pre-keys each client should upload. Default: 100 */
60
+ oneTimePreKeyCount?: number;
61
+ }
62
+ export interface RTCIceServerConfig {
63
+ urls: string | string[];
64
+ username?: string;
65
+ credential?: string;
66
+ }
67
+ export interface MediaConstraintDefaults {
68
+ audio?: boolean | MediaTrackConstraintSet;
69
+ video?: boolean | MediaTrackConstraintSet;
70
+ }
71
+ export interface MediaTrackConstraintSet {
72
+ width?: number | {
73
+ min?: number;
74
+ max?: number;
75
+ ideal?: number;
76
+ };
77
+ height?: number | {
78
+ min?: number;
79
+ max?: number;
80
+ ideal?: number;
81
+ };
82
+ frameRate?: number | {
83
+ min?: number;
84
+ max?: number;
85
+ ideal?: number;
86
+ };
87
+ facingMode?: string;
88
+ echoCancellation?: boolean;
89
+ noiseSuppression?: boolean;
90
+ }
91
+ export interface Conversation {
92
+ id: string;
93
+ type: 'direct' | 'group';
94
+ name?: string;
95
+ participants: Participant[];
96
+ lastMessage?: Message;
97
+ createdAt: string;
98
+ updatedAt: string;
99
+ unreadCount: number;
100
+ pinned?: boolean;
101
+ muted?: boolean;
102
+ archived?: boolean;
103
+ }
104
+ export interface Participant {
105
+ userId: string;
106
+ displayName: string;
107
+ avatarUrl?: string;
108
+ role?: 'owner' | 'admin' | 'member';
109
+ joinedAt: string;
110
+ presence: PresenceStatus;
111
+ }
112
+ export type PresenceStatus = 'online' | 'offline' | 'away' | 'busy';
113
+ export interface PresenceUpdate {
114
+ userId: string;
115
+ status: PresenceStatus;
116
+ lastSeen?: string;
117
+ }
118
+ export interface Message {
119
+ id: string;
120
+ conversationId: string;
121
+ senderId: string;
122
+ content: string;
123
+ type: 'text' | 'image' | 'file' | 'audio' | 'system';
124
+ createdAt: string;
125
+ updatedAt?: string;
126
+ replyTo?: string;
127
+ attachment?: MessageAttachment;
128
+ status: MessageStatus;
129
+ readBy: ReadReceipt[];
130
+ /** Whether this message is end-to-end encrypted */
131
+ encrypted?: boolean;
132
+ /** Encrypted envelope — present when encrypted is true. Server stores this as opaque blob. */
133
+ envelope?: EncryptedEnvelope;
134
+ }
135
+ export type MessageStatus = 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
136
+ export interface MessageAttachment {
137
+ url: string;
138
+ mimeType: string;
139
+ fileName: string;
140
+ fileSize: number;
141
+ width?: number;
142
+ height?: number;
143
+ /** Audio/video duration in seconds */
144
+ duration?: number;
145
+ thumbnailUrl?: string;
146
+ }
147
+ export interface ReadReceipt {
148
+ userId: string;
149
+ readAt: string;
150
+ }
151
+ export interface TypingIndicator {
152
+ conversationId: string;
153
+ userId: string;
154
+ isTyping: boolean;
155
+ }
156
+ export interface MessageForward {
157
+ messageId: string;
158
+ fromConversationId: string;
159
+ toConversationId: string;
160
+ }
161
+ export type CallType = 'audio' | 'video';
162
+ export type CallState = 'idle' | 'initiating' | 'ringing' | 'connecting' | 'connected' | 'reconnecting' | 'ended';
163
+ export type CallEndReason = 'completed' | 'rejected' | 'missed' | 'busy' | 'failed' | 'cancelled';
164
+ export interface Call {
165
+ id: string;
166
+ conversationId: string;
167
+ type: CallType;
168
+ state: CallState;
169
+ callerId: string;
170
+ calleeIds: string[];
171
+ startedAt?: string;
172
+ answeredAt?: string;
173
+ endedAt?: string;
174
+ endReason?: CallEndReason;
175
+ participants: CallParticipant[];
176
+ }
177
+ export interface CallParticipant {
178
+ userId: string;
179
+ joinedAt: string;
180
+ audioMuted: boolean;
181
+ videoMuted: boolean;
182
+ screenSharing: boolean;
183
+ }
184
+ export interface SignalOffer {
185
+ callId: string;
186
+ fromUserId: string;
187
+ toUserId: string;
188
+ type: 'offer' | 'answer';
189
+ sdp: string;
190
+ /** Indicates this offer is a renegotiation (e.g., adding a screen share track mid-call) */
191
+ renegotiation?: boolean;
192
+ }
193
+ export interface SignalIceCandidate {
194
+ callId: string;
195
+ fromUserId: string;
196
+ toUserId: string;
197
+ candidate: string;
198
+ sdpMLineIndex: number | null;
199
+ sdpMid: string | null;
200
+ }
201
+ export interface SignalIceRestart {
202
+ callId: string;
203
+ fromUserId: string;
204
+ toUserId: string;
205
+ }
206
+ export interface ConnectionQualityReport {
207
+ callId: string;
208
+ userId: string;
209
+ /** Round-trip time in ms */
210
+ rtt?: number;
211
+ /** Packet loss percentage (0-100) */
212
+ packetLoss?: number;
213
+ /** Jitter in ms */
214
+ jitter?: number;
215
+ /** Quality level derived from metrics */
216
+ quality: 'excellent' | 'good' | 'fair' | 'poor';
217
+ /** Estimated available bandwidth in kbps */
218
+ availableBandwidth?: number;
219
+ }
220
+ export interface CallInitiate {
221
+ conversationId: string;
222
+ type: CallType;
223
+ calleeIds: string[];
224
+ }
225
+ export interface CallResponse {
226
+ callId: string;
227
+ action: 'accept' | 'reject';
228
+ }
229
+ export interface CallHangup {
230
+ callId: string;
231
+ reason: CallEndReason;
232
+ }
233
+ export interface CallMediaToggle {
234
+ callId: string;
235
+ audio?: boolean;
236
+ video?: boolean;
237
+ screenShare?: boolean;
238
+ }
239
+ /** A single pre-key (identity, signed, or one-time) */
240
+ export interface PreKey {
241
+ keyId: number;
242
+ publicKey: string;
243
+ }
244
+ /** A user's public key bundle uploaded to the server */
245
+ export interface KeyBundle {
246
+ userId: string;
247
+ /** Long-term identity public key */
248
+ identityKey: string;
249
+ /** Signed pre-key (rotated periodically) */
250
+ signedPreKey: PreKey;
251
+ /** Signature of signedPreKey by identityKey */
252
+ signedPreKeySignature: string;
253
+ /** One-time pre-keys (each consumed once during session setup) */
254
+ oneTimePreKeys: PreKey[];
255
+ /** When this bundle was uploaded */
256
+ uploadedAt: string;
257
+ }
258
+ /** Encrypted message envelope — server treats this as an opaque blob */
259
+ export interface EncryptedEnvelope {
260
+ /** Sender's user ID */
261
+ senderId: string;
262
+ /** Recipient's user ID (for 1:1); in groups, one envelope per recipient */
263
+ recipientId: string;
264
+ /** Session identifier for this sender-recipient pair */
265
+ sessionId: string;
266
+ /** Base64-encoded ciphertext */
267
+ ciphertext: string;
268
+ /** 'prekey' for first message (includes key exchange), 'message' for subsequent */
269
+ messageType: 'prekey' | 'message';
270
+ /** Sender's identity public key (included for verification) */
271
+ senderIdentityKey: string;
272
+ /** Ephemeral public key (present in prekey messages for X3DH) */
273
+ senderEphemeralKey?: string;
274
+ /** Which one-time pre-key was used (present in prekey messages) */
275
+ usedOneTimePreKeyId?: number;
276
+ }
277
+ /** Client requests a recipient's key bundle for session setup */
278
+ export interface KeyExchangeRequest {
279
+ recipientId: string;
280
+ }
281
+ /** Server responds with the recipient's public keys */
282
+ export interface KeyExchangeResponse {
283
+ recipientId: string;
284
+ identityKey: string;
285
+ signedPreKey: PreKey;
286
+ signedPreKeySignature: string;
287
+ /** One one-time pre-key (consumed — won't be returned again) */
288
+ oneTimePreKey?: PreKey;
289
+ }
290
+ export interface CommunicationClientEvents {
291
+ 'message:send': (data: {
292
+ conversationId: string;
293
+ content: string;
294
+ type: Message['type'];
295
+ replyTo?: string;
296
+ attachment?: MessageAttachment;
297
+ }) => void;
298
+ 'message:read': (data: {
299
+ conversationId: string;
300
+ messageId: string;
301
+ }) => void;
302
+ 'typing:start': (data: {
303
+ conversationId: string;
304
+ }) => void;
305
+ 'typing:stop': (data: {
306
+ conversationId: string;
307
+ }) => void;
308
+ 'presence:update': (data: {
309
+ status: PresenceStatus;
310
+ }) => void;
311
+ 'conversation:create': (data: {
312
+ type: 'direct' | 'group';
313
+ name?: string;
314
+ participantIds: string[];
315
+ }) => void;
316
+ 'conversation:join': (data: {
317
+ conversationId: string;
318
+ }) => void;
319
+ 'conversation:leave': (data: {
320
+ conversationId: string;
321
+ }) => void;
322
+ 'conversation:archive': (data: {
323
+ conversationId: string;
324
+ archived: boolean;
325
+ }) => void;
326
+ 'conversation:mute': (data: {
327
+ conversationId: string;
328
+ muted: boolean;
329
+ }) => void;
330
+ 'conversation:pin': (data: {
331
+ conversationId: string;
332
+ pinned: boolean;
333
+ }) => void;
334
+ 'message:forward': (data: MessageForward) => void;
335
+ 'call:initiate': (data: CallInitiate) => void;
336
+ 'call:respond': (data: CallResponse) => void;
337
+ 'call:hangup': (data: CallHangup) => void;
338
+ 'call:media-toggle': (data: CallMediaToggle) => void;
339
+ 'call:add-participant': (data: {
340
+ callId: string;
341
+ userId: string;
342
+ }) => void;
343
+ 'call:remove-participant': (data: {
344
+ callId: string;
345
+ userId: string;
346
+ }) => void;
347
+ 'signal:offer': (data: SignalOffer) => void;
348
+ 'signal:answer': (data: SignalOffer) => void;
349
+ 'signal:ice-candidate': (data: SignalIceCandidate) => void;
350
+ 'signal:ice-restart': (data: SignalIceRestart) => void;
351
+ 'call:quality-report': (data: ConnectionQualityReport) => void;
352
+ 'encryption:upload-keys': (data: KeyBundle) => void;
353
+ 'encryption:request-keys': (data: KeyExchangeRequest) => void;
354
+ 'encryption:session-init': (data: {
355
+ recipientId: string;
356
+ sessionId: string;
357
+ envelope: EncryptedEnvelope;
358
+ }) => void;
359
+ /**
360
+ * Request a presigned upload URL for a chat file attachment.
361
+ * For E2E-encrypted chats: client encrypts the file locally before uploading.
362
+ * The server issues a presigned PUT URL — it never sees the plaintext content.
363
+ */
364
+ 'file:request-upload': (data: {
365
+ conversationId: string;
366
+ mimeType: string;
367
+ size: number;
368
+ fileName: string;
369
+ }) => void;
370
+ }
371
+ export interface CommunicationServerEvents {
372
+ 'message:new': (data: Message) => void;
373
+ 'message:updated': (data: Message) => void;
374
+ 'message:status': (data: {
375
+ messageId: string;
376
+ status: MessageStatus;
377
+ }) => void;
378
+ 'message:error': (data: {
379
+ code: string;
380
+ message: string;
381
+ }) => void;
382
+ 'typing:update': (data: TypingIndicator) => void;
383
+ 'presence:changed': (data: PresenceUpdate) => void;
384
+ 'conversation:updated': (data: Conversation) => void;
385
+ 'conversation:new': (data: Conversation) => void;
386
+ 'message:forwarded': (data: Message & {
387
+ forwardedFrom?: {
388
+ conversationId: string;
389
+ messageId: string;
390
+ };
391
+ }) => void;
392
+ 'read-receipt:update': (data: {
393
+ conversationId: string;
394
+ messageId: string;
395
+ readBy: ReadReceipt;
396
+ }) => void;
397
+ 'call:incoming': (data: Call) => void;
398
+ 'call:state-changed': (data: {
399
+ callId: string;
400
+ state: CallState;
401
+ endReason?: CallEndReason;
402
+ }) => void;
403
+ 'call:participant-joined': (data: {
404
+ callId: string;
405
+ participant: CallParticipant;
406
+ }) => void;
407
+ 'call:participant-left': (data: {
408
+ callId: string;
409
+ userId: string;
410
+ }) => void;
411
+ 'call:media-changed': (data: {
412
+ callId: string;
413
+ userId: string;
414
+ audio?: boolean;
415
+ video?: boolean;
416
+ screenShare?: boolean;
417
+ }) => void;
418
+ 'signal:offer': (data: SignalOffer) => void;
419
+ 'signal:answer': (data: SignalOffer) => void;
420
+ 'signal:ice-candidate': (data: SignalIceCandidate) => void;
421
+ 'signal:ice-restart': (data: SignalIceRestart) => void;
422
+ 'call:quality-changed': (data: ConnectionQualityReport) => void;
423
+ 'encryption:keys-response': (data: KeyExchangeResponse) => void;
424
+ 'encryption:session-established': (data: {
425
+ sessionId: string;
426
+ senderId: string;
427
+ }) => void;
428
+ 'encryption:session-init': (data: {
429
+ senderId: string;
430
+ sessionId: string;
431
+ envelope: EncryptedEnvelope;
432
+ }) => void;
433
+ 'encryption:keys-depleted': (data: {
434
+ userId: string;
435
+ }) => void;
436
+ /** Presigned upload URL ready — client should PUT the (encrypted) file to uploadUrl */
437
+ 'file:upload-ready': (data: {
438
+ fileId: string;
439
+ uploadUrl: string;
440
+ key: string;
441
+ expiresAt: string;
442
+ }) => void;
443
+ /** File upload request was rejected */
444
+ 'file:upload-error': (data: {
445
+ code: string;
446
+ message: string;
447
+ }) => void;
448
+ }
449
+ export interface NkCommunication {
450
+ config: CommunicationConfig;
451
+ conversations: Conversation[];
452
+ activeCall?: Call;
453
+ encryptionEnabled?: boolean;
454
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare function createProject(name: string, template: string): Promise<void>;
package/dist/create.js ADDED
@@ -0,0 +1,55 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ const TEMPLATES = ['default', 'blog', 'dashboard', 'social'];
5
+ const BINARY_EXTENSIONS = new Set([
6
+ '.png', '.jpg', '.jpeg', '.gif', '.ico', '.webp', '.avif',
7
+ '.woff', '.woff2', '.ttf', '.eot', '.otf',
8
+ '.mp4', '.mp3', '.zip', '.tar', '.gz',
9
+ ]);
10
+ export async function createProject(name, template) {
11
+ if (!name) {
12
+ console.error('Please provide a project name: lumenjs create <name>');
13
+ process.exit(1);
14
+ }
15
+ if (!TEMPLATES.includes(template)) {
16
+ console.error(`Unknown template "${template}". Available: ${TEMPLATES.join(', ')}`);
17
+ process.exit(1);
18
+ }
19
+ const targetDir = path.resolve(name);
20
+ if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
21
+ console.error(`Directory "${name}" already exists and is not empty.`);
22
+ process.exit(1);
23
+ }
24
+ // Templates are at package-root/templates/ (sibling to dist/)
25
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
26
+ const templateDir = path.join(__dirname, '..', 'templates', template);
27
+ if (!fs.existsSync(templateDir)) {
28
+ console.error(`Template directory not found: ${templateDir}`);
29
+ process.exit(1);
30
+ }
31
+ fs.mkdirSync(targetDir, { recursive: true });
32
+ copyDir(templateDir, targetDir, name);
33
+ console.log(`\n Project created at ./${name}\n`);
34
+ console.log(` cd ${name}`);
35
+ console.log(` npm install`);
36
+ console.log(` npx lumenjs dev\n`);
37
+ }
38
+ function copyDir(src, dest, projectName) {
39
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
40
+ const srcPath = path.join(src, entry.name);
41
+ const destPath = path.join(dest, entry.name);
42
+ if (entry.isDirectory()) {
43
+ fs.mkdirSync(destPath, { recursive: true });
44
+ copyDir(srcPath, destPath, projectName);
45
+ }
46
+ else if (BINARY_EXTENSIONS.has(path.extname(entry.name).toLowerCase())) {
47
+ fs.copyFileSync(srcPath, destPath);
48
+ }
49
+ else {
50
+ let content = fs.readFileSync(srcPath, 'utf-8');
51
+ content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
52
+ fs.writeFileSync(destPath, content);
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,3 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { TableDefinition } from './table.js';
3
+ export declare function autoMigrate(db: Database.Database, projectDir: string, tables: Map<string, TableDefinition>): void;
@@ -0,0 +1,100 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ function parseBaseType(typeStr) {
4
+ // Extract just the base type (first word), lowercased
5
+ return typeStr.trim().split(/\s+/)[0].toLowerCase();
6
+ }
7
+ function buildCreateTableSQL(table) {
8
+ const cols = table.columns
9
+ .map(c => ` ${c.name} ${c.type}`)
10
+ .join(',\n');
11
+ return `CREATE TABLE ${table.name} (\n${cols}\n);`;
12
+ }
13
+ function buildAddColumnSQL(tableName, colName, colType) {
14
+ return `ALTER TABLE ${tableName} ADD COLUMN ${colName} ${colType};`;
15
+ }
16
+ function generateTimestamp() {
17
+ const now = new Date();
18
+ const pad = (n) => String(n).padStart(2, '0');
19
+ return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
20
+ }
21
+ export function autoMigrate(db, projectDir, tables) {
22
+ if (process.env.NODE_ENV === 'production')
23
+ return;
24
+ if (tables.size === 0)
25
+ return;
26
+ const migrationsDir = path.join(projectDir, 'data', 'migrations');
27
+ for (const [tableName, definition] of tables) {
28
+ const existingColumns = getExistingColumns(db, tableName);
29
+ if (!existingColumns) {
30
+ // Table doesn't exist — generate CREATE TABLE
31
+ const sql = buildCreateTableSQL(definition);
32
+ writeMigrationFile(migrationsDir, `auto_${tableName}_create`, sql);
33
+ continue;
34
+ }
35
+ // Table exists — diff columns
36
+ const existingColNames = new Set(existingColumns.map(c => c.name.toLowerCase()));
37
+ const definedColNames = new Set(definition.columns.map(c => c.name.toLowerCase()));
38
+ // Find new columns to add
39
+ const addStatements = [];
40
+ for (const col of definition.columns) {
41
+ if (!existingColNames.has(col.name.toLowerCase())) {
42
+ addStatements.push(buildAddColumnSQL(tableName, col.name, col.type));
43
+ }
44
+ }
45
+ if (addStatements.length > 0) {
46
+ const colNames = definition.columns
47
+ .filter(c => !existingColNames.has(c.name.toLowerCase()))
48
+ .map(c => c.name);
49
+ const suffix = colNames.length === 1
50
+ ? `add_${colNames[0]}`
51
+ : `add_${colNames.length}_columns`;
52
+ writeMigrationFile(migrationsDir, `auto_${tableName}_${suffix}`, addStatements.join('\n'));
53
+ }
54
+ // Warn about columns in DB but not in definition (potential drops)
55
+ for (const existing of existingColumns) {
56
+ if (!definedColNames.has(existing.name.toLowerCase())) {
57
+ console.warn(`[LumenJS] Column "${existing.name}" exists in table "${tableName}" but is not in defineTable(). ` +
58
+ `SQLite does not support DROP COLUMN in older versions — create a manual migration if needed.`);
59
+ }
60
+ }
61
+ // Warn about type mismatches
62
+ const existingByName = new Map(existingColumns.map(c => [c.name.toLowerCase(), c]));
63
+ for (const col of definition.columns) {
64
+ const existing = existingByName.get(col.name.toLowerCase());
65
+ if (existing) {
66
+ const definedBase = parseBaseType(col.type);
67
+ const existingBase = parseBaseType(existing.type);
68
+ if (definedBase !== existingBase) {
69
+ console.warn(`[LumenJS] Column "${col.name}" in table "${tableName}" has type "${existing.type}" in DB ` +
70
+ `but "${col.type}" in defineTable(). SQLite does not support ALTER COLUMN — create a manual migration if needed.`);
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ function getExistingColumns(db, tableName) {
77
+ try {
78
+ const columns = db.pragma(`table_info(${tableName})`);
79
+ if (columns.length === 0)
80
+ return null;
81
+ return columns;
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
87
+ function writeMigrationFile(migrationsDir, label, sql) {
88
+ if (!fs.existsSync(migrationsDir)) {
89
+ fs.mkdirSync(migrationsDir, { recursive: true });
90
+ }
91
+ const timestamp = generateTimestamp();
92
+ const filename = `${timestamp}_${label}.sql`;
93
+ const filePath = path.join(migrationsDir, filename);
94
+ // Avoid duplicate generation if file with same label already exists (not yet applied)
95
+ const existing = fs.readdirSync(migrationsDir).filter(f => f.endsWith(`_${label}.sql`));
96
+ if (existing.length > 0)
97
+ return;
98
+ fs.writeFileSync(filePath, sql + '\n', 'utf-8');
99
+ console.log(`[LumenJS] Generated migration: ${filename}`);
100
+ }
@@ -0,0 +1,3 @@
1
+ import { LumenDb } from './index.js';
2
+ export { LumenDb, waitForSeed } from './index.js';
3
+ export declare function useDb(): LumenDb;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Public-facing DB module for user loaders and API routes.
3
+ * Auto-detects project directory from process.env or cwd.
4
+ */
5
+ import { getProjectDir, setProjectDir } from './context.js';
6
+ import { useDb as _useDb } from './index.js';
7
+ export { LumenDb, waitForSeed } from './index.js';
8
+ export function useDb() {
9
+ try {
10
+ getProjectDir();
11
+ }
12
+ catch {
13
+ // Auto-set from env or cwd
14
+ const dir = process.env.LUMENJS_PROJECT_DIR || process.cwd();
15
+ setProjectDir(dir);
16
+ }
17
+ return _useDb();
18
+ }
@@ -1,19 +1,23 @@
1
1
  import Database from 'better-sqlite3';
2
- export declare class LumenDb {
3
- private db;
4
- constructor(db: Database.Database);
5
- /** SELECT multiple rows */
6
- all<T = any>(sql: string, ...params: any[]): T[];
7
- /** SELECT single row */
8
- get<T = any>(sql: string, ...params: any[]): T | undefined;
9
- /** INSERT/UPDATE/DELETE */
10
- run(sql: string, ...params: any[]): {
2
+ export { defineTable, getRegisteredTables } from './table.js';
3
+ export type { TableDefinition, TableColumn } from './table.js';
4
+ export { waitForSeed } from './seed.js';
5
+ export declare abstract class LumenDb {
6
+ abstract all<T = any>(sql: string, ...params: any[]): Promise<T[]>;
7
+ abstract get<T = any>(sql: string, ...params: any[]): Promise<T | undefined>;
8
+ abstract run(sql: string, ...params: any[]): Promise<{
11
9
  changes: number;
12
10
  lastInsertRowid: number | bigint;
13
- };
14
- /** Multi-statement DDL */
15
- exec(sql: string): void;
16
- /** Access the underlying better-sqlite3 instance */
11
+ }>;
12
+ abstract exec(sql: string): Promise<void>;
13
+ abstract withTransaction<T>(fn: () => Promise<T>): Promise<T>;
14
+ readonly isPg: boolean;
15
+ /** Raw SQLite Database — only available in SQLite mode */
17
16
  get raw(): Database.Database;
18
17
  }
19
18
  export declare function useDb(): LumenDb;
19
+ /**
20
+ * Returns a promise that resolves when the initial DB migrations have completed.
21
+ * Useful for waiting before serving the first request in PG mode.
22
+ */
23
+ export declare function waitForMigrations(): Promise<void>;