@strapi-community/plugin-better-auth-dashboard 1.0.0-alpha.6 → 1.0.0-alpha.7
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.
- package/README.md +101 -0
- package/dist/admin/{Root-BgL9lcCN.js → Root-BUuPFmkA.js} +61 -26
- package/dist/admin/Root-BUuPFmkA.js.map +1 -0
- package/dist/admin/{Root-BHQUxF7-.mjs → Root-Rol-uNmC.mjs} +61 -26
- package/dist/admin/Root-Rol-uNmC.mjs.map +1 -0
- package/dist/admin/{index-DY_8hwEC.js → index-CYaQ-gs-.js} +25 -1
- package/dist/admin/index-CYaQ-gs-.js.map +1 -0
- package/dist/admin/{index-DS5B1Klk.mjs → index-Y9SjzGQY.mjs} +25 -1
- package/dist/admin/index-Y9SjzGQY.mjs.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/index.mjs +2 -1
- package/dist/admin/index.mjs.map +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/index.mjs +1 -0
- package/dist/server/index.mjs.map +1 -0
- package/package.json +1 -1
|
@@ -39,6 +39,23 @@ const PluginIcon = ({
|
|
|
39
39
|
);
|
|
40
40
|
};
|
|
41
41
|
const PLUGIN_ID = "better-auth-dashboard";
|
|
42
|
+
const panels = [];
|
|
43
|
+
function addEditViewSidePanel(config) {
|
|
44
|
+
if (panels.some((p) => p.id === config.id)) {
|
|
45
|
+
console.warn(
|
|
46
|
+
`[better-auth-dashboard] Panel with id "${config.id}" is already registered.`
|
|
47
|
+
);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
panels.push(config);
|
|
51
|
+
}
|
|
52
|
+
function getEditViewSidePanels(model) {
|
|
53
|
+
return panels.filter((p) => {
|
|
54
|
+
if (!p.model) return true;
|
|
55
|
+
if (Array.isArray(p.model)) return p.model.includes(model);
|
|
56
|
+
return p.model === model;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
42
59
|
function captureApp(app) {
|
|
43
60
|
window.__betterAuthDashApp = app;
|
|
44
61
|
}
|
|
@@ -48,6 +65,11 @@ function getMediaLibraryComponent() {
|
|
|
48
65
|
const index = {
|
|
49
66
|
register(app) {
|
|
50
67
|
captureApp(app);
|
|
68
|
+
app.registerPlugin({
|
|
69
|
+
id: PLUGIN_ID,
|
|
70
|
+
name: "Auth Dashboard",
|
|
71
|
+
apis: { addEditViewSidePanel }
|
|
72
|
+
});
|
|
51
73
|
app.addMenuLink({
|
|
52
74
|
to: `/plugins/${PLUGIN_ID}`,
|
|
53
75
|
icon: PluginIcon,
|
|
@@ -55,12 +77,14 @@ const index = {
|
|
|
55
77
|
id: `${PLUGIN_ID}.plugin.name`,
|
|
56
78
|
defaultMessage: "Auth Dashboard"
|
|
57
79
|
},
|
|
58
|
-
Component: async () => Promise.resolve().then(() => require("./Root-
|
|
80
|
+
Component: async () => Promise.resolve().then(() => require("./Root-BUuPFmkA.js"))
|
|
59
81
|
});
|
|
60
82
|
},
|
|
61
83
|
bootstrap() {
|
|
62
84
|
}
|
|
63
85
|
};
|
|
64
86
|
exports.PluginIcon = PluginIcon;
|
|
87
|
+
exports.getEditViewSidePanels = getEditViewSidePanels;
|
|
65
88
|
exports.getMediaLibraryComponent = getMediaLibraryComponent;
|
|
66
89
|
exports.index = index;
|
|
90
|
+
//# sourceMappingURL=index-CYaQ-gs-.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CYaQ-gs-.js","sources":["../../admin/src/components/PluginIcon.tsx","../../admin/src/pluginId.ts","../../admin/src/utils/editViewPanelRegistry.ts","../../admin/src/utils/strapiApp.ts","../../admin/src/index.ts"],"sourcesContent":["export const PluginIcon = ({\n size = 16,\n background = 'transparent',\n opacity = 1,\n rotation = 0,\n shadow = 0,\n flipHorizontal = false,\n flipVertical = false,\n padding = 0\n}) => {\n const transforms = [];\n if (rotation !== 0) transforms.push(`rotate(${rotation}deg)`);\n if (flipHorizontal) transforms.push('scaleX(-1)');\n if (flipVertical) transforms.push('scaleY(-1)');\n\n const viewBoxSize = 24 + (padding * 2);\n const viewBoxOffset = -padding;\n const viewBox = `${viewBoxOffset} ${viewBoxOffset} ${viewBoxSize} ${viewBoxSize}`;\n\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox={viewBox}\n width={size}\n height={size}\n fill=\"none\"\n style={{\n opacity,\n transform: transforms.join(' ') || undefined,\n filter: shadow > 0 ? `drop-shadow(0 ${shadow}px ${shadow * 2}px rgba(0,0,0,0.3))` : undefined,\n backgroundColor: background !== 'transparent' ? background : undefined\n }}\n >\n <title>Better Auth Logo</title>\n <path fill=\"currentColor\" d=\"M0 3.39v17.22h5.783v-5.55h6.434V8.939H5.783V3.39Zm12.217 5.55h5.638v6.122h-5.638v5.548H24V3.391H12.217Z\"/>\n </svg>\n );\n};\n","export const PLUGIN_ID = \"better-auth-dashboard\";\n","import type React from \"react\";\n\nexport interface EditViewPanelProps {\n model: string;\n documentId?: string;\n // biome-ignore lint/suspicious/noExplicitAny: document shape varies by entity type\n document?: Record<string, any>;\n}\n\nexport interface EditViewPanelConfig {\n id: string;\n title: string;\n /** Restrict to specific model(s). Omit to show in all edit views. */\n model?: string | string[];\n Component: React.ComponentType<EditViewPanelProps>;\n}\n\nconst panels: EditViewPanelConfig[] = [];\n\nexport function addEditViewSidePanel(config: EditViewPanelConfig): void {\n if (panels.some((p) => p.id === config.id)) {\n console.warn(\n `[better-auth-dashboard] Panel with id \"${config.id}\" is already registered.`,\n );\n return;\n }\n panels.push(config);\n}\n\nexport function getEditViewSidePanels(model: string): EditViewPanelConfig[] {\n return panels.filter((p) => {\n if (!p.model) return true;\n if (Array.isArray(p.model)) return p.model.includes(model);\n return p.model === model;\n });\n}\n","import type { ComponentType } from \"react\";\n\nexport interface StrapiMediaFile {\n id: number;\n name: string;\n url: string;\n formats?: Record<string, { url: string }> | null;\n alternativeText?: string | null;\n}\n\nexport interface MediaLibraryDialogProps {\n onClose: () => void;\n onSelectAssets: (assets: StrapiMediaFile[]) => void;\n allowedTypes?: Array<\"files\" | \"images\" | \"videos\" | \"audios\">;\n multiple?: boolean;\n}\n\ninterface AppBridge {\n library: {\n components: {\n \"media-library\"?: ComponentType<MediaLibraryDialogProps>;\n };\n };\n}\n\ndeclare global {\n interface Window {\n __betterAuthDashApp?: AppBridge;\n }\n}\n\nexport function captureApp(app: AppBridge) {\n window.__betterAuthDashApp = app;\n}\n\nexport function getMediaLibraryComponent(): ComponentType<MediaLibraryDialogProps> | null {\n return (\n window.__betterAuthDashApp?.library?.components?.[\"media-library\"] ?? null\n );\n}\n","import { PluginIcon } from \"./components/PluginIcon\";\nimport { PLUGIN_ID } from \"./pluginId\";\nimport { addEditViewSidePanel } from \"./utils/editViewPanelRegistry\";\nimport { captureApp } from \"./utils/strapiApp\";\n\nexport default {\n register(app: {\n addMenuLink: (config: {\n to: string;\n icon: React.ComponentType;\n intlLabel: { id: string; defaultMessage: string };\n Component: () => Promise<{ default: React.ComponentType }>;\n }) => void;\n router: {\n addRoute: (config: {\n path: string;\n Component: () => Promise<{ default: React.ComponentType }>;\n }) => void;\n };\n // biome-ignore lint/suspicious/noExplicitAny: Strapi app bridge type\n library: any;\n registerPlugin: (config: {\n id: string;\n name: string;\n // biome-ignore lint/suspicious/noExplicitAny: plugin API shape is open-ended\n apis: Record<string, any>;\n }) => void;\n }) {\n captureApp(app);\n\n app.registerPlugin({\n id: PLUGIN_ID,\n name: \"Auth Dashboard\",\n apis: { addEditViewSidePanel },\n });\n\n app.addMenuLink({\n to: `/plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: \"Auth Dashboard\",\n },\n Component: async () => import(\"./pages/Root\"),\n });\n\n // app.router.addRoute({\n // path: `/plugins/${PLUGIN_ID}`,\n // Component: async () => import(\"./pages/Root\"),\n // });\n },\n\n bootstrap() {},\n};\n"],"names":["jsxs","jsx"],"mappings":";;AAAO,MAAM,aAAa,CAAC;AAAA,EACzB,OAAO;AAAA,EACP,aAAa;AAAA,EACb,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,UAAU;AACZ,MAAM;AACJ,QAAM,aAAa,CAAA;AACnB,MAAI,aAAa,EAAG,YAAW,KAAK,UAAU,QAAQ,MAAM;AAC5D,MAAI,eAAgB,YAAW,KAAK,YAAY;AAChD,MAAI,aAAc,YAAW,KAAK,YAAY;AAE9C,QAAM,cAAc,KAAM,UAAU;AACpC,QAAM,gBAAgB,CAAC;AACvB,QAAM,UAAU,GAAG,aAAa,IAAI,aAAa,IAAI,WAAW,IAAI,WAAW;AAE/E,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAM;AAAA,MACN;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAO;AAAA,QACL;AAAA,QACA,WAAW,WAAW,KAAK,GAAG,KAAK;AAAA,QACnC,QAAQ,SAAS,IAAI,iBAAiB,MAAM,MAAM,SAAS,CAAC,wBAAwB;AAAA,QACpF,iBAAiB,eAAe,gBAAgB,aAAa;AAAA,MAAA;AAAA,MAG/D,UAAA;AAAA,QAAAC,2BAAAA,IAAC,WAAM,UAAA,mBAAA,CAAgB;AAAA,QACvBA,2BAAAA,IAAC,QAAA,EAAK,MAAK,gBAAe,GAAE,0GAAA,CAAyG;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG3I;ACrCO,MAAM,YAAY;ACiBzB,MAAM,SAAgC,CAAA;AAE/B,SAAS,qBAAqB,QAAmC;AACtE,MAAI,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,EAAE,GAAG;AAC1C,YAAQ;AAAA,MACN,0CAA0C,OAAO,EAAE;AAAA,IAAA;AAErD;AAAA,EACF;AACA,SAAO,KAAK,MAAM;AACpB;AAEO,SAAS,sBAAsB,OAAsC;AAC1E,SAAO,OAAO,OAAO,CAAC,MAAM;AAC1B,QAAI,CAAC,EAAE,MAAO,QAAO;AACrB,QAAI,MAAM,QAAQ,EAAE,KAAK,EAAG,QAAO,EAAE,MAAM,SAAS,KAAK;AACzD,WAAO,EAAE,UAAU;AAAA,EACrB,CAAC;AACH;ACJO,SAAS,WAAW,KAAgB;AACzC,SAAO,sBAAsB;AAC/B;AAEO,SAAS,2BAA0E;AACxF,SACE,OAAO,qBAAqB,SAAS,aAAa,eAAe,KAAK;AAE1E;AClCA,MAAA,QAAe;AAAA,EACb,SAAS,KAqBN;AACD,eAAW,GAAG;AAEd,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,MAAM,EAAE,qBAAA;AAAA,IAAqB,CAC9B;AAED,QAAI,YAAY;AAAA,MACd,IAAI,YAAY,SAAS;AAAA,MACzB,MAAM;AAAA,MACN,WAAW;AAAA,QACT,IAAI,GAAG,SAAS;AAAA,QAChB,gBAAgB;AAAA,MAAA;AAAA,MAElB,WAAW,YAAY,QAAA,QAAA,EAAA,KAAA,MAAA,QAAO,oBAAc,CAAA;AAAA,IAAA,CAC7C;AAAA,EAMH;AAAA,EAEA,YAAY;AAAA,EAAC;AACf;;;;;"}
|
|
@@ -38,6 +38,23 @@ const PluginIcon = ({
|
|
|
38
38
|
);
|
|
39
39
|
};
|
|
40
40
|
const PLUGIN_ID = "better-auth-dashboard";
|
|
41
|
+
const panels = [];
|
|
42
|
+
function addEditViewSidePanel(config) {
|
|
43
|
+
if (panels.some((p) => p.id === config.id)) {
|
|
44
|
+
console.warn(
|
|
45
|
+
`[better-auth-dashboard] Panel with id "${config.id}" is already registered.`
|
|
46
|
+
);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
panels.push(config);
|
|
50
|
+
}
|
|
51
|
+
function getEditViewSidePanels(model) {
|
|
52
|
+
return panels.filter((p) => {
|
|
53
|
+
if (!p.model) return true;
|
|
54
|
+
if (Array.isArray(p.model)) return p.model.includes(model);
|
|
55
|
+
return p.model === model;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
41
58
|
function captureApp(app) {
|
|
42
59
|
window.__betterAuthDashApp = app;
|
|
43
60
|
}
|
|
@@ -47,6 +64,11 @@ function getMediaLibraryComponent() {
|
|
|
47
64
|
const index = {
|
|
48
65
|
register(app) {
|
|
49
66
|
captureApp(app);
|
|
67
|
+
app.registerPlugin({
|
|
68
|
+
id: PLUGIN_ID,
|
|
69
|
+
name: "Auth Dashboard",
|
|
70
|
+
apis: { addEditViewSidePanel }
|
|
71
|
+
});
|
|
50
72
|
app.addMenuLink({
|
|
51
73
|
to: `/plugins/${PLUGIN_ID}`,
|
|
52
74
|
icon: PluginIcon,
|
|
@@ -54,7 +76,7 @@ const index = {
|
|
|
54
76
|
id: `${PLUGIN_ID}.plugin.name`,
|
|
55
77
|
defaultMessage: "Auth Dashboard"
|
|
56
78
|
},
|
|
57
|
-
Component: async () => import("./Root-
|
|
79
|
+
Component: async () => import("./Root-Rol-uNmC.mjs")
|
|
58
80
|
});
|
|
59
81
|
},
|
|
60
82
|
bootstrap() {
|
|
@@ -62,6 +84,8 @@ const index = {
|
|
|
62
84
|
};
|
|
63
85
|
export {
|
|
64
86
|
PluginIcon as P,
|
|
87
|
+
getEditViewSidePanels as a,
|
|
65
88
|
getMediaLibraryComponent as g,
|
|
66
89
|
index as i
|
|
67
90
|
};
|
|
91
|
+
//# sourceMappingURL=index-Y9SjzGQY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-Y9SjzGQY.mjs","sources":["../../admin/src/components/PluginIcon.tsx","../../admin/src/pluginId.ts","../../admin/src/utils/editViewPanelRegistry.ts","../../admin/src/utils/strapiApp.ts","../../admin/src/index.ts"],"sourcesContent":["export const PluginIcon = ({\n size = 16,\n background = 'transparent',\n opacity = 1,\n rotation = 0,\n shadow = 0,\n flipHorizontal = false,\n flipVertical = false,\n padding = 0\n}) => {\n const transforms = [];\n if (rotation !== 0) transforms.push(`rotate(${rotation}deg)`);\n if (flipHorizontal) transforms.push('scaleX(-1)');\n if (flipVertical) transforms.push('scaleY(-1)');\n\n const viewBoxSize = 24 + (padding * 2);\n const viewBoxOffset = -padding;\n const viewBox = `${viewBoxOffset} ${viewBoxOffset} ${viewBoxSize} ${viewBoxSize}`;\n\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox={viewBox}\n width={size}\n height={size}\n fill=\"none\"\n style={{\n opacity,\n transform: transforms.join(' ') || undefined,\n filter: shadow > 0 ? `drop-shadow(0 ${shadow}px ${shadow * 2}px rgba(0,0,0,0.3))` : undefined,\n backgroundColor: background !== 'transparent' ? background : undefined\n }}\n >\n <title>Better Auth Logo</title>\n <path fill=\"currentColor\" d=\"M0 3.39v17.22h5.783v-5.55h6.434V8.939H5.783V3.39Zm12.217 5.55h5.638v6.122h-5.638v5.548H24V3.391H12.217Z\"/>\n </svg>\n );\n};\n","export const PLUGIN_ID = \"better-auth-dashboard\";\n","import type React from \"react\";\n\nexport interface EditViewPanelProps {\n model: string;\n documentId?: string;\n // biome-ignore lint/suspicious/noExplicitAny: document shape varies by entity type\n document?: Record<string, any>;\n}\n\nexport interface EditViewPanelConfig {\n id: string;\n title: string;\n /** Restrict to specific model(s). Omit to show in all edit views. */\n model?: string | string[];\n Component: React.ComponentType<EditViewPanelProps>;\n}\n\nconst panels: EditViewPanelConfig[] = [];\n\nexport function addEditViewSidePanel(config: EditViewPanelConfig): void {\n if (panels.some((p) => p.id === config.id)) {\n console.warn(\n `[better-auth-dashboard] Panel with id \"${config.id}\" is already registered.`,\n );\n return;\n }\n panels.push(config);\n}\n\nexport function getEditViewSidePanels(model: string): EditViewPanelConfig[] {\n return panels.filter((p) => {\n if (!p.model) return true;\n if (Array.isArray(p.model)) return p.model.includes(model);\n return p.model === model;\n });\n}\n","import type { ComponentType } from \"react\";\n\nexport interface StrapiMediaFile {\n id: number;\n name: string;\n url: string;\n formats?: Record<string, { url: string }> | null;\n alternativeText?: string | null;\n}\n\nexport interface MediaLibraryDialogProps {\n onClose: () => void;\n onSelectAssets: (assets: StrapiMediaFile[]) => void;\n allowedTypes?: Array<\"files\" | \"images\" | \"videos\" | \"audios\">;\n multiple?: boolean;\n}\n\ninterface AppBridge {\n library: {\n components: {\n \"media-library\"?: ComponentType<MediaLibraryDialogProps>;\n };\n };\n}\n\ndeclare global {\n interface Window {\n __betterAuthDashApp?: AppBridge;\n }\n}\n\nexport function captureApp(app: AppBridge) {\n window.__betterAuthDashApp = app;\n}\n\nexport function getMediaLibraryComponent(): ComponentType<MediaLibraryDialogProps> | null {\n return (\n window.__betterAuthDashApp?.library?.components?.[\"media-library\"] ?? null\n );\n}\n","import { PluginIcon } from \"./components/PluginIcon\";\nimport { PLUGIN_ID } from \"./pluginId\";\nimport { addEditViewSidePanel } from \"./utils/editViewPanelRegistry\";\nimport { captureApp } from \"./utils/strapiApp\";\n\nexport default {\n register(app: {\n addMenuLink: (config: {\n to: string;\n icon: React.ComponentType;\n intlLabel: { id: string; defaultMessage: string };\n Component: () => Promise<{ default: React.ComponentType }>;\n }) => void;\n router: {\n addRoute: (config: {\n path: string;\n Component: () => Promise<{ default: React.ComponentType }>;\n }) => void;\n };\n // biome-ignore lint/suspicious/noExplicitAny: Strapi app bridge type\n library: any;\n registerPlugin: (config: {\n id: string;\n name: string;\n // biome-ignore lint/suspicious/noExplicitAny: plugin API shape is open-ended\n apis: Record<string, any>;\n }) => void;\n }) {\n captureApp(app);\n\n app.registerPlugin({\n id: PLUGIN_ID,\n name: \"Auth Dashboard\",\n apis: { addEditViewSidePanel },\n });\n\n app.addMenuLink({\n to: `/plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: \"Auth Dashboard\",\n },\n Component: async () => import(\"./pages/Root\"),\n });\n\n // app.router.addRoute({\n // path: `/plugins/${PLUGIN_ID}`,\n // Component: async () => import(\"./pages/Root\"),\n // });\n },\n\n bootstrap() {},\n};\n"],"names":[],"mappings":";AAAO,MAAM,aAAa,CAAC;AAAA,EACzB,OAAO;AAAA,EACP,aAAa;AAAA,EACb,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,UAAU;AACZ,MAAM;AACJ,QAAM,aAAa,CAAA;AACnB,MAAI,aAAa,EAAG,YAAW,KAAK,UAAU,QAAQ,MAAM;AAC5D,MAAI,eAAgB,YAAW,KAAK,YAAY;AAChD,MAAI,aAAc,YAAW,KAAK,YAAY;AAE9C,QAAM,cAAc,KAAM,UAAU;AACpC,QAAM,gBAAgB,CAAC;AACvB,QAAM,UAAU,GAAG,aAAa,IAAI,aAAa,IAAI,WAAW,IAAI,WAAW;AAE/E,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAM;AAAA,MACN;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAO;AAAA,QACL;AAAA,QACA,WAAW,WAAW,KAAK,GAAG,KAAK;AAAA,QACnC,QAAQ,SAAS,IAAI,iBAAiB,MAAM,MAAM,SAAS,CAAC,wBAAwB;AAAA,QACpF,iBAAiB,eAAe,gBAAgB,aAAa;AAAA,MAAA;AAAA,MAG/D,UAAA;AAAA,QAAA,oBAAC,WAAM,UAAA,mBAAA,CAAgB;AAAA,QACvB,oBAAC,QAAA,EAAK,MAAK,gBAAe,GAAE,0GAAA,CAAyG;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG3I;ACrCO,MAAM,YAAY;ACiBzB,MAAM,SAAgC,CAAA;AAE/B,SAAS,qBAAqB,QAAmC;AACtE,MAAI,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,EAAE,GAAG;AAC1C,YAAQ;AAAA,MACN,0CAA0C,OAAO,EAAE;AAAA,IAAA;AAErD;AAAA,EACF;AACA,SAAO,KAAK,MAAM;AACpB;AAEO,SAAS,sBAAsB,OAAsC;AAC1E,SAAO,OAAO,OAAO,CAAC,MAAM;AAC1B,QAAI,CAAC,EAAE,MAAO,QAAO;AACrB,QAAI,MAAM,QAAQ,EAAE,KAAK,EAAG,QAAO,EAAE,MAAM,SAAS,KAAK;AACzD,WAAO,EAAE,UAAU;AAAA,EACrB,CAAC;AACH;ACJO,SAAS,WAAW,KAAgB;AACzC,SAAO,sBAAsB;AAC/B;AAEO,SAAS,2BAA0E;AACxF,SACE,OAAO,qBAAqB,SAAS,aAAa,eAAe,KAAK;AAE1E;AClCA,MAAA,QAAe;AAAA,EACb,SAAS,KAqBN;AACD,eAAW,GAAG;AAEd,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,MAAM,EAAE,qBAAA;AAAA,IAAqB,CAC9B;AAED,QAAI,YAAY;AAAA,MACd,IAAI,YAAY,SAAS;AAAA,MACzB,MAAM;AAAA,MACN,WAAW;AAAA,QACT,IAAI,GAAG,SAAS;AAAA,QAChB,gBAAgB;AAAA,MAAA;AAAA,MAElB,WAAW,YAAY,OAAO,qBAAc;AAAA,IAAA,CAC7C;AAAA,EAMH;AAAA,EAEA,YAAY;AAAA,EAAC;AACf;"}
|
package/dist/admin/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
-
const index = require("./index-
|
|
3
|
+
const index = require("./index-CYaQ-gs-.js");
|
|
4
4
|
exports.default = index.index;
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
package/dist/admin/index.mjs
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/dist/server/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../server/src/controllers/auth-controller.ts","../../server/src/controllers/db-controller.ts","../../server/src/controllers/index.ts","../../server/src/routes/admin/index.ts","../../server/src/routes/index.ts","../../server/src/index.ts"],"sourcesContent":["import { errors } from \"@strapi/utils\";\nimport type { Context } from \"koa\";\nimport type { Auth } from \"../../types/better-auth\";\n\nexport const DASHBOARD_API_KEY =\n process.env.BETTER_AUTH_DASHBOARD_SECRET || \"strapi-internal-dashboard-key\";\n\n/**\n * Header name used to pass dash() JWT context fields separately from the HTTP payload.\n *\n * The admin client encodes the context as base64(JSON) in this header.\n * The auth-controller reads it here and injects the fields into the signed JWT\n * so the dash() jwtMiddleware can validate them — without ever mixing them\n * with the actual request body.\n */\nexport const DASH_CONTEXT_HEADER = \"x-dash-context\";\n\nasync function hashApiKey(value: string): Promise<string> {\n const data = new TextEncoder().encode(value);\n const buf = await crypto.subtle.digest(\"SHA-256\", data);\n return Array.from(new Uint8Array(buf))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nconst proxyController = () => ({\n async handleAuthRequest(ctx: Context) {\n const auth = strapi\n .service(\"plugin::better-auth.auth-service\")\n .getAuth() as Auth | null;\n\n if (!auth)\n throw new errors.ApplicationError(\"No Better Auth config file found\");\n\n if (!auth.api.signJWT) {\n throw new errors.ApplicationError(\n \"[@strapi-community/plugin-better-auth-dashboard] The better-auth JWT plugin is required. \" +\n \"Add jwt() from 'better-auth/plugins' to your better-auth configuration.\",\n );\n }\n\n // Read JWT context from the dedicated X-Dash-Context header.\n // The admin client base64-encodes the context JSON and sets this header,\n // keeping context fields cleanly separated from the HTTP payload.\n const contextHeader = ctx.request.headers[DASH_CONTEXT_HEADER];\n let extra: Record<string, unknown> = {};\n if (typeof contextHeader === \"string\" && contextHeader.length > 0) {\n try {\n const decoded = Buffer.from(contextHeader, \"base64\").toString(\"utf8\");\n const parsed = JSON.parse(decoded);\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n extra = parsed as Record<string, unknown>;\n }\n } catch {\n // Malformed context header — proceed without extra context\n }\n }\n\n const apiKeyHash = await hashApiKey(DASHBOARD_API_KEY);\n const { token } = await auth.api.signJWT({\n body: {\n payload: { iat: Math.floor(Date.now() / 1000), apiKeyHash, ...extra },\n overrideOptions: { jwt: { expirationTime: \"5m\" } },\n },\n });\n\n // Create a Request object compatible with Better Auth\n const url = new URL(\n ctx.request.url,\n `${ctx.request.protocol}://${ctx.request.host}`,\n );\n\n // Update the URL path to the Better Auth format\n const betterAuthPath = ctx.params.path || \"\";\n url.pathname = `/api/auth/${betterAuthPath}`;\n\n // Prepare headers\n const headers = new Headers();\n Object.entries(ctx.request.headers).forEach(([key, value]) => {\n if (value) {\n headers.set(key, Array.isArray(value) ? value[0] : String(value));\n }\n });\n\n // Set the Authorization header with the signed JWT\n headers.set(\"Authorization\", `Bearer ${token}`);\n\n const hasBody =\n ctx.request.method !== \"GET\" && ctx.request.method !== \"HEAD\";\n\n // Create the Request object\n const request = new Request(url.toString(), {\n method: ctx.request.method,\n headers: headers,\n body: hasBody ? JSON.stringify(ctx.request.body) : undefined,\n });\n\n // Call Better Auth handler\n const response = await auth.handler(request);\n\n // Set response status\n ctx.status = response.status;\n\n // Copy response headers\n response.headers.forEach((value: string, key: string) => {\n ctx.set(key, value);\n });\n\n // Get response body — read as text first to avoid JSON.parse errors on empty bodies\n // (e.g. deleteUser returns undefined, which better-call serializes as content-type:json + no body)\n const contentType = response.headers.get(\"content-type\");\n const text = await response.text();\n\n if (!text) {\n ctx.body = {};\n } else if (contentType?.includes(\"application/json\")) {\n ctx.body = JSON.parse(text);\n } else {\n ctx.body = text;\n }\n },\n});\n\nexport default proxyController;\n","import { UID } from \"@strapi/strapi\";\nimport type { Context } from \"koa\";\n\n/**\n * Generic CRUD controller for Strapi content types used by the dashboard.\n *\n * These admin routes proxy directly to the Strapi document service and are\n * protected by Strapi's own admin JWT — only authenticated admin users can\n * reach them, which is the same access level as the built-in content manager.\n */\n\nfunction assertValidUid(ctx: Context, uid: unknown): uid is string {\n if (\n typeof uid !== \"string\" ||\n (!uid.startsWith(\"plugin::\") &&\n !uid.startsWith(\"api::\") &&\n !uid.startsWith(\"admin::\"))\n ) {\n ctx.status = 400;\n ctx.body = { error: \"uid must be a valid Strapi content-type UID\" };\n return false;\n }\n return true;\n}\n\nconst dbController = () => ({\n /**\n * List documents.\n *\n * Query params (all optional):\n * uid – content-type UID, e.g. plugin::better-auth.session\n * filters – Strapi filter object, supports nested qs syntax:\n * ?filters[userId][$eq]=1\n * sort – sort string or array, e.g. sort[0]=createdAt:desc\n * pagination[page] – 1-indexed page number (default 1)\n * pagination[pageSize] – items per page (default 50)\n * populate – \"*\" for all relations, or comma-separated field names\n *\n * Response: { results: [...], pagination: { page, pageSize, total, pageCount } }\n */\n async list(ctx: Context) {\n const { uid, filters, pagination, populate } = ctx.query as {\n uid?: string;\n filters?: Record<string, unknown>;\n pagination?: { page?: string; pageSize?: string };\n populate?: string;\n };\n\n if (!assertValidUid(ctx, uid)) return;\n\n const page = Math.max(1, parseInt(pagination?.page ?? \"1\", 10));\n const pageSize = Math.min(\n 200,\n Math.max(1, parseInt(pagination?.pageSize ?? \"50\", 10)),\n );\n\n const populateArg = populate\n ? populate === \"*\"\n ? \"*\"\n : populate\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\n\n // biome-ignore lint/suspicious/noExplicitAny: populate type is complex\n const service = strapi.documents(uid as UID.CollectionType) as any;\n\n const [results, total] = await Promise.all([\n service.findMany({\n filters: filters ?? {},\n sort: \"createdAt:desc\",\n limit: pageSize,\n start: (page - 1) * pageSize,\n ...(populateArg ? { populate: populateArg } : {}),\n }),\n strapi.documents(uid as UID.CollectionType).count({ filters: filters ?? {} }),\n ]);\n\n ctx.body = {\n results,\n pagination: {\n page,\n pageSize,\n total,\n pageCount: Math.ceil(total / pageSize),\n },\n };\n },\n\n /**\n * Update a single document by its documentId (UUID).\n *\n * Query params:\n * uid – content-type UID\n *\n * Body: partial field values to update.\n *\n * Response: updated document.\n */\n async update(ctx: Context) {\n const { uid } = ctx.query as { uid?: string };\n\n if (!assertValidUid(ctx, uid)) return;\n\n const { documentId } = ctx.params as { documentId: string };\n\n // biome-ignore lint/suspicious/noExplicitAny: strapi global\n const result = await (strapi as any).documents(uid).update({\n documentId,\n data: ctx.request.body,\n });\n\n if (!result) {\n ctx.status = 404;\n ctx.body = { error: \"Document not found\" };\n return;\n }\n\n ctx.body = result;\n },\n});\n\nexport default dbController;\n","import authController from \"./auth-controller\";\nimport dbController from \"./db-controller\";\n\nexport default {\n \"auth-controller\": authController,\n \"db-controller\": dbController,\n};\n","export default () => ({\n type: \"admin\",\n routes: [\n {\n method: \"GET\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n prefix: \"\",\n auth: false,\n },\n },\n {\n method: \"POST\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n auth: false,\n prefix: \"\",\n },\n },\n {\n method: \"PUT\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n auth: false,\n prefix: \"\",\n },\n },\n {\n method: \"PATCH\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n auth: false,\n prefix: \"\",\n },\n },\n {\n method: \"DELETE\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n auth: false,\n prefix: \"\",\n },\n },\n {\n method: \"GET\",\n path: \"/better-auth-dashboard/db\",\n handler: \"db-controller.list\",\n config: {\n policies: [],\n prefix: \"\",\n },\n },\n {\n method: \"PUT\",\n path: \"/better-auth-dashboard/db/:documentId\",\n handler: \"db-controller.update\",\n config: {\n policies: [],\n prefix: \"\",\n },\n },\n ],\n});\n","import adminRoutes from \"./admin\";\n\nexport default { admin: adminRoutes };\n","import controllers from \"./controllers\";\nimport routes from \"./routes\";\n\nexport default {\n controllers,\n routes,\n};\n"],"names":["errors","authController"],"mappings":"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"}
|
package/dist/server/index.mjs
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../server/src/controllers/auth-controller.ts","../../server/src/controllers/db-controller.ts","../../server/src/controllers/index.ts","../../server/src/routes/admin/index.ts","../../server/src/routes/index.ts","../../server/src/index.ts"],"sourcesContent":["import { errors } from \"@strapi/utils\";\nimport type { Context } from \"koa\";\nimport type { Auth } from \"../../types/better-auth\";\n\nexport const DASHBOARD_API_KEY =\n process.env.BETTER_AUTH_DASHBOARD_SECRET || \"strapi-internal-dashboard-key\";\n\n/**\n * Header name used to pass dash() JWT context fields separately from the HTTP payload.\n *\n * The admin client encodes the context as base64(JSON) in this header.\n * The auth-controller reads it here and injects the fields into the signed JWT\n * so the dash() jwtMiddleware can validate them — without ever mixing them\n * with the actual request body.\n */\nexport const DASH_CONTEXT_HEADER = \"x-dash-context\";\n\nasync function hashApiKey(value: string): Promise<string> {\n const data = new TextEncoder().encode(value);\n const buf = await crypto.subtle.digest(\"SHA-256\", data);\n return Array.from(new Uint8Array(buf))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nconst proxyController = () => ({\n async handleAuthRequest(ctx: Context) {\n const auth = strapi\n .service(\"plugin::better-auth.auth-service\")\n .getAuth() as Auth | null;\n\n if (!auth)\n throw new errors.ApplicationError(\"No Better Auth config file found\");\n\n if (!auth.api.signJWT) {\n throw new errors.ApplicationError(\n \"[@strapi-community/plugin-better-auth-dashboard] The better-auth JWT plugin is required. \" +\n \"Add jwt() from 'better-auth/plugins' to your better-auth configuration.\",\n );\n }\n\n // Read JWT context from the dedicated X-Dash-Context header.\n // The admin client base64-encodes the context JSON and sets this header,\n // keeping context fields cleanly separated from the HTTP payload.\n const contextHeader = ctx.request.headers[DASH_CONTEXT_HEADER];\n let extra: Record<string, unknown> = {};\n if (typeof contextHeader === \"string\" && contextHeader.length > 0) {\n try {\n const decoded = Buffer.from(contextHeader, \"base64\").toString(\"utf8\");\n const parsed = JSON.parse(decoded);\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n extra = parsed as Record<string, unknown>;\n }\n } catch {\n // Malformed context header — proceed without extra context\n }\n }\n\n const apiKeyHash = await hashApiKey(DASHBOARD_API_KEY);\n const { token } = await auth.api.signJWT({\n body: {\n payload: { iat: Math.floor(Date.now() / 1000), apiKeyHash, ...extra },\n overrideOptions: { jwt: { expirationTime: \"5m\" } },\n },\n });\n\n // Create a Request object compatible with Better Auth\n const url = new URL(\n ctx.request.url,\n `${ctx.request.protocol}://${ctx.request.host}`,\n );\n\n // Update the URL path to the Better Auth format\n const betterAuthPath = ctx.params.path || \"\";\n url.pathname = `/api/auth/${betterAuthPath}`;\n\n // Prepare headers\n const headers = new Headers();\n Object.entries(ctx.request.headers).forEach(([key, value]) => {\n if (value) {\n headers.set(key, Array.isArray(value) ? value[0] : String(value));\n }\n });\n\n // Set the Authorization header with the signed JWT\n headers.set(\"Authorization\", `Bearer ${token}`);\n\n const hasBody =\n ctx.request.method !== \"GET\" && ctx.request.method !== \"HEAD\";\n\n // Create the Request object\n const request = new Request(url.toString(), {\n method: ctx.request.method,\n headers: headers,\n body: hasBody ? JSON.stringify(ctx.request.body) : undefined,\n });\n\n // Call Better Auth handler\n const response = await auth.handler(request);\n\n // Set response status\n ctx.status = response.status;\n\n // Copy response headers\n response.headers.forEach((value: string, key: string) => {\n ctx.set(key, value);\n });\n\n // Get response body — read as text first to avoid JSON.parse errors on empty bodies\n // (e.g. deleteUser returns undefined, which better-call serializes as content-type:json + no body)\n const contentType = response.headers.get(\"content-type\");\n const text = await response.text();\n\n if (!text) {\n ctx.body = {};\n } else if (contentType?.includes(\"application/json\")) {\n ctx.body = JSON.parse(text);\n } else {\n ctx.body = text;\n }\n },\n});\n\nexport default proxyController;\n","import { UID } from \"@strapi/strapi\";\nimport type { Context } from \"koa\";\n\n/**\n * Generic CRUD controller for Strapi content types used by the dashboard.\n *\n * These admin routes proxy directly to the Strapi document service and are\n * protected by Strapi's own admin JWT — only authenticated admin users can\n * reach them, which is the same access level as the built-in content manager.\n */\n\nfunction assertValidUid(ctx: Context, uid: unknown): uid is string {\n if (\n typeof uid !== \"string\" ||\n (!uid.startsWith(\"plugin::\") &&\n !uid.startsWith(\"api::\") &&\n !uid.startsWith(\"admin::\"))\n ) {\n ctx.status = 400;\n ctx.body = { error: \"uid must be a valid Strapi content-type UID\" };\n return false;\n }\n return true;\n}\n\nconst dbController = () => ({\n /**\n * List documents.\n *\n * Query params (all optional):\n * uid – content-type UID, e.g. plugin::better-auth.session\n * filters – Strapi filter object, supports nested qs syntax:\n * ?filters[userId][$eq]=1\n * sort – sort string or array, e.g. sort[0]=createdAt:desc\n * pagination[page] – 1-indexed page number (default 1)\n * pagination[pageSize] – items per page (default 50)\n * populate – \"*\" for all relations, or comma-separated field names\n *\n * Response: { results: [...], pagination: { page, pageSize, total, pageCount } }\n */\n async list(ctx: Context) {\n const { uid, filters, pagination, populate } = ctx.query as {\n uid?: string;\n filters?: Record<string, unknown>;\n pagination?: { page?: string; pageSize?: string };\n populate?: string;\n };\n\n if (!assertValidUid(ctx, uid)) return;\n\n const page = Math.max(1, parseInt(pagination?.page ?? \"1\", 10));\n const pageSize = Math.min(\n 200,\n Math.max(1, parseInt(pagination?.pageSize ?? \"50\", 10)),\n );\n\n const populateArg = populate\n ? populate === \"*\"\n ? \"*\"\n : populate\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\n\n // biome-ignore lint/suspicious/noExplicitAny: populate type is complex\n const service = strapi.documents(uid as UID.CollectionType) as any;\n\n const [results, total] = await Promise.all([\n service.findMany({\n filters: filters ?? {},\n sort: \"createdAt:desc\",\n limit: pageSize,\n start: (page - 1) * pageSize,\n ...(populateArg ? { populate: populateArg } : {}),\n }),\n strapi.documents(uid as UID.CollectionType).count({ filters: filters ?? {} }),\n ]);\n\n ctx.body = {\n results,\n pagination: {\n page,\n pageSize,\n total,\n pageCount: Math.ceil(total / pageSize),\n },\n };\n },\n\n /**\n * Update a single document by its documentId (UUID).\n *\n * Query params:\n * uid – content-type UID\n *\n * Body: partial field values to update.\n *\n * Response: updated document.\n */\n async update(ctx: Context) {\n const { uid } = ctx.query as { uid?: string };\n\n if (!assertValidUid(ctx, uid)) return;\n\n const { documentId } = ctx.params as { documentId: string };\n\n // biome-ignore lint/suspicious/noExplicitAny: strapi global\n const result = await (strapi as any).documents(uid).update({\n documentId,\n data: ctx.request.body,\n });\n\n if (!result) {\n ctx.status = 404;\n ctx.body = { error: \"Document not found\" };\n return;\n }\n\n ctx.body = result;\n },\n});\n\nexport default dbController;\n","import authController from \"./auth-controller\";\nimport dbController from \"./db-controller\";\n\nexport default {\n \"auth-controller\": authController,\n \"db-controller\": dbController,\n};\n","export default () => ({\n type: \"admin\",\n routes: [\n {\n method: \"GET\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n prefix: \"\",\n auth: false,\n },\n },\n {\n method: \"POST\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n auth: false,\n prefix: \"\",\n },\n },\n {\n method: \"PUT\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n auth: false,\n prefix: \"\",\n },\n },\n {\n method: \"PATCH\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n auth: false,\n prefix: \"\",\n },\n },\n {\n method: \"DELETE\",\n path: \"/auth/:path*\",\n handler: \"auth-controller.handleAuthRequest\",\n config: {\n policies: [],\n auth: false,\n prefix: \"\",\n },\n },\n {\n method: \"GET\",\n path: \"/better-auth-dashboard/db\",\n handler: \"db-controller.list\",\n config: {\n policies: [],\n prefix: \"\",\n },\n },\n {\n method: \"PUT\",\n path: \"/better-auth-dashboard/db/:documentId\",\n handler: \"db-controller.update\",\n config: {\n policies: [],\n prefix: \"\",\n },\n },\n ],\n});\n","import adminRoutes from \"./admin\";\n\nexport default { admin: adminRoutes };\n","import controllers from \"./controllers\";\nimport routes from \"./routes\";\n\nexport default {\n controllers,\n routes,\n};\n"],"names":["authController"],"mappings":"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"}
|