@nuraly/lumenjs 0.1.2 → 0.1.4

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 (337) hide show
  1. package/README.md +76 -235
  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 +73 -0
  11. package/dist/auth/native-auth.js +293 -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 +98 -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/utils.d.ts +7 -0
  31. package/dist/auth/routes/utils.js +35 -0
  32. package/dist/auth/routes/verify.d.ts +3 -0
  33. package/dist/auth/routes/verify.js +26 -0
  34. package/dist/auth/routes.d.ts +8 -0
  35. package/dist/auth/routes.js +110 -0
  36. package/dist/auth/session.d.ts +8 -0
  37. package/dist/auth/session.js +54 -0
  38. package/dist/auth/token.d.ts +33 -0
  39. package/dist/auth/token.js +90 -0
  40. package/dist/auth/types.d.ts +156 -0
  41. package/dist/auth/types.js +2 -0
  42. package/dist/build/build-client.d.ts +15 -0
  43. package/dist/build/build-client.js +45 -0
  44. package/dist/build/build-prerender.d.ts +11 -0
  45. package/dist/build/build-prerender.js +159 -0
  46. package/dist/build/build-server.d.ts +17 -0
  47. package/dist/build/build-server.js +98 -0
  48. package/dist/build/build.js +52 -120
  49. package/dist/build/scan.d.ts +19 -0
  50. package/dist/build/scan.js +77 -6
  51. package/dist/build/serve-api.js +8 -2
  52. package/dist/build/serve-loaders.d.ts +4 -2
  53. package/dist/build/serve-loaders.js +128 -10
  54. package/dist/build/serve-ssr.js +38 -11
  55. package/dist/build/serve-static.js +3 -3
  56. package/dist/build/serve.js +229 -14
  57. package/dist/cli.js +37 -6
  58. package/dist/communication/encryption.d.ts +35 -0
  59. package/dist/communication/encryption.js +90 -0
  60. package/dist/communication/handlers/context.d.ts +27 -0
  61. package/dist/communication/handlers/context.js +1 -0
  62. package/dist/communication/handlers/conversation.d.ts +24 -0
  63. package/dist/communication/handlers/conversation.js +113 -0
  64. package/dist/communication/handlers/file-upload.d.ts +17 -0
  65. package/dist/communication/handlers/file-upload.js +62 -0
  66. package/dist/communication/handlers/messaging.d.ts +30 -0
  67. package/dist/communication/handlers/messaging.js +237 -0
  68. package/dist/communication/handlers/presence.d.ts +15 -0
  69. package/dist/communication/handlers/presence.js +76 -0
  70. package/dist/communication/handlers.d.ts +5 -0
  71. package/dist/communication/handlers.js +5 -0
  72. package/dist/communication/index.d.ts +9 -0
  73. package/dist/communication/index.js +7 -0
  74. package/dist/communication/link-preview.d.ts +18 -0
  75. package/dist/communication/link-preview.js +115 -0
  76. package/dist/communication/schema.d.ts +10 -0
  77. package/dist/communication/schema.js +101 -0
  78. package/dist/communication/server.d.ts +86 -0
  79. package/dist/communication/server.js +212 -0
  80. package/dist/communication/signaling.d.ts +43 -0
  81. package/dist/communication/signaling.js +271 -0
  82. package/dist/communication/store.d.ts +71 -0
  83. package/dist/communication/store.js +289 -0
  84. package/dist/communication/types.d.ts +454 -0
  85. package/dist/communication/types.js +1 -0
  86. package/dist/create.d.ts +1 -0
  87. package/dist/create.js +55 -0
  88. package/dist/db/auto-migrate.d.ts +3 -0
  89. package/dist/db/auto-migrate.js +100 -0
  90. package/dist/db/client.d.ts +3 -0
  91. package/dist/db/client.js +18 -0
  92. package/dist/db/context.d.ts +2 -0
  93. package/dist/db/context.js +9 -0
  94. package/dist/db/index.d.ts +23 -0
  95. package/dist/db/index.js +258 -0
  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 +14 -0
  101. package/dist/dev-server/config.js +26 -9
  102. package/dist/dev-server/index-html.d.ts +3 -0
  103. package/dist/dev-server/index-html.js +18 -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.d.ts +0 -1
  122. package/dist/dev-server/plugins/vite-plugin-loaders.js +311 -42
  123. package/dist/dev-server/plugins/vite-plugin-routes.js +18 -6
  124. package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
  125. package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
  126. package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
  127. package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
  128. package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
  129. package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
  130. package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +111 -2
  131. package/dist/dev-server/server.js +128 -12
  132. package/dist/dev-server/ssr-render.d.ts +2 -1
  133. package/dist/dev-server/ssr-render.js +107 -48
  134. package/dist/editor/ai/backend.d.ts +20 -0
  135. package/dist/editor/ai/backend.js +104 -0
  136. package/dist/editor/ai/claude-code-client.d.ts +20 -0
  137. package/dist/editor/ai/claude-code-client.js +145 -0
  138. package/dist/editor/ai/opencode-client.d.ts +14 -0
  139. package/dist/editor/ai/opencode-client.js +125 -0
  140. package/dist/editor/ai/snapshot-store.d.ts +22 -0
  141. package/dist/editor/ai/snapshot-store.js +35 -0
  142. package/dist/editor/ai/types.d.ts +30 -0
  143. package/dist/editor/ai/types.js +136 -0
  144. package/dist/editor/ai-chat-panel.d.ts +13 -0
  145. package/dist/editor/ai-chat-panel.js +587 -0
  146. package/dist/editor/ai-markdown.d.ts +10 -0
  147. package/dist/editor/ai-markdown.js +70 -0
  148. package/dist/editor/ai-project-panel.d.ts +11 -0
  149. package/dist/editor/ai-project-panel.js +332 -0
  150. package/dist/editor/ast-modification.d.ts +11 -0
  151. package/dist/editor/ast-modification.js +1 -0
  152. package/dist/editor/ast-service.d.ts +30 -0
  153. package/dist/editor/ast-service.js +180 -0
  154. package/dist/editor/css-rules.d.ts +54 -0
  155. package/dist/editor/css-rules.js +423 -0
  156. package/dist/editor/editor-api-client.d.ts +51 -0
  157. package/dist/editor/editor-api-client.js +162 -0
  158. package/dist/editor/editor-bridge.d.ts +1 -0
  159. package/dist/editor/editor-bridge.js +17 -8
  160. package/dist/editor/editor-toolbar.d.ts +14 -0
  161. package/dist/editor/editor-toolbar.js +115 -0
  162. package/dist/editor/file-editor.d.ts +9 -0
  163. package/dist/editor/file-editor.js +236 -0
  164. package/dist/editor/file-service.d.ts +16 -0
  165. package/dist/editor/file-service.js +52 -0
  166. package/dist/editor/i18n-key-gen.d.ts +1 -0
  167. package/dist/editor/i18n-key-gen.js +7 -0
  168. package/dist/editor/inline-text-edit.d.ts +5 -0
  169. package/dist/editor/inline-text-edit.js +173 -92
  170. package/dist/editor/overlay-events.d.ts +5 -0
  171. package/dist/editor/overlay-events.js +364 -0
  172. package/dist/editor/overlay-hmr.d.ts +2 -0
  173. package/dist/editor/overlay-hmr.js +75 -0
  174. package/dist/editor/overlay-selection.d.ts +29 -0
  175. package/dist/editor/overlay-selection.js +148 -0
  176. package/dist/editor/overlay-utils.d.ts +12 -0
  177. package/dist/editor/overlay-utils.js +59 -0
  178. package/dist/editor/properties-panel-persist.d.ts +14 -0
  179. package/dist/editor/properties-panel-persist.js +70 -0
  180. package/dist/editor/properties-panel-rows.d.ts +10 -0
  181. package/dist/editor/properties-panel-rows.js +349 -0
  182. package/dist/editor/properties-panel-styles.d.ts +4 -0
  183. package/dist/editor/properties-panel-styles.js +174 -0
  184. package/dist/editor/properties-panel.d.ts +4 -0
  185. package/dist/editor/properties-panel.js +148 -0
  186. package/dist/editor/property-registry.d.ts +16 -0
  187. package/dist/editor/property-registry.js +303 -0
  188. package/dist/editor/standalone-file-panel.d.ts +0 -0
  189. package/dist/editor/standalone-file-panel.js +1 -0
  190. package/dist/editor/standalone-overlay-dom.d.ts +0 -0
  191. package/dist/editor/standalone-overlay-dom.js +1 -0
  192. package/dist/editor/standalone-overlay-styles.d.ts +0 -0
  193. package/dist/editor/standalone-overlay-styles.js +1 -0
  194. package/dist/editor/standalone-overlay.d.ts +1 -0
  195. package/dist/editor/standalone-overlay.js +76 -0
  196. package/dist/editor/syntax-highlighter.d.ts +4 -0
  197. package/dist/editor/syntax-highlighter.js +81 -0
  198. package/dist/editor/text-toolbar.d.ts +11 -0
  199. package/dist/editor/text-toolbar.js +327 -0
  200. package/dist/editor/toolbar-styles.d.ts +4 -0
  201. package/dist/editor/toolbar-styles.js +198 -0
  202. package/dist/email/index.d.ts +32 -0
  203. package/dist/email/index.js +154 -0
  204. package/dist/email/providers/resend.d.ts +2 -0
  205. package/dist/email/providers/resend.js +24 -0
  206. package/dist/email/providers/sendgrid.d.ts +2 -0
  207. package/dist/email/providers/sendgrid.js +31 -0
  208. package/dist/email/providers/smtp.d.ts +13 -0
  209. package/dist/email/providers/smtp.js +125 -0
  210. package/dist/email/template-engine.d.ts +18 -0
  211. package/dist/email/template-engine.js +116 -0
  212. package/dist/email/templates/base.d.ts +9 -0
  213. package/dist/email/templates/base.js +65 -0
  214. package/dist/email/templates/password-reset.d.ts +5 -0
  215. package/dist/email/templates/password-reset.js +15 -0
  216. package/dist/email/templates/verify-email.d.ts +5 -0
  217. package/dist/email/templates/verify-email.js +15 -0
  218. package/dist/email/templates/welcome.d.ts +5 -0
  219. package/dist/email/templates/welcome.js +13 -0
  220. package/dist/email/types.d.ts +49 -0
  221. package/dist/email/types.js +1 -0
  222. package/dist/llms/generate.d.ts +46 -0
  223. package/dist/llms/generate.js +185 -0
  224. package/dist/permissions/guard.d.ts +28 -0
  225. package/dist/permissions/guard.js +30 -0
  226. package/dist/permissions/index.d.ts +6 -0
  227. package/dist/permissions/index.js +3 -0
  228. package/dist/permissions/service.d.ts +80 -0
  229. package/dist/permissions/service.js +210 -0
  230. package/dist/permissions/tables.d.ts +5 -0
  231. package/dist/permissions/tables.js +68 -0
  232. package/dist/permissions/types.d.ts +33 -0
  233. package/dist/permissions/types.js +1 -0
  234. package/dist/runtime/app-shell.js +163 -0
  235. package/dist/runtime/auth.d.ts +10 -0
  236. package/dist/runtime/auth.js +30 -0
  237. package/dist/runtime/communication.d.ts +137 -0
  238. package/dist/runtime/communication.js +228 -0
  239. package/dist/runtime/error-boundary.d.ts +23 -0
  240. package/dist/runtime/error-boundary.js +120 -0
  241. package/dist/runtime/i18n.d.ts +6 -1
  242. package/dist/runtime/i18n.js +42 -21
  243. package/dist/runtime/router-data.d.ts +5 -0
  244. package/dist/runtime/router-data.js +121 -16
  245. package/dist/runtime/router-hydration.js +25 -0
  246. package/dist/runtime/router.d.ts +21 -1
  247. package/dist/runtime/router.js +221 -39
  248. package/dist/runtime/socket-client.d.ts +2 -0
  249. package/dist/runtime/socket-client.js +30 -0
  250. package/dist/runtime/webrtc.d.ts +47 -0
  251. package/dist/runtime/webrtc.js +178 -0
  252. package/dist/shared/graceful-shutdown.d.ts +8 -0
  253. package/dist/shared/graceful-shutdown.js +36 -0
  254. package/dist/shared/health.d.ts +8 -0
  255. package/dist/shared/health.js +25 -0
  256. package/dist/shared/llms-txt.d.ts +31 -0
  257. package/dist/shared/llms-txt.js +85 -0
  258. package/dist/shared/logger.d.ts +32 -0
  259. package/dist/shared/logger.js +93 -0
  260. package/dist/shared/meta.d.ts +27 -0
  261. package/dist/shared/meta.js +71 -0
  262. package/dist/shared/middleware-runner.d.ts +9 -0
  263. package/dist/shared/middleware-runner.js +29 -0
  264. package/dist/shared/rate-limit.d.ts +18 -0
  265. package/dist/shared/rate-limit.js +71 -0
  266. package/dist/shared/request-id.d.ts +5 -0
  267. package/dist/shared/request-id.js +18 -0
  268. package/dist/shared/route-matching.js +16 -1
  269. package/dist/shared/security-headers.d.ts +18 -0
  270. package/dist/shared/security-headers.js +38 -0
  271. package/dist/shared/socket-io-setup.d.ts +11 -0
  272. package/dist/shared/socket-io-setup.js +51 -0
  273. package/dist/shared/types.d.ts +16 -0
  274. package/dist/shared/utils.d.ts +37 -7
  275. package/dist/shared/utils.js +175 -26
  276. package/dist/storage/adapters/local.d.ts +44 -0
  277. package/dist/storage/adapters/local.js +85 -0
  278. package/dist/storage/adapters/s3.d.ts +32 -0
  279. package/dist/storage/adapters/s3.js +116 -0
  280. package/dist/storage/adapters/types.d.ts +53 -0
  281. package/dist/storage/adapters/types.js +1 -0
  282. package/dist/storage/index.d.ts +76 -0
  283. package/dist/storage/index.js +83 -0
  284. package/package.json +20 -1
  285. package/templates/blog/api/posts.ts +6 -0
  286. package/templates/blog/data/migrations/001_init.sql +13 -0
  287. package/templates/blog/lumenjs.config.ts +3 -0
  288. package/templates/blog/package.json +14 -0
  289. package/templates/blog/pages/_layout.ts +25 -0
  290. package/templates/blog/pages/index.ts +65 -0
  291. package/templates/blog/pages/posts/[slug].ts +60 -0
  292. package/templates/blog/pages/tag/[tag].ts +44 -0
  293. package/templates/dashboard/api/stats.ts +10 -0
  294. package/templates/dashboard/data/migrations/001_init.sql +13 -0
  295. package/templates/dashboard/lumenjs.config.ts +3 -0
  296. package/templates/dashboard/package.json +14 -0
  297. package/templates/dashboard/pages/_layout.ts +25 -0
  298. package/templates/dashboard/pages/index.ts +72 -0
  299. package/templates/dashboard/pages/settings/index.ts +29 -0
  300. package/templates/default/lumenjs.config.ts +3 -0
  301. package/templates/default/package.json +14 -0
  302. package/templates/default/pages/index.ts +24 -0
  303. package/templates/social/api/posts/[id].ts +14 -0
  304. package/templates/social/api/posts.ts +11 -0
  305. package/templates/social/api/profile/[username].ts +10 -0
  306. package/templates/social/api/upload.ts +19 -0
  307. package/templates/social/data/migrations/001_init.sql +78 -0
  308. package/templates/social/data/migrations/002_add_image_url.sql +1 -0
  309. package/templates/social/data/migrations/003_auth.sql +7 -0
  310. package/templates/social/docs/architecture.md +76 -0
  311. package/templates/social/docs/components.md +100 -0
  312. package/templates/social/docs/data.md +89 -0
  313. package/templates/social/docs/pages.md +96 -0
  314. package/templates/social/docs/theming.md +52 -0
  315. package/templates/social/lib/media.ts +130 -0
  316. package/templates/social/lumenjs.auth.ts +21 -0
  317. package/templates/social/lumenjs.config.ts +3 -0
  318. package/templates/social/package.json +5 -0
  319. package/templates/social/pages/_layout.ts +239 -0
  320. package/templates/social/pages/apps/[id].ts +173 -0
  321. package/templates/social/pages/apps/index.ts +116 -0
  322. package/templates/social/pages/auth/login.ts +92 -0
  323. package/templates/social/pages/bookmarks.ts +57 -0
  324. package/templates/social/pages/explore.ts +73 -0
  325. package/templates/social/pages/index.ts +351 -0
  326. package/templates/social/pages/messages.ts +298 -0
  327. package/templates/social/pages/new.ts +77 -0
  328. package/templates/social/pages/notifications.ts +73 -0
  329. package/templates/social/pages/post/[id].ts +124 -0
  330. package/templates/social/pages/profile/[username].ts +100 -0
  331. package/templates/social/pages/settings/accessibility.ts +153 -0
  332. package/templates/social/pages/settings/account.ts +260 -0
  333. package/templates/social/pages/settings/help.ts +141 -0
  334. package/templates/social/pages/settings/language.ts +103 -0
  335. package/templates/social/pages/settings/privacy.ts +183 -0
  336. package/templates/social/pages/settings/security.ts +133 -0
  337. package/templates/social/pages/settings.ts +185 -0
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Auto-create permission tables in the LumenJS SQLite database.
3
+ * Follows the same pattern as ensureUsersTable() in auth/native-auth.ts.
4
+ */
5
+ export async function ensurePermissionTables(db) {
6
+ if (db.isPg)
7
+ return;
8
+ await db.exec(`
9
+ CREATE TABLE IF NOT EXISTS _nk_resource_permissions (
10
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
11
+ resource_type TEXT NOT NULL,
12
+ resource_id TEXT NOT NULL,
13
+ grantee_type TEXT NOT NULL CHECK (grantee_type IN ('user', 'role', 'public', 'anonymous')),
14
+ grantee_id TEXT NOT NULL DEFAULT '',
15
+ permission TEXT NOT NULL,
16
+ granted_by TEXT,
17
+ expires_at TEXT,
18
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
19
+ UNIQUE(resource_type, resource_id, grantee_type, grantee_id, permission)
20
+ );
21
+
22
+ CREATE INDEX IF NOT EXISTS idx_nk_rp_resource
23
+ ON _nk_resource_permissions(resource_type, resource_id);
24
+ CREATE INDEX IF NOT EXISTS idx_nk_rp_grantee
25
+ ON _nk_resource_permissions(grantee_type, grantee_id);
26
+
27
+ CREATE TABLE IF NOT EXISTS _nk_roles (
28
+ id TEXT PRIMARY KEY,
29
+ name TEXT NOT NULL UNIQUE,
30
+ permissions TEXT NOT NULL DEFAULT '[]',
31
+ hierarchy INTEGER NOT NULL DEFAULT 0,
32
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
33
+ );
34
+
35
+ CREATE TABLE IF NOT EXISTS _nk_user_roles (
36
+ user_id TEXT NOT NULL,
37
+ role_id TEXT NOT NULL,
38
+ resource_type TEXT NOT NULL DEFAULT '',
39
+ resource_id TEXT NOT NULL DEFAULT '',
40
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
41
+ PRIMARY KEY (user_id, role_id, resource_type, resource_id)
42
+ );
43
+
44
+ CREATE INDEX IF NOT EXISTS idx_nk_ur_user
45
+ ON _nk_user_roles(user_id);
46
+
47
+ CREATE TABLE IF NOT EXISTS _nk_permission_audit_log (
48
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
49
+ action TEXT NOT NULL,
50
+ resource_type TEXT,
51
+ resource_id TEXT,
52
+ grantee_type TEXT,
53
+ grantee_id TEXT,
54
+ permission TEXT,
55
+ role_id TEXT,
56
+ actor_id TEXT NOT NULL,
57
+ details TEXT,
58
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
59
+ );
60
+
61
+ CREATE INDEX IF NOT EXISTS idx_nk_pal_resource
62
+ ON _nk_permission_audit_log(resource_type, resource_id);
63
+ CREATE INDEX IF NOT EXISTS idx_nk_pal_actor
64
+ ON _nk_permission_audit_log(actor_id);
65
+ CREATE INDEX IF NOT EXISTS idx_nk_pal_created
66
+ ON _nk_permission_audit_log(created_at);
67
+ `);
68
+ }
@@ -0,0 +1,33 @@
1
+ export interface ResourcePermission {
2
+ id: number;
3
+ resource_type: string;
4
+ resource_id: string;
5
+ grantee_type: 'user' | 'role' | 'public' | 'anonymous';
6
+ grantee_id: string | null;
7
+ permission: string;
8
+ granted_by: string | null;
9
+ expires_at: string | null;
10
+ created_at: string;
11
+ }
12
+ export interface Role {
13
+ id: string;
14
+ name: string;
15
+ permissions: string[];
16
+ hierarchy: number;
17
+ created_at: string;
18
+ }
19
+ export interface UserRole {
20
+ user_id: string;
21
+ role_id: string;
22
+ resource_type: string | null;
23
+ resource_id: string | null;
24
+ created_at: string;
25
+ }
26
+ export interface PermissionsConfig {
27
+ enabled?: boolean;
28
+ defaultOwnerGrants?: string[];
29
+ }
30
+ export interface ResolvedPermissionsConfig {
31
+ enabled: boolean;
32
+ defaultOwnerGrants: string[];
33
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,146 @@
1
1
  import { routes } from 'virtual:lumenjs-routes';
2
2
  import { NkRouter } from './router.js';
3
+ function getDefaultStrategy() {
4
+ const el = document.getElementById('__nk_prefetch__');
5
+ if (el) {
6
+ const val = el.textContent?.trim();
7
+ if (val === 'hover' || val === 'viewport' || val === 'none')
8
+ return val;
9
+ }
10
+ return 'hover';
11
+ }
12
+ function getAnchorHref(anchor) {
13
+ const href = anchor.getAttribute('href');
14
+ if (!href || href.startsWith('http') || href.startsWith('#') || anchor.hasAttribute('target'))
15
+ return null;
16
+ return href;
17
+ }
18
+ function getLinkStrategy(anchor, defaultStrategy) {
19
+ const override = anchor.dataset.prefetch;
20
+ if (override === 'hover' || override === 'viewport' || override === 'none')
21
+ return override;
22
+ return defaultStrategy;
23
+ }
24
+ function setupPrefetchObserver(defaultStrategy) {
25
+ const prefetched = new Set();
26
+ const doPrefetch = (href) => {
27
+ if (prefetched.has(href))
28
+ return;
29
+ prefetched.add(href);
30
+ const pf = window.__nk_prefetch;
31
+ if (pf)
32
+ pf(href);
33
+ };
34
+ // Hover strategy: event delegation on document
35
+ if (defaultStrategy === 'hover' || defaultStrategy === 'viewport') {
36
+ const onPointerEnter = (e) => {
37
+ const path = e.composedPath();
38
+ const anchor = path.find(el => el instanceof HTMLElement && el.tagName === 'A');
39
+ if (!anchor)
40
+ return;
41
+ const href = getAnchorHref(anchor);
42
+ if (!href)
43
+ return;
44
+ const strategy = getLinkStrategy(anchor, defaultStrategy);
45
+ if (strategy === 'none')
46
+ return;
47
+ if (strategy === 'hover')
48
+ doPrefetch(href);
49
+ };
50
+ document.addEventListener('pointerenter', onPointerEnter, true);
51
+ document.addEventListener('focusin', (e) => {
52
+ const target = e.target;
53
+ if (target instanceof HTMLAnchorElement) {
54
+ const href = getAnchorHref(target);
55
+ if (!href)
56
+ return;
57
+ const strategy = getLinkStrategy(target, defaultStrategy);
58
+ if (strategy === 'none')
59
+ return;
60
+ if (strategy === 'hover')
61
+ doPrefetch(href);
62
+ }
63
+ });
64
+ }
65
+ // Viewport strategy: IntersectionObserver for links
66
+ if (defaultStrategy === 'viewport') {
67
+ const observedLinks = new WeakSet();
68
+ const io = new IntersectionObserver((entries) => {
69
+ for (const entry of entries) {
70
+ if (!entry.isIntersecting)
71
+ continue;
72
+ const anchor = entry.target;
73
+ const href = getAnchorHref(anchor);
74
+ if (!href)
75
+ continue;
76
+ const strategy = getLinkStrategy(anchor, defaultStrategy);
77
+ if (strategy === 'none' || strategy === 'hover')
78
+ continue;
79
+ doPrefetch(href);
80
+ io.unobserve(anchor);
81
+ }
82
+ }, { rootMargin: '200px' });
83
+ const observeLinks = (root) => {
84
+ const anchors = root.querySelectorAll('a[href]');
85
+ for (const a of anchors) {
86
+ const anchor = a;
87
+ if (observedLinks.has(anchor))
88
+ continue;
89
+ const href = getAnchorHref(anchor);
90
+ if (!href)
91
+ continue;
92
+ const strategy = getLinkStrategy(anchor, defaultStrategy);
93
+ if (strategy !== 'viewport')
94
+ continue;
95
+ observedLinks.add(anchor);
96
+ io.observe(anchor);
97
+ }
98
+ // Walk shadow roots to find links inside web components
99
+ const els = root.querySelectorAll('*');
100
+ for (const el of els) {
101
+ if (el.shadowRoot)
102
+ observeLinks(el.shadowRoot);
103
+ }
104
+ };
105
+ const observeShadowRoot = (sr) => {
106
+ observeLinks(sr);
107
+ const smo = new MutationObserver(() => observeLinks(sr));
108
+ smo.observe(sr, { childList: true, subtree: true });
109
+ };
110
+ // Observe existing links after initial render (including shadow roots)
111
+ requestAnimationFrame(() => {
112
+ observeLinks(document);
113
+ // Also observe shadow roots of existing elements
114
+ document.querySelectorAll('*').forEach(el => {
115
+ if (el.shadowRoot)
116
+ observeShadowRoot(el.shadowRoot);
117
+ });
118
+ });
119
+ // Watch for dynamically added links and new shadow roots
120
+ const mo = new MutationObserver((mutations) => {
121
+ for (const mutation of mutations) {
122
+ for (const node of mutation.addedNodes) {
123
+ if (node instanceof HTMLElement) {
124
+ if (node.tagName === 'A') {
125
+ observeLinks(node.parentElement || document);
126
+ }
127
+ else {
128
+ observeLinks(node);
129
+ if (node.shadowRoot)
130
+ observeShadowRoot(node.shadowRoot);
131
+ }
132
+ // Check children for shadow roots
133
+ node.querySelectorAll?.('*').forEach(child => {
134
+ if (child.shadowRoot)
135
+ observeShadowRoot(child.shadowRoot);
136
+ });
137
+ }
138
+ }
139
+ }
140
+ });
141
+ mo.observe(document.body, { childList: true, subtree: true });
142
+ }
143
+ }
3
144
  /**
4
145
  * <nk-app> — The application shell. Sets up the router and renders pages.
5
146
  */
@@ -14,7 +155,29 @@ class NkApp extends HTMLElement {
14
155
  this.innerHTML = '<div id="nk-router-outlet"></div>';
15
156
  }
16
157
  const outlet = this.querySelector('#nk-router-outlet');
158
+ // Create route announcer for screen readers (WCAG 2.4.2)
159
+ const announcer = document.createElement('div');
160
+ announcer.id = 'nk-route-announcer';
161
+ announcer.setAttribute('aria-live', 'assertive');
162
+ announcer.setAttribute('aria-atomic', 'true');
163
+ announcer.setAttribute('role', 'status');
164
+ Object.assign(announcer.style, {
165
+ position: 'absolute',
166
+ width: '1px',
167
+ height: '1px',
168
+ padding: '0',
169
+ margin: '-1px',
170
+ overflow: 'hidden',
171
+ clip: 'rect(0,0,0,0)',
172
+ whiteSpace: 'nowrap',
173
+ border: '0',
174
+ });
175
+ this.appendChild(announcer);
17
176
  this.router = new NkRouter(routes, outlet, isSSR);
177
+ const strategy = getDefaultStrategy();
178
+ if (strategy !== 'none') {
179
+ setupPrefetchObserver(strategy);
180
+ }
18
181
  }
19
182
  }
20
183
  if (!customElements.get('nk-app')) {
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Client-side auth store — singleton following the i18n.ts pattern.
3
+ * Hydrated from __nk_auth__ script tag on page load.
4
+ */
5
+ export declare function getUser(): any;
6
+ export declare function isAuthenticated(): boolean;
7
+ export declare function hasRole(role: string): boolean;
8
+ export declare function initAuth(user: any): void;
9
+ export declare function login(returnTo?: string): void;
10
+ export declare function logout(): void;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Client-side auth store — singleton following the i18n.ts pattern.
3
+ * Hydrated from __nk_auth__ script tag on page load.
4
+ */
5
+ let currentUser = null;
6
+ let initialized = false;
7
+ export function getUser() {
8
+ return currentUser;
9
+ }
10
+ export function isAuthenticated() {
11
+ return currentUser !== null;
12
+ }
13
+ export function hasRole(role) {
14
+ return currentUser?.roles?.includes(role) ?? false;
15
+ }
16
+ export function initAuth(user) {
17
+ currentUser = user;
18
+ initialized = true;
19
+ }
20
+ export function login(returnTo) {
21
+ const url = new URL('/__nk_auth/login', location.origin);
22
+ if (returnTo)
23
+ url.searchParams.set('returnTo', returnTo);
24
+ location.href = url.toString();
25
+ }
26
+ export function logout() {
27
+ currentUser = null;
28
+ initialized = false;
29
+ location.href = '/__nk_auth/logout';
30
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Client-side communication SDK.
3
+ * Connects to the server via Socket.io and provides a clean API for chat, typing, and presence.
4
+ */
5
+ /**
6
+ * Connect to the communication socket.
7
+ * Must be called before using any other functions.
8
+ */
9
+ export declare function connectChat(params?: Record<string, string>): Promise<void>;
10
+ /** Join a conversation room to receive messages */
11
+ export declare function joinConversation(conversationId: string): void;
12
+ /** Leave a conversation room */
13
+ export declare function leaveConversation(conversationId: string): void;
14
+ /** Send a message */
15
+ export declare function sendMessage(conversationId: string, content: string, type?: string): void;
16
+ /** Mark a message as read */
17
+ export declare function markRead(conversationId: string, messageId: string): void;
18
+ /** React to a message with an emoji (toggle) */
19
+ export declare function reactToMessage(messageId: string, conversationId: string, emoji: string): void;
20
+ /** Edit a message */
21
+ export declare function editMessage(messageId: string, conversationId: string, content: string): void;
22
+ /** Delete a message */
23
+ export declare function deleteMessage(messageId: string, conversationId: string): void;
24
+ /** Listen for reaction updates */
25
+ export declare function onReactionUpdate(handler: (data: {
26
+ messageId: string;
27
+ reactions: any[];
28
+ }) => void): () => void;
29
+ /** Listen for message edits */
30
+ export declare function onMessageUpdated(handler: (data: {
31
+ messageId: string;
32
+ content: string;
33
+ updatedAt: string;
34
+ }) => void): () => void;
35
+ /** Listen for message deletions */
36
+ export declare function onMessageDeleted(handler: (data: {
37
+ messageId: string;
38
+ conversationId: string;
39
+ }) => void): () => void;
40
+ /** Upload a file (returns attachment metadata) */
41
+ export declare function uploadFile(file: Blob, filename: string, encrypted?: boolean): Promise<{
42
+ id: string;
43
+ url: string;
44
+ size: number;
45
+ }>;
46
+ /** Fetch link previews for a text */
47
+ export declare function fetchLinkPreviews(text: string): Promise<any[]>;
48
+ /** Start typing indicator */
49
+ export declare function startTyping(conversationId: string): void;
50
+ /** Stop typing indicator */
51
+ export declare function stopTyping(conversationId: string): void;
52
+ /** Update presence status */
53
+ export declare function updatePresence(status: 'online' | 'offline' | 'away' | 'busy'): void;
54
+ /** Listen for new messages */
55
+ export declare function onMessage(handler: (message: any) => void): () => void;
56
+ /** Listen for typing updates */
57
+ export declare function onTyping(handler: (data: {
58
+ conversationId: string;
59
+ userId: string;
60
+ isTyping: boolean;
61
+ }) => void): () => void;
62
+ /** Listen for presence changes */
63
+ export declare function onPresence(handler: (data: {
64
+ userId: string;
65
+ status: string;
66
+ lastSeen: string;
67
+ }) => void): () => void;
68
+ /** Listen for read receipts */
69
+ export declare function onReadReceipt(handler: (data: any) => void): () => void;
70
+ /** Listen for incoming calls */
71
+ export declare function onIncomingCall(handler: (call: any) => void): () => void;
72
+ /** Listen for call state changes (initiating, ringing, connecting, connected, ended) */
73
+ export declare function onCallStateChanged(handler: (data: {
74
+ callId: string;
75
+ state: string;
76
+ endReason?: string;
77
+ }) => void): () => void;
78
+ /** Listen for participants joining a call */
79
+ export declare function onParticipantJoined(handler: (data: {
80
+ callId: string;
81
+ participant: any;
82
+ }) => void): () => void;
83
+ /** Listen for participants leaving a call */
84
+ export declare function onParticipantLeft(handler: (data: {
85
+ callId: string;
86
+ userId: string;
87
+ }) => void): () => void;
88
+ /** Listen for media changes (mute/unmute/screenshare) */
89
+ export declare function onMediaChanged(handler: (data: {
90
+ callId: string;
91
+ userId: string;
92
+ audio?: boolean;
93
+ video?: boolean;
94
+ screenShare?: boolean;
95
+ }) => void): () => void;
96
+ /** Initiate an audio or video call */
97
+ export declare function initiateCall(conversationId: string, type: 'audio' | 'video', calleeIds: string[]): void;
98
+ /** Respond to an incoming call */
99
+ export declare function respondToCall(callId: string, action: 'accept' | 'reject'): void;
100
+ /** Hang up an active call */
101
+ export declare function hangup(callId: string, reason?: string): void;
102
+ /** Toggle audio/video/screenshare during a call */
103
+ export declare function toggleMedia(callId: string, opts: {
104
+ audio?: boolean;
105
+ video?: boolean;
106
+ screenShare?: boolean;
107
+ }): void;
108
+ /** Send SDP offer to a peer */
109
+ export declare function sendOffer(callId: string, toUserId: string, sdp: string): void;
110
+ /** Send SDP answer to a peer */
111
+ export declare function sendAnswer(callId: string, toUserId: string, sdp: string): void;
112
+ /** Send ICE candidate to a peer */
113
+ export declare function sendIceCandidate(callId: string, toUserId: string, candidate: string, sdpMLineIndex: number | null, sdpMid: string | null): void;
114
+ /** Listen for SDP offers from peers */
115
+ export declare function onSignalOffer(handler: (data: {
116
+ callId: string;
117
+ fromUserId: string;
118
+ sdp: string;
119
+ }) => void): () => void;
120
+ /** Listen for SDP answers from peers */
121
+ export declare function onSignalAnswer(handler: (data: {
122
+ callId: string;
123
+ fromUserId: string;
124
+ sdp: string;
125
+ }) => void): () => void;
126
+ /** Listen for ICE candidates from peers */
127
+ export declare function onIceCandidate(handler: (data: {
128
+ callId: string;
129
+ fromUserId: string;
130
+ candidate: string;
131
+ sdpMLineIndex: number | null;
132
+ sdpMid: string | null;
133
+ }) => void): () => void;
134
+ /** Disconnect from communication socket */
135
+ export declare function disconnect(): void;
136
+ /** Check if connected */
137
+ export declare function isConnected(): boolean;
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Client-side communication SDK.
3
+ * Connects to the server via Socket.io and provides a clean API for chat, typing, and presence.
4
+ */
5
+ let _socket = null;
6
+ let _handlers = new Map();
7
+ function emit(event, data) {
8
+ if (!_socket)
9
+ throw new Error('Communication not connected. Call connectChat() first.');
10
+ _socket.emit(`nk:${event}`, data);
11
+ }
12
+ function addHandler(event, handler) {
13
+ let set = _handlers.get(event);
14
+ if (!set) {
15
+ set = new Set();
16
+ _handlers.set(event, set);
17
+ }
18
+ set.add(handler);
19
+ }
20
+ function removeHandler(event, handler) {
21
+ _handlers.get(event)?.delete(handler);
22
+ }
23
+ /**
24
+ * Connect to the communication socket.
25
+ * Must be called before using any other functions.
26
+ */
27
+ export async function connectChat(params) {
28
+ if (_socket)
29
+ return;
30
+ const { io } = await import('socket.io-client');
31
+ _socket = io('/nk/messages', {
32
+ path: '/__nk_socketio/',
33
+ query: { ...params, __params: JSON.stringify(params || {}) },
34
+ });
35
+ _socket.on('nk:data', (data) => {
36
+ if (data?.event) {
37
+ const handlers = _handlers.get(data.event);
38
+ if (handlers) {
39
+ for (const h of handlers)
40
+ h(data.data);
41
+ }
42
+ }
43
+ });
44
+ }
45
+ /** Join a conversation room to receive messages */
46
+ export function joinConversation(conversationId) {
47
+ emit('conversation:join', { conversationId });
48
+ }
49
+ /** Leave a conversation room */
50
+ export function leaveConversation(conversationId) {
51
+ emit('conversation:leave', { conversationId });
52
+ }
53
+ /** Send a message */
54
+ export function sendMessage(conversationId, content, type = 'text') {
55
+ emit('message:send', { conversationId, content, type });
56
+ }
57
+ /** Mark a message as read */
58
+ export function markRead(conversationId, messageId) {
59
+ emit('message:read', { conversationId, messageId });
60
+ }
61
+ /** React to a message with an emoji (toggle) */
62
+ export function reactToMessage(messageId, conversationId, emoji) {
63
+ emit('message:react', { messageId, conversationId, emoji });
64
+ }
65
+ /** Edit a message */
66
+ export function editMessage(messageId, conversationId, content) {
67
+ emit('message:edit', { messageId, conversationId, content });
68
+ }
69
+ /** Delete a message */
70
+ export function deleteMessage(messageId, conversationId) {
71
+ emit('message:delete', { messageId, conversationId });
72
+ }
73
+ /** Listen for reaction updates */
74
+ export function onReactionUpdate(handler) {
75
+ addHandler('message:reaction-update', handler);
76
+ return () => removeHandler('message:reaction-update', handler);
77
+ }
78
+ /** Listen for message edits */
79
+ export function onMessageUpdated(handler) {
80
+ addHandler('message:updated', handler);
81
+ return () => removeHandler('message:updated', handler);
82
+ }
83
+ /** Listen for message deletions */
84
+ export function onMessageDeleted(handler) {
85
+ addHandler('message:deleted', handler);
86
+ return () => removeHandler('message:deleted', handler);
87
+ }
88
+ /** Upload a file (returns attachment metadata) */
89
+ export async function uploadFile(file, filename, encrypted = false) {
90
+ const res = await fetch('/__nk_comm/upload', {
91
+ method: 'POST',
92
+ headers: {
93
+ 'Content-Type': file.type || 'application/octet-stream',
94
+ 'X-Filename': filename,
95
+ ...(encrypted ? { 'X-Encrypted': '1' } : {}),
96
+ },
97
+ body: file,
98
+ });
99
+ if (!res.ok)
100
+ throw new Error(`Upload failed: ${res.status}`);
101
+ return res.json();
102
+ }
103
+ /** Fetch link previews for a text */
104
+ export async function fetchLinkPreviews(text) {
105
+ const res = await fetch('/__nk_comm/link-preview', {
106
+ method: 'POST',
107
+ headers: { 'Content-Type': 'application/json' },
108
+ body: JSON.stringify({ text }),
109
+ });
110
+ if (!res.ok)
111
+ return [];
112
+ const data = await res.json();
113
+ return data.previews || [];
114
+ }
115
+ /** Start typing indicator */
116
+ export function startTyping(conversationId) {
117
+ emit('typing:start', { conversationId });
118
+ }
119
+ /** Stop typing indicator */
120
+ export function stopTyping(conversationId) {
121
+ emit('typing:stop', { conversationId });
122
+ }
123
+ /** Update presence status */
124
+ export function updatePresence(status) {
125
+ emit('presence:update', { status });
126
+ }
127
+ /** Listen for new messages */
128
+ export function onMessage(handler) {
129
+ addHandler('message:new', handler);
130
+ return () => removeHandler('message:new', handler);
131
+ }
132
+ /** Listen for typing updates */
133
+ export function onTyping(handler) {
134
+ addHandler('typing:update', handler);
135
+ return () => removeHandler('typing:update', handler);
136
+ }
137
+ /** Listen for presence changes */
138
+ export function onPresence(handler) {
139
+ addHandler('presence:changed', handler);
140
+ return () => removeHandler('presence:changed', handler);
141
+ }
142
+ /** Listen for read receipts */
143
+ export function onReadReceipt(handler) {
144
+ addHandler('read-receipt:update', handler);
145
+ return () => removeHandler('read-receipt:update', handler);
146
+ }
147
+ // ── Calls ─────────────────────────────────────────────────────────
148
+ /** Listen for incoming calls */
149
+ export function onIncomingCall(handler) {
150
+ addHandler('call:incoming', handler);
151
+ return () => removeHandler('call:incoming', handler);
152
+ }
153
+ /** Listen for call state changes (initiating, ringing, connecting, connected, ended) */
154
+ export function onCallStateChanged(handler) {
155
+ addHandler('call:state-changed', handler);
156
+ return () => removeHandler('call:state-changed', handler);
157
+ }
158
+ /** Listen for participants joining a call */
159
+ export function onParticipantJoined(handler) {
160
+ addHandler('call:participant-joined', handler);
161
+ return () => removeHandler('call:participant-joined', handler);
162
+ }
163
+ /** Listen for participants leaving a call */
164
+ export function onParticipantLeft(handler) {
165
+ addHandler('call:participant-left', handler);
166
+ return () => removeHandler('call:participant-left', handler);
167
+ }
168
+ /** Listen for media changes (mute/unmute/screenshare) */
169
+ export function onMediaChanged(handler) {
170
+ addHandler('call:media-changed', handler);
171
+ return () => removeHandler('call:media-changed', handler);
172
+ }
173
+ /** Initiate an audio or video call */
174
+ export function initiateCall(conversationId, type, calleeIds) {
175
+ emit('call:initiate', { conversationId, type, calleeIds });
176
+ }
177
+ /** Respond to an incoming call */
178
+ export function respondToCall(callId, action) {
179
+ emit('call:respond', { callId, action });
180
+ }
181
+ /** Hang up an active call */
182
+ export function hangup(callId, reason = 'completed') {
183
+ emit('call:hangup', { callId, reason });
184
+ }
185
+ /** Toggle audio/video/screenshare during a call */
186
+ export function toggleMedia(callId, opts) {
187
+ emit('call:media-toggle', { callId, ...opts });
188
+ }
189
+ // ── WebRTC Signaling ──────────────────────────────────────────────
190
+ /** Send SDP offer to a peer */
191
+ export function sendOffer(callId, toUserId, sdp) {
192
+ emit('signal:offer', { callId, fromUserId: '', toUserId, type: 'offer', sdp });
193
+ }
194
+ /** Send SDP answer to a peer */
195
+ export function sendAnswer(callId, toUserId, sdp) {
196
+ emit('signal:answer', { callId, fromUserId: '', toUserId, type: 'answer', sdp });
197
+ }
198
+ /** Send ICE candidate to a peer */
199
+ export function sendIceCandidate(callId, toUserId, candidate, sdpMLineIndex, sdpMid) {
200
+ emit('signal:ice-candidate', { callId, fromUserId: '', toUserId, candidate, sdpMLineIndex, sdpMid });
201
+ }
202
+ /** Listen for SDP offers from peers */
203
+ export function onSignalOffer(handler) {
204
+ addHandler('signal:offer', handler);
205
+ return () => removeHandler('signal:offer', handler);
206
+ }
207
+ /** Listen for SDP answers from peers */
208
+ export function onSignalAnswer(handler) {
209
+ addHandler('signal:answer', handler);
210
+ return () => removeHandler('signal:answer', handler);
211
+ }
212
+ /** Listen for ICE candidates from peers */
213
+ export function onIceCandidate(handler) {
214
+ addHandler('signal:ice-candidate', handler);
215
+ return () => removeHandler('signal:ice-candidate', handler);
216
+ }
217
+ /** Disconnect from communication socket */
218
+ export function disconnect() {
219
+ if (_socket) {
220
+ _socket.disconnect();
221
+ _socket = null;
222
+ _handlers.clear();
223
+ }
224
+ }
225
+ /** Check if connected */
226
+ export function isConnected() {
227
+ return _socket?.connected ?? false;
228
+ }