@questpie/admin 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +439 -424
- package/dist/auth-layout-M8K8_q5R.mjs +181 -0
- package/dist/auth-layout-M8K8_q5R.mjs.map +1 -0
- package/dist/bulk-upload-dialog-h7zXD78Y.mjs +274 -0
- package/dist/bulk-upload-dialog-h7zXD78Y.mjs.map +1 -0
- package/dist/{components/ui/card.mjs → card-BKHjBQfw.mjs} +8 -8
- package/dist/card-BKHjBQfw.mjs.map +1 -0
- package/dist/client/styles/index.css +434 -0
- package/dist/client-BCGpkAz6.mjs +22635 -0
- package/dist/client-BCGpkAz6.mjs.map +1 -0
- package/dist/client-CcWZbkBP.d.mts +13585 -0
- package/dist/client-CcWZbkBP.d.mts.map +1 -0
- package/dist/client.d.mts +3 -0
- package/dist/client.mjs +14 -0
- package/dist/content-locales-provider-BXvuIgfg.mjs +1650 -0
- package/dist/content-locales-provider-BXvuIgfg.mjs.map +1 -0
- package/dist/dashboard-page-B4PGEdc2.mjs +2500 -0
- package/dist/dashboard-page-B4PGEdc2.mjs.map +1 -0
- package/dist/dashboard-page-CVlyR40m.mjs +6 -0
- package/dist/dropzone-Do3awXKd.mjs +634 -0
- package/dist/dropzone-Do3awXKd.mjs.map +1 -0
- package/dist/{views/auth/forgot-password-form.mjs → forgot-password-page-Bcp-An4Y.mjs} +87 -14
- package/dist/forgot-password-page-Bcp-An4Y.mjs.map +1 -0
- package/dist/forgot-password-page-CIILVhfo.mjs +7 -0
- package/dist/index-B9Xwk4hi.d.mts +2753 -0
- package/dist/index-B9Xwk4hi.d.mts.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +14 -0
- package/dist/login-page-8K7fo0qK.mjs +7 -0
- package/dist/login-page-CP4gA-dl.mjs +298 -0
- package/dist/login-page-CP4gA-dl.mjs.map +1 -0
- package/dist/preview-utils-BKQ9-TMa.mjs +65 -0
- package/dist/preview-utils-BKQ9-TMa.mjs.map +1 -0
- package/dist/{views/auth/reset-password-form.mjs → reset-password-page-BqfDmLxA.mjs} +111 -14
- package/dist/reset-password-page-BqfDmLxA.mjs.map +1 -0
- package/dist/reset-password-page-DLATv0xQ.mjs +7 -0
- package/dist/runtime-6VZM878K.mjs +69 -0
- package/dist/runtime-6VZM878K.mjs.map +1 -0
- package/dist/saved-views.types-BMsz5mCy.d.mts +42 -0
- package/dist/saved-views.types-BMsz5mCy.d.mts.map +1 -0
- package/dist/server.d.mts +250 -0
- package/dist/server.d.mts.map +1 -0
- package/dist/server.mjs +832 -0
- package/dist/server.mjs.map +1 -0
- package/dist/setup-page-CMZ5P_OE.mjs +6 -0
- package/dist/setup-page-YAP_fzqh.mjs +264 -0
- package/dist/setup-page-YAP_fzqh.mjs.map +1 -0
- package/dist/shared.d.mts +57 -0
- package/dist/shared.d.mts.map +1 -0
- package/dist/shared.mjs +3 -0
- package/dist/{hooks/use-auth.mjs → use-auth-BoLmWtmU.mjs} +42 -30
- package/dist/use-auth-BoLmWtmU.mjs.map +1 -0
- package/package.json +48 -197
- package/.turbo/turbo-build.log +0 -108
- package/CHANGELOG.md +0 -10
- package/STATUS.md +0 -917
- package/VALIDATION.md +0 -602
- package/components.json +0 -24
- package/dist/__tests__/setup.mjs +0 -38
- package/dist/__tests__/test-utils.mjs +0 -45
- package/dist/__tests__/vitest.d.mjs +0 -3
- package/dist/components/admin-app.mjs +0 -69
- package/dist/components/fields/array-field.mjs +0 -190
- package/dist/components/fields/checkbox-field.mjs +0 -34
- package/dist/components/fields/custom-field.mjs +0 -32
- package/dist/components/fields/date-field.mjs +0 -41
- package/dist/components/fields/datetime-field.mjs +0 -42
- package/dist/components/fields/email-field.mjs +0 -37
- package/dist/components/fields/embedded-collection.mjs +0 -253
- package/dist/components/fields/field-types.mjs +0 -1
- package/dist/components/fields/field-utils.mjs +0 -10
- package/dist/components/fields/field-wrapper.mjs +0 -34
- package/dist/components/fields/index.mjs +0 -23
- package/dist/components/fields/json-field.mjs +0 -243
- package/dist/components/fields/locale-badge.mjs +0 -16
- package/dist/components/fields/number-field.mjs +0 -39
- package/dist/components/fields/password-field.mjs +0 -37
- package/dist/components/fields/relation-field.mjs +0 -104
- package/dist/components/fields/relation-picker.mjs +0 -229
- package/dist/components/fields/relation-select.mjs +0 -188
- package/dist/components/fields/rich-text-editor/index.mjs +0 -897
- package/dist/components/fields/select-field.mjs +0 -41
- package/dist/components/fields/switch-field.mjs +0 -34
- package/dist/components/fields/text-field.mjs +0 -38
- package/dist/components/fields/textarea-field.mjs +0 -38
- package/dist/components/index.mjs +0 -59
- package/dist/components/primitives/checkbox-input.mjs +0 -127
- package/dist/components/primitives/date-input.mjs +0 -303
- package/dist/components/primitives/index.mjs +0 -12
- package/dist/components/primitives/number-input.mjs +0 -104
- package/dist/components/primitives/select-input.mjs +0 -177
- package/dist/components/primitives/tag-input.mjs +0 -135
- package/dist/components/primitives/text-input.mjs +0 -39
- package/dist/components/primitives/textarea-input.mjs +0 -37
- package/dist/components/primitives/toggle-input.mjs +0 -31
- package/dist/components/primitives/types.mjs +0 -12
- package/dist/components/ui/accordion.mjs +0 -55
- package/dist/components/ui/avatar.mjs +0 -54
- package/dist/components/ui/badge.mjs +0 -34
- package/dist/components/ui/button.mjs +0 -48
- package/dist/components/ui/checkbox.mjs +0 -21
- package/dist/components/ui/combobox.mjs +0 -163
- package/dist/components/ui/dialog.mjs +0 -95
- package/dist/components/ui/dropdown-menu.mjs +0 -138
- package/dist/components/ui/field.mjs +0 -113
- package/dist/components/ui/input-group.mjs +0 -82
- package/dist/components/ui/input.mjs +0 -17
- package/dist/components/ui/label.mjs +0 -15
- package/dist/components/ui/popover.mjs +0 -56
- package/dist/components/ui/scroll-area.mjs +0 -38
- package/dist/components/ui/select.mjs +0 -100
- package/dist/components/ui/separator.mjs +0 -16
- package/dist/components/ui/sheet.mjs +0 -90
- package/dist/components/ui/sidebar.mjs +0 -387
- package/dist/components/ui/skeleton.mjs +0 -14
- package/dist/components/ui/spinner.mjs +0 -16
- package/dist/components/ui/switch.mjs +0 -22
- package/dist/components/ui/table.mjs +0 -68
- package/dist/components/ui/tabs.mjs +0 -48
- package/dist/components/ui/textarea.mjs +0 -15
- package/dist/components/ui/tooltip.mjs +0 -44
- package/dist/config/component-registry.mjs +0 -38
- package/dist/config/index.mjs +0 -129
- package/dist/hooks/admin-provider.mjs +0 -70
- package/dist/hooks/index.mjs +0 -7
- package/dist/hooks/store.mjs +0 -178
- package/dist/hooks/use-collection-db.mjs +0 -146
- package/dist/hooks/use-collection.mjs +0 -112
- package/dist/hooks/use-global.mjs +0 -46
- package/dist/hooks/use-mobile.mjs +0 -20
- package/dist/lib/utils.mjs +0 -10
- package/dist/styles/index.css +0 -336
- package/dist/styles/index.mjs +0 -1
- package/dist/utils/index.mjs +0 -9
- package/dist/views/auth/auth-layout.mjs +0 -52
- package/dist/views/auth/index.mjs +0 -6
- package/dist/views/auth/login-form.mjs +0 -156
- package/dist/views/collection/auto-form-fields.mjs +0 -525
- package/dist/views/collection/collection-form.mjs +0 -91
- package/dist/views/collection/collection-list.mjs +0 -76
- package/dist/views/collection/form-field.mjs +0 -42
- package/dist/views/collection/index.mjs +0 -6
- package/dist/views/common/index.mjs +0 -4
- package/dist/views/common/locale-switcher.mjs +0 -39
- package/dist/views/common/version-history.mjs +0 -272
- package/dist/views/index.mjs +0 -9
- package/dist/views/layout/admin-layout.mjs +0 -40
- package/dist/views/layout/admin-router.mjs +0 -95
- package/dist/views/layout/admin-sidebar.mjs +0 -63
- package/dist/views/layout/index.mjs +0 -5
- package/src/__tests__/setup.ts +0 -44
- package/src/__tests__/test-utils.tsx +0 -49
- package/src/__tests__/vitest.d.ts +0 -9
- package/src/components/admin-app.tsx +0 -221
- package/src/components/fields/array-field.tsx +0 -237
- package/src/components/fields/checkbox-field.tsx +0 -47
- package/src/components/fields/custom-field.tsx +0 -50
- package/src/components/fields/date-field.tsx +0 -65
- package/src/components/fields/datetime-field.tsx +0 -67
- package/src/components/fields/email-field.tsx +0 -51
- package/src/components/fields/embedded-collection.tsx +0 -315
- package/src/components/fields/field-types.ts +0 -162
- package/src/components/fields/field-utils.ts +0 -6
- package/src/components/fields/field-wrapper.tsx +0 -52
- package/src/components/fields/index.ts +0 -66
- package/src/components/fields/json-field.tsx +0 -440
- package/src/components/fields/locale-badge.tsx +0 -15
- package/src/components/fields/number-field.tsx +0 -57
- package/src/components/fields/password-field.tsx +0 -51
- package/src/components/fields/relation-field.tsx +0 -243
- package/src/components/fields/relation-picker.tsx +0 -402
- package/src/components/fields/relation-select.tsx +0 -327
- package/src/components/fields/rich-text-editor/index.tsx +0 -1337
- package/src/components/fields/select-field.tsx +0 -61
- package/src/components/fields/switch-field.tsx +0 -47
- package/src/components/fields/text-field.tsx +0 -55
- package/src/components/fields/textarea-field.tsx +0 -55
- package/src/components/index.ts +0 -40
- package/src/components/primitives/checkbox-input.tsx +0 -193
- package/src/components/primitives/date-input.tsx +0 -401
- package/src/components/primitives/index.ts +0 -24
- package/src/components/primitives/number-input.tsx +0 -132
- package/src/components/primitives/select-input.tsx +0 -296
- package/src/components/primitives/tag-input.tsx +0 -200
- package/src/components/primitives/text-input.tsx +0 -49
- package/src/components/primitives/textarea-input.tsx +0 -46
- package/src/components/primitives/toggle-input.tsx +0 -36
- package/src/components/primitives/types.ts +0 -235
- package/src/components/ui/accordion.tsx +0 -72
- package/src/components/ui/avatar.tsx +0 -106
- package/src/components/ui/badge.tsx +0 -48
- package/src/components/ui/button.tsx +0 -53
- package/src/components/ui/card.tsx +0 -94
- package/src/components/ui/checkbox.tsx +0 -27
- package/src/components/ui/combobox.tsx +0 -290
- package/src/components/ui/dialog.tsx +0 -151
- package/src/components/ui/dropdown-menu.tsx +0 -254
- package/src/components/ui/field.tsx +0 -227
- package/src/components/ui/input-group.tsx +0 -149
- package/src/components/ui/input.tsx +0 -20
- package/src/components/ui/label.tsx +0 -18
- package/src/components/ui/popover.tsx +0 -88
- package/src/components/ui/scroll-area.tsx +0 -53
- package/src/components/ui/select.tsx +0 -192
- package/src/components/ui/separator.tsx +0 -23
- package/src/components/ui/sheet.tsx +0 -127
- package/src/components/ui/sidebar.tsx +0 -723
- package/src/components/ui/skeleton.tsx +0 -13
- package/src/components/ui/spinner.tsx +0 -10
- package/src/components/ui/switch.tsx +0 -32
- package/src/components/ui/table.tsx +0 -99
- package/src/components/ui/tabs.tsx +0 -82
- package/src/components/ui/textarea.tsx +0 -18
- package/src/components/ui/tooltip.tsx +0 -70
- package/src/config/component-registry.ts +0 -190
- package/src/config/index.ts +0 -1099
- package/src/hooks/README.md +0 -269
- package/src/hooks/admin-provider.tsx +0 -110
- package/src/hooks/index.ts +0 -41
- package/src/hooks/store.ts +0 -248
- package/src/hooks/use-auth.ts +0 -168
- package/src/hooks/use-collection-db.ts +0 -209
- package/src/hooks/use-collection.ts +0 -156
- package/src/hooks/use-global.ts +0 -69
- package/src/hooks/use-mobile.ts +0 -21
- package/src/lib/utils.ts +0 -6
- package/src/styles/index.css +0 -340
- package/src/utils/index.ts +0 -6
- package/src/views/auth/auth-layout.tsx +0 -77
- package/src/views/auth/forgot-password-form.tsx +0 -192
- package/src/views/auth/index.ts +0 -21
- package/src/views/auth/login-form.tsx +0 -229
- package/src/views/auth/reset-password-form.tsx +0 -232
- package/src/views/collection/auto-form-fields.tsx +0 -982
- package/src/views/collection/collection-form.tsx +0 -186
- package/src/views/collection/collection-list.tsx +0 -223
- package/src/views/collection/form-field.tsx +0 -52
- package/src/views/collection/index.ts +0 -15
- package/src/views/common/index.ts +0 -8
- package/src/views/common/locale-switcher.tsx +0 -45
- package/src/views/common/version-history.tsx +0 -406
- package/src/views/index.ts +0 -25
- package/src/views/layout/admin-layout.tsx +0 -117
- package/src/views/layout/admin-router.tsx +0 -206
- package/src/views/layout/admin-sidebar.tsx +0 -185
- package/src/views/layout/index.ts +0 -12
- package/tsconfig.json +0 -13
- package/tsconfig.tsbuildinfo +0 -1
- package/tsdown.config.ts +0 -13
- package/vitest.config.ts +0 -29
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reset-password-page-BqfDmLxA.mjs","names":["React","React"],"sources":["../src/client/views/auth/reset-password-form.tsx","../src/client/views/pages/reset-password-page.tsx"],"sourcesContent":["/**\n * Reset Password Form - set new password with token\n */\n\nimport {\n CheckCircle,\n Lock,\n SpinnerGap,\n WarningCircle,\n} from \"@phosphor-icons/react\";\nimport * as React from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { Alert, AlertDescription } from \"../../components/ui/alert\";\nimport { Button } from \"../../components/ui/button\";\nimport {\n Field,\n FieldContent,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n} from \"../../components/ui/field\";\nimport { Input } from \"../../components/ui/input\";\nimport { cn } from \"../../lib/utils\";\n\nexport type ResetPasswordFormValues = {\n password: string;\n confirmPassword: string;\n};\n\nexport type ResetPasswordFormProps = {\n /** Reset token from URL */\n token: string;\n /** Called when form is submitted with valid data */\n onSubmit: (\n values: ResetPasswordFormValues & { token: string },\n ) => Promise<void>;\n /** Called when back to login link is clicked */\n onBackToLoginClick?: () => void;\n /** Minimum password length */\n minPasswordLength?: number;\n /** Additional class name */\n className?: string;\n /** Error message from auth */\n error?: string | null;\n};\n\n/**\n * Reset password form with password confirmation\n *\n * @example\n * ```tsx\n * const authClient = createAdminAuthClient<typeof cms>({ baseURL: '...' })\n *\n * function ResetPasswordPage() {\n * const token = useSearchParams().get('token')\n * const [error, setError] = useState<string | null>(null)\n *\n * const handleSubmit = async (values) => {\n * const result = await authClient.resetPassword({\n * token: values.token,\n * newPassword: values.password,\n * })\n * if (result.error) {\n * setError(result.error.message)\n * }\n * }\n *\n * return (\n * <AuthLayout title=\"Reset password\">\n * <ResetPasswordForm token={token} onSubmit={handleSubmit} error={error} />\n * </AuthLayout>\n * )\n * }\n * ```\n */\nexport function ResetPasswordForm({\n token,\n onSubmit,\n onBackToLoginClick,\n minPasswordLength = 8,\n className,\n error,\n}: ResetPasswordFormProps) {\n const [isSuccess, setIsSuccess] = React.useState(false);\n\n const {\n register,\n handleSubmit,\n watch,\n formState: { errors, isSubmitting },\n } = useForm<ResetPasswordFormValues>({\n defaultValues: {\n password: \"\",\n confirmPassword: \"\",\n },\n });\n\n const password = watch(\"password\");\n\n const handleFormSubmit = handleSubmit(async (values) => {\n await onSubmit({ ...values, token });\n if (!error) {\n setIsSuccess(true);\n }\n });\n\n // Success state\n if (isSuccess) {\n return (\n <div className={cn(\"space-y-4 text-center\", className)}>\n <div className=\"bg-primary/10 mx-auto flex size-12 items-center justify-center\">\n <CheckCircle className=\"text-primary size-6\" weight=\"duotone\" />\n </div>\n <div className=\"space-y-2\">\n <h3 className=\"text-sm font-medium\">Password reset successful</h3>\n <p className=\"text-muted-foreground text-xs\">\n Your password has been reset successfully. You can now sign in with\n your new password.\n </p>\n </div>\n <Button\n type=\"button\"\n className=\"w-full\"\n size=\"lg\"\n onClick={onBackToLoginClick}\n >\n Sign in\n </Button>\n </div>\n );\n }\n\n return (\n <form onSubmit={handleFormSubmit} className={cn(\"space-y-4\", className)}>\n <p className=\"text-muted-foreground text-xs\">\n Enter your new password below.\n </p>\n\n <FieldGroup>\n {/* Password Field */}\n <Field data-invalid={!!errors.password}>\n <FieldLabel htmlFor=\"password\">New password</FieldLabel>\n <FieldContent>\n <div className=\"relative\">\n <Lock\n className=\"text-muted-foreground absolute left-2 top-1/2 size-4 -translate-y-1/2\"\n weight=\"duotone\"\n />\n <Input\n id=\"password\"\n type=\"password\"\n placeholder=\"Enter new password\"\n className=\"pl-8\"\n autoComplete=\"new-password\"\n aria-invalid={!!errors.password}\n {...register(\"password\", {\n required: \"Password is required\",\n minLength: {\n value: minPasswordLength,\n message: `Password must be at least ${minPasswordLength} characters`,\n },\n })}\n />\n </div>\n <FieldDescription>\n Must be at least {minPasswordLength} characters\n </FieldDescription>\n <FieldError>{errors.password?.message}</FieldError>\n </FieldContent>\n </Field>\n\n {/* Confirm Password Field */}\n <Field data-invalid={!!errors.confirmPassword}>\n <FieldLabel htmlFor=\"confirmPassword\">Confirm password</FieldLabel>\n <FieldContent>\n <div className=\"relative\">\n <Lock\n className=\"text-muted-foreground absolute left-2 top-1/2 size-4 -translate-y-1/2\"\n weight=\"duotone\"\n />\n <Input\n id=\"confirmPassword\"\n type=\"password\"\n placeholder=\"Confirm new password\"\n className=\"pl-8\"\n autoComplete=\"new-password\"\n aria-invalid={!!errors.confirmPassword}\n {...register(\"confirmPassword\", {\n required: \"Please confirm your password\",\n validate: (value) =>\n value === password || \"Passwords do not match\",\n })}\n />\n </div>\n <FieldError>{errors.confirmPassword?.message}</FieldError>\n </FieldContent>\n </Field>\n </FieldGroup>\n\n {/* Error Message */}\n {error && (\n <Alert variant=\"destructive\">\n <WarningCircle />\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n )}\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n className=\"w-full\"\n size=\"lg\"\n disabled={isSubmitting}\n >\n {isSubmitting ? (\n <>\n <SpinnerGap className=\"animate-spin\" weight=\"bold\" />\n Resetting...\n </>\n ) : (\n \"Reset password\"\n )}\n </Button>\n\n {/* Back to Login Link */}\n <p className=\"text-muted-foreground text-center text-xs\">\n Remember your password?{\" \"}\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n onClick={onBackToLoginClick}\n className=\"h-auto p-0 text-xs\"\n >\n Back to login\n </Button>\n </p>\n </form>\n );\n}\n","/**\n * Reset Password Page\n *\n * Default reset password page that uses AuthLayout and ResetPasswordForm.\n * Integrates with authClient from AdminProvider context.\n */\n\nimport * as React from \"react\";\nimport { Button } from \"../../components/ui/button\";\nimport { useAuthClient } from \"../../hooks/use-auth\";\nimport {\n selectBasePath,\n selectBrandName,\n selectNavigate,\n useAdminStore,\n} from \"../../runtime/provider\";\nimport { AuthLayout } from \"../auth/auth-layout\";\nimport {\n ResetPasswordForm,\n type ResetPasswordFormValues,\n} from \"../auth/reset-password-form\";\n\nexport interface ResetPasswordPageProps {\n /**\n * Title shown on the page\n * @default \"Reset password\"\n */\n title?: string;\n\n /**\n * Description shown below the title\n * @default \"Enter your new password\"\n */\n description?: string;\n\n /**\n * Logo component to show above the form\n */\n logo?: React.ReactNode;\n\n /**\n * Path to login page\n * @default \"{basePath}/login\"\n */\n loginPath?: string;\n\n /**\n * Minimum password length\n * @default 8\n */\n minPasswordLength?: number;\n\n /**\n * Function to get token from URL.\n * By default, reads from URL search params (?token=...)\n */\n getToken?: () => string | null;\n}\n\n/**\n * Default reset password page component.\n *\n * Uses authClient from AdminProvider to handle password reset.\n * Expects a token in the URL query params (?token=...).\n *\n * @example\n * ```tsx\n * // In your admin config\n * const admin = qa<AppCMS>()\n * .use(coreAdminModule)\n * .pages({\n * resetPassword: page(\"reset-password\", { component: ResetPasswordPage })\n * .path(\"/reset-password\"),\n * })\n * ```\n */\nexport function ResetPasswordPage({\n title = \"Reset password\",\n description = \"Enter your new password\",\n logo,\n loginPath,\n minPasswordLength = 8,\n getToken,\n}: ResetPasswordPageProps) {\n const authClient = useAuthClient();\n const navigate = useAdminStore(selectNavigate);\n const basePath = useAdminStore(selectBasePath);\n const brandName = useAdminStore(selectBrandName);\n\n const [error, setError] = React.useState<string | null>(null);\n\n // Get token from URL\n const token = React.useMemo(() => {\n if (getToken) {\n return getToken();\n }\n if (typeof window !== \"undefined\") {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"token\");\n }\n return null;\n }, [getToken]);\n\n const handleSubmit = async (\n values: ResetPasswordFormValues & { token: string },\n ) => {\n setError(null);\n\n try {\n const result = await authClient.resetPassword({\n token: values.token,\n newPassword: values.password,\n });\n\n if (result.error) {\n setError(result.error.message || \"Failed to reset password\");\n return;\n }\n\n // Success is handled by the form (shows success message)\n } catch (err) {\n setError(err instanceof Error ? err.message : \"An error occurred\");\n }\n };\n\n const handleBackToLoginClick = () => {\n navigate(loginPath ?? `${basePath}/login`);\n };\n\n // Show error if no token\n if (!token) {\n return (\n <AuthLayout\n title=\"Invalid Link\"\n description=\"The password reset link is invalid or has expired.\"\n logo={logo ?? <DefaultLogo brandName={brandName} />}\n >\n <div className=\"space-y-4 text-center\">\n <p className=\"text-muted-foreground text-sm\">\n Please request a new password reset link.\n </p>\n <Button type=\"button\" variant=\"link\" onClick={handleBackToLoginClick}>\n Back to login\n </Button>\n </div>\n </AuthLayout>\n );\n }\n\n return (\n <AuthLayout\n title={title}\n description={description}\n logo={logo ?? <DefaultLogo brandName={brandName} />}\n >\n <ResetPasswordForm\n token={token}\n onSubmit={handleSubmit}\n onBackToLoginClick={handleBackToLoginClick}\n minPasswordLength={minPasswordLength}\n error={error}\n />\n </AuthLayout>\n );\n}\n\nfunction DefaultLogo({ brandName }: { brandName: string }) {\n return (\n <div className=\"text-center\">\n <h1 className=\"text-xl font-bold\">{brandName}</h1>\n </div>\n );\n}\n\nexport default ResetPasswordPage;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import "./content-locales-provider-BXvuIgfg.mjs";
|
|
2
|
+
import "./auth-layout-M8K8_q5R.mjs";
|
|
3
|
+
import "./use-auth-BoLmWtmU.mjs";
|
|
4
|
+
import "./card-BKHjBQfw.mjs";
|
|
5
|
+
import { n as reset_password_page_default, t as ResetPasswordPage } from "./reset-password-page-BqfDmLxA.mjs";
|
|
6
|
+
|
|
7
|
+
export { ResetPasswordPage, reset_password_page_default as default };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { c as selectContentLocale, d as selectSetContentLocale, f as useAdminStore } from "./content-locales-provider-BXvuIgfg.mjs";
|
|
2
|
+
import * as React$1 from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { useShallow } from "zustand/shallow";
|
|
5
|
+
|
|
6
|
+
//#region src/client/runtime/locale-scope.tsx
|
|
7
|
+
/**
|
|
8
|
+
* LocaleScope Context
|
|
9
|
+
*
|
|
10
|
+
* Provides scoped locale state for nested forms (e.g., ResourceSheet).
|
|
11
|
+
* When a component is wrapped in LocaleScopeProvider, locale changes
|
|
12
|
+
* affect only that scope, not the global content locale.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* // In ResourceSheet - creates isolated locale scope
|
|
17
|
+
* <LocaleScopeProvider>
|
|
18
|
+
* <FormView ... />
|
|
19
|
+
* </LocaleScopeProvider>
|
|
20
|
+
*
|
|
21
|
+
* // In FieldWrapper - uses scoped locale if available
|
|
22
|
+
* const { locale, setLocale } = useScopedLocale();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
const LocaleScopeContext = React$1.createContext(null);
|
|
26
|
+
/**
|
|
27
|
+
* Provides an isolated locale scope for nested forms.
|
|
28
|
+
* Locale changes inside this provider don't affect the global state.
|
|
29
|
+
*/
|
|
30
|
+
function LocaleScopeProvider({ children, initialLocale }) {
|
|
31
|
+
const globalLocale = useAdminStore(selectContentLocale);
|
|
32
|
+
const [scopedLocale, setScopedLocale] = React$1.useState(initialLocale ?? globalLocale);
|
|
33
|
+
const hasModifiedRef = React$1.useRef(false);
|
|
34
|
+
React$1.useEffect(() => {
|
|
35
|
+
if (!hasModifiedRef.current) setScopedLocale(globalLocale);
|
|
36
|
+
}, [globalLocale]);
|
|
37
|
+
const setLocale = React$1.useCallback((locale) => {
|
|
38
|
+
hasModifiedRef.current = true;
|
|
39
|
+
setScopedLocale(locale);
|
|
40
|
+
}, []);
|
|
41
|
+
const value = React$1.useMemo(() => ({
|
|
42
|
+
locale: scopedLocale,
|
|
43
|
+
setLocale,
|
|
44
|
+
isScoped: true
|
|
45
|
+
}), [scopedLocale, setLocale]);
|
|
46
|
+
return /* @__PURE__ */ jsx(LocaleScopeContext.Provider, {
|
|
47
|
+
value,
|
|
48
|
+
children
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns scoped locale if in a LocaleScopeProvider, otherwise global locale.
|
|
53
|
+
* Use this in components that need locale-aware behavior (FieldWrapper, FormView).
|
|
54
|
+
*/
|
|
55
|
+
function useScopedLocale() {
|
|
56
|
+
const scopedContext = React$1.useContext(LocaleScopeContext);
|
|
57
|
+
const globalLocale = useAdminStore(selectContentLocale);
|
|
58
|
+
const globalSetLocale = useAdminStore(selectSetContentLocale);
|
|
59
|
+
if (scopedContext) return scopedContext;
|
|
60
|
+
return {
|
|
61
|
+
locale: globalLocale,
|
|
62
|
+
setLocale: globalSetLocale,
|
|
63
|
+
isScoped: false
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
export { LocaleScopeProvider as n, useScopedLocale as r, useShallow as t };
|
|
69
|
+
//# sourceMappingURL=runtime-6VZM878K.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-6VZM878K.mjs","names":["React"],"sources":["../src/client/runtime/locale-scope.tsx"],"sourcesContent":["/**\n * LocaleScope Context\n *\n * Provides scoped locale state for nested forms (e.g., ResourceSheet).\n * When a component is wrapped in LocaleScopeProvider, locale changes\n * affect only that scope, not the global content locale.\n *\n * @example\n * ```tsx\n * // In ResourceSheet - creates isolated locale scope\n * <LocaleScopeProvider>\n * <FormView ... />\n * </LocaleScopeProvider>\n *\n * // In FieldWrapper - uses scoped locale if available\n * const { locale, setLocale } = useScopedLocale();\n * ```\n */\n\nimport * as React from \"react\";\nimport {\n\tselectContentLocale,\n\tselectSetContentLocale,\n\tuseAdminStore,\n} from \"./index\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface LocaleScopeContextValue {\n\t/** Current locale in this scope */\n\tlocale: string;\n\t/** Set locale for this scope only */\n\tsetLocale: (locale: string) => void;\n\t/** Whether we're in a scoped context (nested form) */\n\tisScoped: boolean;\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst LocaleScopeContext = React.createContext<LocaleScopeContextValue | null>(\n\tnull,\n);\n\n// ============================================================================\n// Provider\n// ============================================================================\n\ninterface LocaleScopeProviderProps {\n\tchildren: React.ReactNode;\n\t/** Initial locale (defaults to current global content locale) */\n\tinitialLocale?: string;\n}\n\n/**\n * Provides an isolated locale scope for nested forms.\n * Locale changes inside this provider don't affect the global state.\n */\nexport function LocaleScopeProvider({\n\tchildren,\n\tinitialLocale,\n}: LocaleScopeProviderProps) {\n\tconst globalLocale = useAdminStore(selectContentLocale);\n\tconst [scopedLocale, setScopedLocale] = React.useState(\n\t\tinitialLocale ?? globalLocale,\n\t);\n\n\t// Sync with global locale on mount or when global changes (only if not yet modified)\n\tconst hasModifiedRef = React.useRef(false);\n\tReact.useEffect(() => {\n\t\tif (!hasModifiedRef.current) {\n\t\t\tsetScopedLocale(globalLocale);\n\t\t}\n\t}, [globalLocale]);\n\n\tconst setLocale = React.useCallback((locale: string) => {\n\t\thasModifiedRef.current = true;\n\t\tsetScopedLocale(locale);\n\t}, []);\n\n\tconst value = React.useMemo<LocaleScopeContextValue>(\n\t\t() => ({\n\t\t\tlocale: scopedLocale,\n\t\t\tsetLocale,\n\t\t\tisScoped: true,\n\t\t}),\n\t\t[scopedLocale, setLocale],\n\t);\n\n\treturn (\n\t\t<LocaleScopeContext.Provider value={value}>\n\t\t\t{children}\n\t\t</LocaleScopeContext.Provider>\n\t);\n}\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Returns scoped locale if in a LocaleScopeProvider, otherwise global locale.\n * Use this in components that need locale-aware behavior (FieldWrapper, FormView).\n */\nexport function useScopedLocale(): LocaleScopeContextValue {\n\tconst scopedContext = React.useContext(LocaleScopeContext);\n\tconst globalLocale = useAdminStore(selectContentLocale);\n\tconst globalSetLocale = useAdminStore(selectSetContentLocale);\n\n\t// If we're in a scoped context, use that\n\tif (scopedContext) {\n\t\treturn scopedContext;\n\t}\n\n\t// Otherwise, use global locale\n\treturn {\n\t\tlocale: globalLocale,\n\t\tsetLocale: globalSetLocale,\n\t\tisScoped: false,\n\t};\n}\n\n/**\n * Returns true if we're currently in a scoped locale context (nested form).\n */\nexport function useIsLocaleScopeActive(): boolean {\n\tconst scopedContext = React.useContext(LocaleScopeContext);\n\treturn scopedContext !== null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAM,qBAAqBA,QAAM,cAChC,KACA;;;;;AAgBD,SAAgB,oBAAoB,EACnC,UACA,iBAC4B;CAC5B,MAAM,eAAe,cAAc,oBAAoB;CACvD,MAAM,CAAC,cAAc,mBAAmBA,QAAM,SAC7C,iBAAiB,aACjB;CAGD,MAAM,iBAAiBA,QAAM,OAAO,MAAM;AAC1C,SAAM,gBAAgB;AACrB,MAAI,CAAC,eAAe,QACnB,iBAAgB,aAAa;IAE5B,CAAC,aAAa,CAAC;CAElB,MAAM,YAAYA,QAAM,aAAa,WAAmB;AACvD,iBAAe,UAAU;AACzB,kBAAgB,OAAO;IACrB,EAAE,CAAC;CAEN,MAAM,QAAQA,QAAM,eACZ;EACN,QAAQ;EACR;EACA,UAAU;EACV,GACD,CAAC,cAAc,UAAU,CACzB;AAED,QACC,oBAAC,mBAAmB;EAAgB;EAClC;GAC4B;;;;;;AAYhC,SAAgB,kBAA2C;CAC1D,MAAM,gBAAgBA,QAAM,WAAW,mBAAmB;CAC1D,MAAM,eAAe,cAAc,oBAAoB;CACvD,MAAM,kBAAkB,cAAc,uBAAuB;AAG7D,KAAI,cACH,QAAO;AAIR,QAAO;EACN,QAAQ;EACR,WAAW;EACX,UAAU;EACV"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/shared/types/saved-views.types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Saved Views Types
|
|
4
|
+
*
|
|
5
|
+
* Shared types used by both server and client code.
|
|
6
|
+
* This file must NOT import any server-only dependencies like drizzle-orm.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Filter operator types supported by the saved views filter builder
|
|
10
|
+
*/
|
|
11
|
+
type FilterOperator = "equals" | "not_equals" | "contains" | "not_contains" | "starts_with" | "ends_with" | "greater_than" | "less_than" | "greater_than_or_equal" | "less_than_or_equal" | "in" | "not_in" | "some" | "every" | "none" | "is_empty" | "is_not_empty";
|
|
12
|
+
/**
|
|
13
|
+
* Filter value type
|
|
14
|
+
*/
|
|
15
|
+
type FilterValue = string | number | boolean | Array<string | number | boolean> | null;
|
|
16
|
+
/**
|
|
17
|
+
* A single filter rule configuration
|
|
18
|
+
*/
|
|
19
|
+
interface FilterRule {
|
|
20
|
+
id: string;
|
|
21
|
+
field: string;
|
|
22
|
+
operator: FilterOperator;
|
|
23
|
+
value: FilterValue;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Sort configuration for a view
|
|
27
|
+
*/
|
|
28
|
+
interface SortConfig {
|
|
29
|
+
field: string;
|
|
30
|
+
direction: "asc" | "desc";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Complete view configuration stored in the database
|
|
34
|
+
*/
|
|
35
|
+
interface ViewConfiguration {
|
|
36
|
+
filters: FilterRule[];
|
|
37
|
+
sortConfig: SortConfig | null;
|
|
38
|
+
visibleColumns: string[];
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { ViewConfiguration as i, FilterRule as n, SortConfig as r, FilterOperator as t };
|
|
42
|
+
//# sourceMappingURL=saved-views.types-BMsz5mCy.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saved-views.types-BMsz5mCy.d.mts","names":[],"sources":["../src/shared/types/saved-views.types.ts"],"sourcesContent":[],"mappings":";;AAUA;AAsBA;AAUA;AAUA;AAQA;;;;KAlDY,cAAA;;;;KAsBA,WAAA,+BAIT;;;;UAMc,UAAA;;;YAGN;SACH;;;;;UAMS,UAAA;;;;;;;UAQA,iBAAA;WACP;cACG"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { a as PreviewTokenPayload, c as verifyPreviewTokenDirect, d as GetAdminSessionOptions, f as RequireAdminAuthOptions, h as requireAdminAuth, i as setupFunctions, l as savedViewsCollection, m as isAdminUser, n as createFirstAdmin, o as createPreviewFunctions, p as getAdminSession, r as isSetupRequired, s as createPreviewTokenVerifier, t as adminModule, u as AuthSession } from "./index-B9Xwk4hi.mjs";
|
|
2
|
+
import { i as ViewConfiguration, n as FilterRule, r as SortConfig, t as FilterOperator } from "./saved-views.types-BMsz5mCy.mjs";
|
|
3
|
+
import { Questpie } from "questpie";
|
|
4
|
+
|
|
5
|
+
//#region src/server/adapters/tanstack.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for TanStack auth guard
|
|
9
|
+
*/
|
|
10
|
+
interface TanStackAuthGuardOptions {
|
|
11
|
+
/**
|
|
12
|
+
* The CMS instance with auth configured
|
|
13
|
+
*/
|
|
14
|
+
cms: Questpie<any>;
|
|
15
|
+
/**
|
|
16
|
+
* Path to redirect to when not authenticated
|
|
17
|
+
* @default "/admin/login"
|
|
18
|
+
*/
|
|
19
|
+
loginPath?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Required role for access
|
|
22
|
+
* @default "admin"
|
|
23
|
+
*/
|
|
24
|
+
requiredRole?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Query parameter name for redirect URL
|
|
27
|
+
* @default "redirect"
|
|
28
|
+
*/
|
|
29
|
+
redirectParam?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Context passed to TanStack Router beforeLoad
|
|
33
|
+
*/
|
|
34
|
+
interface BeforeLoadContext {
|
|
35
|
+
context: {
|
|
36
|
+
request: Request;
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
};
|
|
39
|
+
[key: string]: unknown;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a TanStack Router beforeLoad guard for admin authentication.
|
|
43
|
+
*
|
|
44
|
+
* Returns a function that can be used as beforeLoad in route definitions.
|
|
45
|
+
* Throws a redirect Response when authentication fails.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { createFileRoute } from "@tanstack/react-router";
|
|
50
|
+
* import { createTanStackAuthGuard } from "@questpie/admin/server/adapters/tanstack";
|
|
51
|
+
* import { cms } from "~/questpie/server/cms";
|
|
52
|
+
*
|
|
53
|
+
* export const Route = createFileRoute("/admin")({
|
|
54
|
+
* beforeLoad: createTanStackAuthGuard({
|
|
55
|
+
* cms,
|
|
56
|
+
* loginPath: "/admin/login",
|
|
57
|
+
* requiredRole: "admin",
|
|
58
|
+
* }),
|
|
59
|
+
* component: AdminLayout,
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @example With custom context
|
|
64
|
+
* ```ts
|
|
65
|
+
* export const Route = createFileRoute("/admin")({
|
|
66
|
+
* beforeLoad: async (ctx) => {
|
|
67
|
+
* // Run auth guard
|
|
68
|
+
* await createTanStackAuthGuard({ cms })(ctx);
|
|
69
|
+
*
|
|
70
|
+
* // Add additional context
|
|
71
|
+
* return { user: ctx.context.user };
|
|
72
|
+
* },
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
declare function createTanStackAuthGuard({
|
|
77
|
+
cms,
|
|
78
|
+
loginPath,
|
|
79
|
+
requiredRole,
|
|
80
|
+
redirectParam
|
|
81
|
+
}: TanStackAuthGuardOptions): ({
|
|
82
|
+
context
|
|
83
|
+
}: BeforeLoadContext) => Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Create a TanStack Router loader that injects the admin session into context.
|
|
86
|
+
*
|
|
87
|
+
* Use this when you need access to the session in your components.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* import { createTanStackSessionLoader } from "@questpie/admin/server/adapters/tanstack";
|
|
92
|
+
*
|
|
93
|
+
* export const Route = createFileRoute("/admin")({
|
|
94
|
+
* loader: createTanStackSessionLoader({ cms }),
|
|
95
|
+
* component: AdminLayout,
|
|
96
|
+
* });
|
|
97
|
+
*
|
|
98
|
+
* function AdminLayout() {
|
|
99
|
+
* const { session } = Route.useLoaderData();
|
|
100
|
+
* return <div>Hello {session?.user?.name}</div>;
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
declare function createTanStackSessionLoader({
|
|
105
|
+
cms
|
|
106
|
+
}: {
|
|
107
|
+
cms: Questpie<any>;
|
|
108
|
+
}): ({
|
|
109
|
+
context
|
|
110
|
+
}: BeforeLoadContext) => Promise<{
|
|
111
|
+
session: {
|
|
112
|
+
session: {
|
|
113
|
+
id: string;
|
|
114
|
+
createdAt: Date;
|
|
115
|
+
updatedAt: Date;
|
|
116
|
+
userId: string;
|
|
117
|
+
expiresAt: Date;
|
|
118
|
+
token: string;
|
|
119
|
+
ipAddress?: string | null | undefined | undefined;
|
|
120
|
+
userAgent?: string | null | undefined | undefined;
|
|
121
|
+
};
|
|
122
|
+
user: {
|
|
123
|
+
id: string;
|
|
124
|
+
createdAt: Date;
|
|
125
|
+
updatedAt: Date;
|
|
126
|
+
email: string;
|
|
127
|
+
emailVerified: boolean;
|
|
128
|
+
name: string;
|
|
129
|
+
image?: string | null | undefined | undefined;
|
|
130
|
+
};
|
|
131
|
+
} | null;
|
|
132
|
+
}>;
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/server/adapters/nextjs.d.ts
|
|
135
|
+
/**
|
|
136
|
+
* Options for Next.js auth middleware
|
|
137
|
+
*/
|
|
138
|
+
interface NextAuthMiddlewareOptions {
|
|
139
|
+
/**
|
|
140
|
+
* The CMS instance with auth configured
|
|
141
|
+
*/
|
|
142
|
+
cms: Questpie<any>;
|
|
143
|
+
/**
|
|
144
|
+
* Path to redirect to when not authenticated
|
|
145
|
+
* @default "/admin/login"
|
|
146
|
+
*/
|
|
147
|
+
loginPath?: string;
|
|
148
|
+
/**
|
|
149
|
+
* Required role for access
|
|
150
|
+
* @default "admin"
|
|
151
|
+
*/
|
|
152
|
+
requiredRole?: string;
|
|
153
|
+
/**
|
|
154
|
+
* Paths that require authentication (uses startsWith matching)
|
|
155
|
+
* @default ["/admin"]
|
|
156
|
+
*/
|
|
157
|
+
protectedPaths?: string[];
|
|
158
|
+
/**
|
|
159
|
+
* Paths within protectedPaths that should be publicly accessible
|
|
160
|
+
* @default ["/admin/login", "/admin/forgot-password", "/admin/reset-password", "/admin/accept-invite"]
|
|
161
|
+
*/
|
|
162
|
+
publicPaths?: string[];
|
|
163
|
+
/**
|
|
164
|
+
* Query parameter name for redirect URL
|
|
165
|
+
* @default "redirect"
|
|
166
|
+
*/
|
|
167
|
+
redirectParam?: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Create a Next.js middleware for admin authentication.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* // middleware.ts
|
|
175
|
+
* import { createNextAuthMiddleware } from "@questpie/admin/server/adapters/nextjs";
|
|
176
|
+
* import { cms } from "./questpie/server/cms";
|
|
177
|
+
*
|
|
178
|
+
* export default createNextAuthMiddleware({
|
|
179
|
+
* cms,
|
|
180
|
+
* loginPath: "/admin/login",
|
|
181
|
+
* });
|
|
182
|
+
*
|
|
183
|
+
* export const config = {
|
|
184
|
+
* matcher: ["/admin/:path*"],
|
|
185
|
+
* };
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
declare function createNextAuthMiddleware({
|
|
189
|
+
cms,
|
|
190
|
+
loginPath,
|
|
191
|
+
requiredRole,
|
|
192
|
+
protectedPaths,
|
|
193
|
+
publicPaths,
|
|
194
|
+
redirectParam
|
|
195
|
+
}: NextAuthMiddlewareOptions): (request: Request) => Promise<Response>;
|
|
196
|
+
/**
|
|
197
|
+
* Get the admin session in a Next.js server component or API route.
|
|
198
|
+
*
|
|
199
|
+
* @example Server Component
|
|
200
|
+
* ```tsx
|
|
201
|
+
* // app/admin/layout.tsx
|
|
202
|
+
* import { getNextAdminSession } from "@questpie/admin/server/adapters/nextjs";
|
|
203
|
+
* import { headers } from "next/headers";
|
|
204
|
+
* import { cms } from "~/questpie/server/cms";
|
|
205
|
+
*
|
|
206
|
+
* export default async function AdminLayout({ children }) {
|
|
207
|
+
* const headersList = headers();
|
|
208
|
+
* const session = await getNextAdminSession({
|
|
209
|
+
* headers: headersList,
|
|
210
|
+
* cms,
|
|
211
|
+
* });
|
|
212
|
+
*
|
|
213
|
+
* if (!session) {
|
|
214
|
+
* redirect("/admin/login");
|
|
215
|
+
* }
|
|
216
|
+
*
|
|
217
|
+
* return <div>{children}</div>;
|
|
218
|
+
* }
|
|
219
|
+
* ```
|
|
220
|
+
*
|
|
221
|
+
* @example API Route
|
|
222
|
+
* ```ts
|
|
223
|
+
* // app/api/admin/users/route.ts
|
|
224
|
+
* import { getNextAdminSession } from "@questpie/admin/server/adapters/nextjs";
|
|
225
|
+
* import { cms } from "~/questpie/server/cms";
|
|
226
|
+
*
|
|
227
|
+
* export async function GET(request: Request) {
|
|
228
|
+
* const session = await getNextAdminSession({
|
|
229
|
+
* headers: request.headers,
|
|
230
|
+
* cms,
|
|
231
|
+
* });
|
|
232
|
+
*
|
|
233
|
+
* if (!session || session.user.role !== "admin") {
|
|
234
|
+
* return Response.json({ error: "Unauthorized" }, { status: 401 });
|
|
235
|
+
* }
|
|
236
|
+
*
|
|
237
|
+
* // ... handle request
|
|
238
|
+
* }
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
declare function getNextAdminSession({
|
|
242
|
+
headers,
|
|
243
|
+
cms
|
|
244
|
+
}: {
|
|
245
|
+
headers: Headers;
|
|
246
|
+
cms: Questpie<any>;
|
|
247
|
+
}): Promise<AuthSession | null>;
|
|
248
|
+
//#endregion
|
|
249
|
+
export { AuthSession, BeforeLoadContext, FilterOperator, FilterRule, GetAdminSessionOptions, NextAuthMiddlewareOptions, PreviewTokenPayload, RequireAdminAuthOptions, SortConfig, TanStackAuthGuardOptions, ViewConfiguration, adminModule, createFirstAdmin, createNextAuthMiddleware, createPreviewFunctions, createPreviewTokenVerifier, createTanStackAuthGuard, createTanStackSessionLoader, getAdminSession, getNextAdminSession, isAdminUser, isSetupRequired, requireAdminAuth, savedViewsCollection, setupFunctions, verifyPreviewTokenDirect };
|
|
250
|
+
//# sourceMappingURL=server.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.mts","names":[],"sources":["../src/server/adapters/tanstack.ts","../src/server/adapters/nextjs.ts"],"sourcesContent":[],"mappings":";;;;;;;AAiJA;;AAA4D,UA3H3C,wBAAA,CA2H2C;EAC7B;;;OAxHxB;;;;;EAwHsD,SAAA,CAAA,EAAA,MAAA;;;;ACpH7D;EAoEgB,YAAA,CAAA,EAAA,MAAA;EACd;;;;EAIA,aAAA,CAAA,EAAA,MAAA;;;;;AAQoD,UD7DrC,iBAAA,CC6DqC;EAAO,OAAA,EAAA;IAyFvC,OAAA,EDpJT,OCoJS;IACpB,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EACA,CAAA;EAES,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBD/GK,uBAAA;;;;;GAKb;;GAC6C,sBAAiB;;;;;;;;;;;;;;;;;;;;;iBA8CjD,2BAAA;;;OAA4C;;;GAChB,sBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,UCpH5C,yBAAA,CDoH4C;EAAA;;;OChHtD;EAJU;AAoEjB;;;EAGE,SAAA,CAAA,EAAA,MAAA;EACA;;;;EAS0C,YAAA,CAAA,EAAA,MAAA;EAAkB;;;AAyF9D;EACE,cAAA,CAAA,EAAA,MAAA,EAAA;EACA;;;;EAID,WAAA,CAAA,EAAA,MAAA,EAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;iBA5Ge,wBAAA;;;;;;;GAYb,sCACyC,YAAU,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyFxC,mBAAA;;;;WAIX;OACJ;IACN,QADc,WAAA"}
|