@kyro-cms/admin 0.1.2 → 0.1.3

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 (58) hide show
  1. package/package.json +17 -6
  2. package/src/components/Admin.tsx +50 -1
  3. package/src/components/LoginPage.tsx +223 -0
  4. package/src/components/layout/Sidebar.tsx +35 -0
  5. package/src/index.ts +35 -0
  6. package/src/middleware.ts +2 -0
  7. package/src/pages/api/auth/register.ts +133 -0
  8. package/src/styles/main.css +148 -0
  9. package/.astro/content.d.ts +0 -154
  10. package/.astro/settings.json +0 -5
  11. package/.astro/types.d.ts +0 -2
  12. package/astro.config.mjs +0 -28
  13. package/bun.lock +0 -1374
  14. package/dist/client/_astro/AdminLayout.DkDpng53.css +0 -1
  15. package/dist/client/_astro/AutoForm.3eJCmCJp.js +0 -1
  16. package/dist/client/_astro/client.DyczpTbx.js +0 -9
  17. package/dist/client/_astro/index.B02hbnpo.js +0 -1
  18. package/dist/client/fonts/Serotiva-Black.woff2 +0 -0
  19. package/dist/client/fonts/Serotiva-Bold.woff2 +0 -0
  20. package/dist/client/fonts/Serotiva-Medium.woff2 +0 -0
  21. package/dist/client/fonts/Serotiva-Regular.woff2 +0 -0
  22. package/dist/client/fonts/Serotiva-SemiBold.woff2 +0 -0
  23. package/dist/server/chunks/AdminLayout_D-_JeUqC.mjs +0 -26
  24. package/dist/server/chunks/_id__BzI_o0qT.mjs +0 -50
  25. package/dist/server/chunks/_id__Cd-jOuY3.mjs +0 -238
  26. package/dist/server/chunks/_id__DvbD--iR.mjs +0 -992
  27. package/dist/server/chunks/_id__vpVaEo16.mjs +0 -128
  28. package/dist/server/chunks/_virtual_astro_server-island-manifest_CQQ1F5PF.mjs +0 -7
  29. package/dist/server/chunks/_virtual_astro_session-driver_Bk3Q189E.mjs +0 -4
  30. package/dist/server/chunks/astro-component_Dbx3T2Nh.mjs +0 -37
  31. package/dist/server/chunks/audit-logs_DrnUMRvY.mjs +0 -74
  32. package/dist/server/chunks/config_CPXslElD.mjs +0 -4221
  33. package/dist/server/chunks/dataStore_Dl7cA2Qp.mjs +0 -89
  34. package/dist/server/chunks/index_CVqOkerS.mjs +0 -2960
  35. package/dist/server/chunks/index_CX8SQ4BF.mjs +0 -55
  36. package/dist/server/chunks/index_CYofDU51.mjs +0 -58
  37. package/dist/server/chunks/index_DdNRhuaM.mjs +0 -55
  38. package/dist/server/chunks/index_DupPvtIF.mjs +0 -42
  39. package/dist/server/chunks/index_YTS_M-B9.mjs +0 -263
  40. package/dist/server/chunks/index_YeCzuVps.mjs +0 -53
  41. package/dist/server/chunks/login_DLyqMRO8.mjs +0 -93
  42. package/dist/server/chunks/logout_CSbt5wea.mjs +0 -50
  43. package/dist/server/chunks/me_C04jlYhH.mjs +0 -41
  44. package/dist/server/chunks/new_BbQ9b55M.mjs +0 -92
  45. package/dist/server/chunks/node_9bvTewss.mjs +0 -1014
  46. package/dist/server/chunks/noop-entrypoint_BOlrdqWF.mjs +0 -3
  47. package/dist/server/chunks/sequence_9cl7AJy-.mjs +0 -2503
  48. package/dist/server/chunks/server_peBx9VXG.mjs +0 -8117
  49. package/dist/server/chunks/sharp_pmJ7nHES.mjs +0 -142
  50. package/dist/server/chunks/users_Dzddy_YR.mjs +0 -137
  51. package/dist/server/entry.mjs +0 -5
  52. package/dist/server/virtual_astro_middleware.mjs +0 -48
  53. package/public/fonts/Serotiva-Black.woff2 +0 -0
  54. package/public/fonts/Serotiva-Bold.woff2 +0 -0
  55. package/public/fonts/Serotiva-Medium.woff2 +0 -0
  56. package/public/fonts/Serotiva-Regular.woff2 +0 -0
  57. package/public/fonts/Serotiva-SemiBold.woff2 +0 -0
  58. package/tsconfig.json +0 -12
@@ -1,142 +0,0 @@
1
- import { A as AstroError, bf as MissingSharp } from './sequence_9cl7AJy-.mjs';
2
- import { b as baseService, p as parseQuality } from './node_9bvTewss.mjs';
3
-
4
- let sharp;
5
- const qualityTable = {
6
- low: 25,
7
- mid: 50,
8
- high: 80,
9
- max: 100
10
- };
11
- function resolveSharpQuality(quality) {
12
- if (!quality) return void 0;
13
- const parsedQuality = parseQuality(quality);
14
- if (typeof parsedQuality === "number") {
15
- return parsedQuality;
16
- }
17
- return quality in qualityTable ? qualityTable[quality] : void 0;
18
- }
19
- function resolveSharpEncoderOptions(transform, inputFormat, serviceConfig = {}) {
20
- const quality = resolveSharpQuality(transform.quality);
21
- switch (transform.format) {
22
- case "jpg":
23
- case "jpeg":
24
- return {
25
- ...serviceConfig.jpeg,
26
- ...quality === void 0 ? {} : { quality }
27
- };
28
- case "png":
29
- return {
30
- ...serviceConfig.png,
31
- ...quality === void 0 ? {} : { quality }
32
- };
33
- case "webp": {
34
- const webpOptions = {
35
- ...serviceConfig.webp,
36
- ...quality === void 0 ? {} : { quality }
37
- };
38
- if (inputFormat === "gif") {
39
- webpOptions.loop ??= 0;
40
- }
41
- return webpOptions;
42
- }
43
- case "avif":
44
- return {
45
- ...serviceConfig.avif,
46
- ...quality === void 0 ? {} : { quality }
47
- };
48
- default:
49
- return quality === void 0 ? void 0 : { quality };
50
- }
51
- }
52
- async function loadSharp() {
53
- let sharpImport;
54
- try {
55
- sharpImport = (await import('sharp')).default;
56
- } catch {
57
- throw new AstroError(MissingSharp);
58
- }
59
- sharpImport.cache(false);
60
- return sharpImport;
61
- }
62
- const fitMap = {
63
- fill: "fill",
64
- contain: "inside",
65
- cover: "cover",
66
- none: "outside",
67
- "scale-down": "inside",
68
- outside: "outside",
69
- inside: "inside"
70
- };
71
- const sharpService = {
72
- validateOptions: baseService.validateOptions,
73
- getURL: baseService.getURL,
74
- parseURL: baseService.parseURL,
75
- getHTMLAttributes: baseService.getHTMLAttributes,
76
- getSrcSet: baseService.getSrcSet,
77
- getRemoteSize: baseService.getRemoteSize,
78
- async transform(inputBuffer, transformOptions, config) {
79
- if (!sharp) sharp = await loadSharp();
80
- const transform = transformOptions;
81
- const kernel = config.service.config.kernel;
82
- if (transform.format === "svg") return { data: inputBuffer, format: "svg" };
83
- const result = sharp(inputBuffer, {
84
- failOnError: false,
85
- pages: -1,
86
- limitInputPixels: config.service.config.limitInputPixels
87
- });
88
- result.rotate();
89
- const { format } = await result.metadata();
90
- if (transform.width && transform.height) {
91
- const fit = transform.fit ? fitMap[transform.fit] ?? "inside" : void 0;
92
- result.resize({
93
- width: Math.round(transform.width),
94
- height: Math.round(transform.height),
95
- kernel,
96
- fit,
97
- position: transform.position,
98
- withoutEnlargement: true
99
- });
100
- } else if (transform.height && !transform.width) {
101
- result.resize({
102
- height: Math.round(transform.height),
103
- withoutEnlargement: true,
104
- kernel
105
- });
106
- } else if (transform.width) {
107
- result.resize({
108
- width: Math.round(transform.width),
109
- withoutEnlargement: true,
110
- kernel
111
- });
112
- }
113
- if (transform.background) {
114
- result.flatten({ background: transform.background });
115
- }
116
- if (transform.format) {
117
- const encoderOptions = resolveSharpEncoderOptions(transform, format, config.service.config);
118
- if (transform.format === "webp" && format === "gif") {
119
- result.webp(encoderOptions);
120
- } else if (transform.format === "webp") {
121
- result.webp(encoderOptions);
122
- } else if (transform.format === "png") {
123
- result.png(encoderOptions);
124
- } else if (transform.format === "avif") {
125
- result.avif(encoderOptions);
126
- } else if (transform.format === "jpeg" || transform.format === "jpg") {
127
- result.jpeg(encoderOptions);
128
- } else {
129
- result.toFormat(transform.format, encoderOptions);
130
- }
131
- }
132
- const { data, info } = await result.toBuffer({ resolveWithObject: true });
133
- const needsCopy = "buffer" in data && data.buffer instanceof SharedArrayBuffer;
134
- return {
135
- data: needsCopy ? new Uint8Array(data) : data,
136
- format: info.format
137
- };
138
- }
139
- };
140
- var sharp_default = sharpService;
141
-
142
- export { sharp_default as default, resolveSharpEncoderOptions };
@@ -1,137 +0,0 @@
1
- import { RedisAuthAdapter, createAuditContext, AuditLogger } from './index_CVqOkerS.mjs';
2
- import bcrypt from 'bcryptjs';
3
-
4
- const redisAdapter = new RedisAuthAdapter({
5
- url: process.env.REDIS_URL || "redis://localhost:6379"
6
- });
7
- const auditLogger = new AuditLogger(redisAdapter);
8
- async function ensureConnection() {
9
- try {
10
- await redisAdapter.connect();
11
- } catch (e) {
12
- }
13
- }
14
- const GET = async ({ url, request }) => {
15
- await ensureConnection();
16
- const page = parseInt(url.searchParams.get("page") || "1");
17
- const limit = parseInt(url.searchParams.get("limit") || "25");
18
- const search = url.searchParams.get("search") || "";
19
- try {
20
- const pattern = search ? `*${search.toLowerCase()}*` : "*";
21
- let cursor = "0";
22
- const users = [];
23
- const seenIds = /* @__PURE__ */ new Set();
24
- do {
25
- const [nextCursor, keys] = await redisAdapter.redis.scan(
26
- cursor,
27
- "MATCH",
28
- "kyro:auth:users:email:*",
29
- "COUNT",
30
- 100
31
- );
32
- cursor = nextCursor;
33
- for (const key of keys) {
34
- const userId = await redisAdapter.redis.get(key);
35
- if (userId && !seenIds.has(userId)) {
36
- seenIds.add(userId);
37
- const user = await redisAdapter.findUserById(userId);
38
- if (user) {
39
- const { passwordHash, ...safeUser } = user;
40
- users.push(safeUser);
41
- }
42
- }
43
- }
44
- } while (cursor !== "0");
45
- const totalDocs = users.length;
46
- const startIndex = (page - 1) * limit;
47
- const paginatedUsers = users.slice(startIndex, startIndex + limit);
48
- return new Response(
49
- JSON.stringify({
50
- docs: paginatedUsers,
51
- totalDocs,
52
- page,
53
- limit,
54
- totalPages: Math.ceil(totalDocs / limit)
55
- }),
56
- {
57
- status: 200,
58
- headers: { "Content-Type": "application/json" }
59
- }
60
- );
61
- } catch (error) {
62
- console.error("Error fetching users:", error);
63
- return new Response(
64
- JSON.stringify({
65
- error: "Failed to fetch users",
66
- docs: [],
67
- totalDocs: 0
68
- }),
69
- {
70
- status: 200,
71
- headers: { "Content-Type": "application/json" }
72
- }
73
- );
74
- }
75
- };
76
- const POST = async ({ request }) => {
77
- await ensureConnection();
78
- const { ipAddress, userAgent } = createAuditContext(request);
79
- try {
80
- const body = await request.json();
81
- const { email, password, role, tenantId } = body;
82
- if (!email || !password) {
83
- return new Response(
84
- JSON.stringify({ error: "Email and password are required" }),
85
- {
86
- status: 400,
87
- headers: { "Content-Type": "application/json" }
88
- }
89
- );
90
- }
91
- const existing = await redisAdapter.findUserByEmail(email);
92
- if (existing) {
93
- return new Response(JSON.stringify({ error: "Email already exists" }), {
94
- status: 400,
95
- headers: { "Content-Type": "application/json" }
96
- });
97
- }
98
- const passwordHash = await bcrypt.hash(password, 12);
99
- const user = await redisAdapter.createUser({
100
- email,
101
- passwordHash,
102
- role: role || "customer",
103
- tenantId
104
- });
105
- await auditLogger.log({
106
- action: "user_create",
107
- userId: user.id,
108
- userEmail: user.email,
109
- role: user.role,
110
- resource: "users",
111
- ipAddress,
112
- userAgent,
113
- success: true
114
- });
115
- const { passwordHash: _, ...safeUser } = user;
116
- return new Response(JSON.stringify({ data: safeUser }), {
117
- status: 201,
118
- headers: { "Content-Type": "application/json" }
119
- });
120
- } catch (error) {
121
- console.error("Error creating user:", error);
122
- return new Response(JSON.stringify({ error: "Failed to create user" }), {
123
- status: 500,
124
- headers: { "Content-Type": "application/json" }
125
- });
126
- }
127
- };
128
-
129
- const _page = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
130
- __proto__: null,
131
- GET,
132
- POST
133
- }, Symbol.toStringTag, { value: 'Module' }));
134
-
135
- const page = () => _page;
136
-
137
- export { page };
@@ -1,5 +0,0 @@
1
- export { h as handler, o as options, b as startServer } from './chunks/server_peBx9VXG.mjs';
2
- import './chunks/sequence_9cl7AJy-.mjs';
3
- import 'piccolore';
4
- import 'es-module-lexer';
5
- import 'clsx';
@@ -1,48 +0,0 @@
1
- import jwt from 'jsonwebtoken';
2
- import { ag as sequence } from './chunks/sequence_9cl7AJy-.mjs';
3
-
4
- const JWT_SECRET = process.env.JWT_SECRET || "change-me-in-production";
5
- const PUBLIC_PATHS = [
6
- "/api/auth/login",
7
- "/api/auth/logout",
8
- "/api/auth/me",
9
- "/api/health",
10
- "/favicon.svg"
11
- ];
12
- const PUBLIC_PREFIXES = ["/api/collections/", "/api/auth/"];
13
- const onRequest$1 = async ({ request, url }, next) => {
14
- const pathname = new URL(url).pathname;
15
- if (PUBLIC_PATHS.includes(pathname)) {
16
- return next();
17
- }
18
- for (const prefix of PUBLIC_PREFIXES) {
19
- if (pathname.startsWith(prefix)) {
20
- return next();
21
- }
22
- }
23
- const authHeader = request.headers.get("authorization");
24
- const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
25
- if (!token) {
26
- return new Response(JSON.stringify({ error: "Authentication required" }), {
27
- status: 401,
28
- headers: { "Content-Type": "application/json" }
29
- });
30
- }
31
- try {
32
- const payload = jwt.verify(token, JWT_SECRET);
33
- return next();
34
- } catch {
35
- return new Response(JSON.stringify({ error: "Invalid or expired token" }), {
36
- status: 401,
37
- headers: { "Content-Type": "application/json" }
38
- });
39
- }
40
- };
41
-
42
- const onRequest = sequence(
43
-
44
- onRequest$1
45
-
46
- );
47
-
48
- export { onRequest };
Binary file
Binary file
Binary file
Binary file
package/tsconfig.json DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "extends": "astro/tsconfigs/strict",
3
- "compilerOptions": {
4
- "jsx": "react-jsx",
5
- "jsxImportSource": "react",
6
- "baseUrl": ".",
7
- "paths": {
8
- "@/*": ["src/*"],
9
- "@kyro-cms/core": ["../src"]
10
- }
11
- }
12
- }