@nextjscms/plugin-cpanel-emails 1.1.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/dist/client/EmailsPage.d.ts +6 -0
- package/dist/client/EmailsPage.d.ts.map +1 -0
- package/dist/client/EmailsPage.js +42 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/router.d.ts +63 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +136 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +25 -0
- package/package.json +41 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailsPage.d.ts","sourceRoot":"","sources":["../../src/client/EmailsPage.tsx"],"names":[],"mappings":"AA6CA,KAAK,qBAAqB,GAAG;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,WAAW,qBAAqB,4CAiDhE,CAAA;AA0ID,eAAe,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { trpc as trpcClient } from 'nextjs-cms/api/trpc/client';
|
|
5
|
+
import { useI18n } from 'nextjs-cms/translations/client';
|
|
6
|
+
export const CpanelEmailsPage = ({ title }) => {
|
|
7
|
+
const t = useI18n();
|
|
8
|
+
const trpc = trpcClient;
|
|
9
|
+
const query = trpc?.cpanelEmails?.getEmails.useQuery;
|
|
10
|
+
const { data, isLoading, isError, error, refetch } = query
|
|
11
|
+
? query()
|
|
12
|
+
: { isLoading: true, isError: true, error: null, refetch: async () => undefined };
|
|
13
|
+
if (!query) {
|
|
14
|
+
return _jsx("div", { className: 'p-6 text-sm text-red-500', children: "cPanel emails plugin misconfigured: missing trpc client." });
|
|
15
|
+
}
|
|
16
|
+
const pluginApi = trpc.cpanelEmails;
|
|
17
|
+
const createEmailMutation = pluginApi.createEmail.useMutation({ onSuccess: () => refetch() });
|
|
18
|
+
const quotaMutation = pluginApi.quotaChange.useMutation({ onSuccess: () => refetch() });
|
|
19
|
+
const passwordMutation = pluginApi.passwordChange.useMutation({ onSuccess: () => refetch() });
|
|
20
|
+
const deleteMutation = pluginApi.deleteEmail.useMutation({ onSuccess: () => refetch() });
|
|
21
|
+
return (_jsxs("div", { className: 'bg-white dark:bg-slate-900', children: [_jsx("div", { className: 'bg-linear-to-r from-sky-200 via-emerald-300 to-blue-600 p-8 font-extrabold text-foreground dark:from-blue-800 dark:via-amber-700 dark:to-rose-900', children: _jsx("h1", { className: 'text-3xl', children: title || t('emailAccounts') }) }), _jsxs("div", { className: 'flex flex-col gap-3 p-4', children: [_jsx(CreateEmailForm, { onSubmit: createEmailMutation.mutateAsync, isSubmitting: !!createEmailMutation.isPending }), isLoading && _jsx("div", { className: 'text-muted-foreground', children: "Loading emails\u2026" }), isError && !isLoading && (_jsx("div", { className: 'rounded border border-destructive/50 bg-destructive/10 p-3 text-sm text-destructive', children: error instanceof Error ? error.message : 'Unable to load emails' })), data?.emails?.length ? (_jsx("div", { className: 'grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3', children: data.emails.map((email) => (_jsx(EmailCard, { email: email, onDelete: () => deleteMutation.mutateAsync(email.user), onQuotaChange: (quota) => quotaMutation.mutateAsync({ email: email.user, quota }), onPasswordChange: (password, confirm) => passwordMutation.mutateAsync({ email: email.user, password, passwordConfirm: confirm }) }, email.user))) })) : null] })] }));
|
|
22
|
+
};
|
|
23
|
+
const CreateEmailForm = ({ onSubmit, isSubmitting, }) => {
|
|
24
|
+
const [email, setEmail] = useState('');
|
|
25
|
+
const [password, setPassword] = useState('');
|
|
26
|
+
const [quota, setQuota] = useState('1024');
|
|
27
|
+
const t = useI18n();
|
|
28
|
+
return (_jsxs("form", { className: 'rounded-lg border bg-card p-4 text-card-foreground shadow-sm', onSubmit: async (e) => {
|
|
29
|
+
e.preventDefault();
|
|
30
|
+
await onSubmit({ email, password, quota });
|
|
31
|
+
setEmail('');
|
|
32
|
+
setPassword('');
|
|
33
|
+
}, children: [_jsx("div", { className: 'text-lg font-semibold', children: t('createNewEmailAccount') }), _jsxs("div", { className: 'mt-3 grid grid-cols-1 gap-3 md:grid-cols-3', children: [_jsx("input", { className: 'rounded border px-3 py-2 text-sm', value: email, onChange: (e) => setEmail(e.target.value), placeholder: t('email'), required: true }), _jsx("input", { className: 'rounded border px-3 py-2 text-sm', type: 'password', value: password, onChange: (e) => setPassword(e.target.value), placeholder: t('password'), required: true }), _jsx("input", { className: 'rounded border px-3 py-2 text-sm', value: quota, onChange: (e) => setQuota(e.target.value), placeholder: t('quota'), required: true })] }), _jsx("button", { type: 'submit', disabled: isSubmitting, className: 'mt-3 inline-flex items-center justify-center rounded bg-primary px-4 py-2 text-sm font-semibold text-primary-foreground shadow-sm hover:opacity-90 disabled:opacity-50', children: isSubmitting ? t('loading') + '…' : t('create') })] }));
|
|
34
|
+
};
|
|
35
|
+
const EmailCard = ({ email, onDelete, onQuotaChange, onPasswordChange, }) => {
|
|
36
|
+
const [quota, setQuota] = useState(email.diskquota);
|
|
37
|
+
const [password, setPassword] = useState('');
|
|
38
|
+
const [confirm, setConfirm] = useState('');
|
|
39
|
+
const t = useI18n();
|
|
40
|
+
return (_jsxs("div", { className: 'rounded-lg border bg-card p-4 text-card-foreground shadow-sm', children: [_jsxs("div", { className: 'flex items-center justify-between', children: [_jsx("div", { className: 'font-semibold', children: email.user }), _jsx("button", { className: 'text-sm text-destructive hover:underline', type: 'button', onClick: () => onDelete(), children: t('delete') })] }), _jsxs("div", { className: 'mt-2 text-sm text-muted-foreground', children: [_jsxs("div", { children: ["Disk Used: ", email.diskusedpercent, " / ", email.diskquota] }), _jsxs("div", { children: ["Login: ", email.user] })] }), _jsxs("div", { className: 'mt-3 space-y-2 text-sm', children: [_jsxs("label", { className: 'block', children: [_jsx("span", { className: 'text-xs text-muted-foreground', children: "Quota" }), _jsx("input", { className: 'mt-1 w-full rounded border px-3 py-2', value: quota, onChange: (e) => setQuota(e.target.value) }), _jsx("button", { type: 'button', className: 'mt-1 inline-flex items-center justify-center rounded bg-primary px-3 py-1 text-xs font-semibold text-primary-foreground hover:opacity-90', onClick: () => onQuotaChange(quota), children: t('update') })] }), _jsxs("label", { className: 'block', children: [_jsx("span", { className: 'text-xs text-muted-foreground', children: "Password" }), _jsx("input", { className: 'mt-1 w-full rounded border px-3 py-2', type: 'password', value: password, onChange: (e) => setPassword(e.target.value) })] }), _jsxs("label", { className: 'block', children: [_jsx("span", { className: 'text-xs text-muted-foreground', children: "Confirm" }), _jsx("input", { className: 'mt-1 w-full rounded border px-3 py-2', type: 'password', value: confirm, onChange: (e) => setConfirm(e.target.value) })] }), _jsx("button", { type: 'button', className: 'inline-flex items-center justify-center rounded bg-primary px-3 py-1 text-xs font-semibold text-primary-foreground hover:opacity-90', onClick: () => onPasswordChange(password, confirm), children: t('changePassword') })] })] }));
|
|
41
|
+
};
|
|
42
|
+
export default CpanelEmailsPage;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,wBAAgB,YAAY,6DAc3B"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { definePlugin } from 'nextjs-cms/plugins/server';
|
|
2
|
+
import { cpanelEmailsRouter } from './router.js';
|
|
3
|
+
export function createPlugin() {
|
|
4
|
+
return definePlugin({
|
|
5
|
+
title: 'cPanel Emails',
|
|
6
|
+
name: 'plugin_cpanel_emails',
|
|
7
|
+
registryName: 'cpanel-emails',
|
|
8
|
+
router: cpanelEmailsRouter,
|
|
9
|
+
routes: [
|
|
10
|
+
{
|
|
11
|
+
path: '/cpanel-emails',
|
|
12
|
+
title: 'cPanel Emails',
|
|
13
|
+
icon: 'mail',
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
export declare const cpanelEmailsRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
3
|
+
ctx: {
|
|
4
|
+
headers: Headers;
|
|
5
|
+
db: import("drizzle-orm/mysql2").MySql2Database<typeof import("nextjs-cms/db/schema")> & {
|
|
6
|
+
$client: import("mysql2/promise").Pool;
|
|
7
|
+
};
|
|
8
|
+
session: import("nextjs-cms").Session | null;
|
|
9
|
+
};
|
|
10
|
+
meta: object;
|
|
11
|
+
errorShape: {
|
|
12
|
+
data: {
|
|
13
|
+
zodError: import("zod").ZodFlattenedError<unknown, string> | null;
|
|
14
|
+
code: import("@trpc/server").TRPC_ERROR_CODE_KEY;
|
|
15
|
+
httpStatus: number;
|
|
16
|
+
path?: string;
|
|
17
|
+
stack?: string;
|
|
18
|
+
};
|
|
19
|
+
message: string;
|
|
20
|
+
code: import("@trpc/server").TRPC_ERROR_CODE_NUMBER;
|
|
21
|
+
};
|
|
22
|
+
transformer: true;
|
|
23
|
+
}, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
|
|
24
|
+
getEmails: import("@trpc/server").TRPCQueryProcedure<{
|
|
25
|
+
input: void;
|
|
26
|
+
output: {
|
|
27
|
+
emails: any;
|
|
28
|
+
};
|
|
29
|
+
meta: object;
|
|
30
|
+
}>;
|
|
31
|
+
createEmail: import("@trpc/server").TRPCMutationProcedure<{
|
|
32
|
+
input: {
|
|
33
|
+
email: string;
|
|
34
|
+
password: string;
|
|
35
|
+
quota: string;
|
|
36
|
+
};
|
|
37
|
+
output: any;
|
|
38
|
+
meta: object;
|
|
39
|
+
}>;
|
|
40
|
+
quotaChange: import("@trpc/server").TRPCMutationProcedure<{
|
|
41
|
+
input: {
|
|
42
|
+
email: string;
|
|
43
|
+
quota: string;
|
|
44
|
+
};
|
|
45
|
+
output: any;
|
|
46
|
+
meta: object;
|
|
47
|
+
}>;
|
|
48
|
+
passwordChange: import("@trpc/server").TRPCMutationProcedure<{
|
|
49
|
+
input: {
|
|
50
|
+
email: string;
|
|
51
|
+
password: string;
|
|
52
|
+
passwordConfirm: string;
|
|
53
|
+
};
|
|
54
|
+
output: any;
|
|
55
|
+
meta: object;
|
|
56
|
+
}>;
|
|
57
|
+
deleteEmail: import("@trpc/server").TRPCMutationProcedure<{
|
|
58
|
+
input: string;
|
|
59
|
+
output: any;
|
|
60
|
+
meta: object;
|
|
61
|
+
}>;
|
|
62
|
+
}>>;
|
|
63
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAKxB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;gBAkDf,CAAf;iBAA2B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwH3B,CAAA"}
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { TRPCError } from '@trpc/server';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import getString from 'nextjs-cms/translations';
|
|
4
|
+
import { CpanelAPI } from 'nextjs-cms/utils';
|
|
5
|
+
import { pluginProcedure, router } from 'nextjs-cms/api/trpc';
|
|
6
|
+
export const cpanelEmailsRouter = router({
|
|
7
|
+
getEmails: pluginProcedure('plugin_cpanel_emails').query(async ({ ctx }) => {
|
|
8
|
+
if (!process.env.CPANEL_USER || !process.env.CPANEL_PASSWORD || !process.env.CPANEL_DOMAIN) {
|
|
9
|
+
throw new TRPCError({
|
|
10
|
+
code: 'BAD_REQUEST',
|
|
11
|
+
message: getString('cpanelCredentialsNotSet', ctx.session.user.locale),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const cPanel = new CpanelAPI(process.env.CPANEL_USER, process.env.CPANEL_PASSWORD, `cpanel.${process.env.CPANEL_DOMAIN}`);
|
|
15
|
+
const data = await cPanel.callApi('Email', 'list_pops_with_disk', {
|
|
16
|
+
domain: process.env.CPANEL_DOMAIN,
|
|
17
|
+
maxaccounts: 100,
|
|
18
|
+
no_validate: 1,
|
|
19
|
+
infinitylang: 1,
|
|
20
|
+
'api.sort': '1',
|
|
21
|
+
'api.sort_column': 'mtime',
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
emails: data.data,
|
|
25
|
+
};
|
|
26
|
+
}),
|
|
27
|
+
createEmail: pluginProcedure('plugin_cpanel_emails', 'C')
|
|
28
|
+
.input(z.object({
|
|
29
|
+
email: z.string(),
|
|
30
|
+
password: z.string(),
|
|
31
|
+
quota: z.string(),
|
|
32
|
+
}))
|
|
33
|
+
.mutation(async ({ input, ctx }) => {
|
|
34
|
+
if (!process.env.CPANEL_USER || !process.env.CPANEL_PASSWORD || !process.env.CPANEL_DOMAIN) {
|
|
35
|
+
throw new TRPCError({
|
|
36
|
+
code: 'BAD_REQUEST',
|
|
37
|
+
message: getString('cpanelCredentialsNotSet', ctx.session.user.locale),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const cPanel = new CpanelAPI(process.env.CPANEL_USER, process.env.CPANEL_PASSWORD, `cpanel.${process.env.CPANEL_DOMAIN}`);
|
|
41
|
+
const data = await cPanel.callApi('Email', 'add_pop', {
|
|
42
|
+
domain: process.env.CPANEL_DOMAIN,
|
|
43
|
+
email: input.email,
|
|
44
|
+
password: input.password,
|
|
45
|
+
quota: input.quota,
|
|
46
|
+
});
|
|
47
|
+
if (cPanel.isError) {
|
|
48
|
+
throw new TRPCError({
|
|
49
|
+
code: 'BAD_REQUEST',
|
|
50
|
+
message: cPanel.getError(),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return data;
|
|
54
|
+
}),
|
|
55
|
+
quotaChange: pluginProcedure('plugin_cpanel_emails', 'U')
|
|
56
|
+
.input(z.object({
|
|
57
|
+
email: z.string(),
|
|
58
|
+
quota: z.string(),
|
|
59
|
+
}))
|
|
60
|
+
.mutation(async ({ input, ctx }) => {
|
|
61
|
+
if (!process.env.CPANEL_USER || !process.env.CPANEL_PASSWORD || !process.env.CPANEL_DOMAIN) {
|
|
62
|
+
throw new TRPCError({
|
|
63
|
+
code: 'BAD_REQUEST',
|
|
64
|
+
message: getString('cpanelCredentialsNotSet', ctx.session.user.locale),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const cPanel = new CpanelAPI(process.env.CPANEL_USER, process.env.CPANEL_PASSWORD, `cpanel.${process.env.CPANEL_DOMAIN}`);
|
|
68
|
+
const data = await cPanel.callApi('Email', 'edit_pop_quota', {
|
|
69
|
+
domain: process.env.CPANEL_DOMAIN,
|
|
70
|
+
email: input.email,
|
|
71
|
+
quota: input.quota,
|
|
72
|
+
});
|
|
73
|
+
if (cPanel.isError) {
|
|
74
|
+
throw new TRPCError({
|
|
75
|
+
code: 'BAD_REQUEST',
|
|
76
|
+
message: cPanel.getError(),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return data;
|
|
80
|
+
}),
|
|
81
|
+
passwordChange: pluginProcedure('plugin_cpanel_emails', 'U')
|
|
82
|
+
.input(z.object({
|
|
83
|
+
email: z.string(),
|
|
84
|
+
password: z.string(),
|
|
85
|
+
passwordConfirm: z.string(),
|
|
86
|
+
}))
|
|
87
|
+
.mutation(async ({ input, ctx }) => {
|
|
88
|
+
if (!process.env.CPANEL_USER || !process.env.CPANEL_PASSWORD || !process.env.CPANEL_DOMAIN) {
|
|
89
|
+
throw new TRPCError({
|
|
90
|
+
code: 'BAD_REQUEST',
|
|
91
|
+
message: getString('cpanelCredentialsNotSet', ctx.session.user.locale),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (input.password !== input.passwordConfirm) {
|
|
95
|
+
throw new TRPCError({
|
|
96
|
+
code: 'BAD_REQUEST',
|
|
97
|
+
message: getString('passwordsDoNotMatch', ctx.session.user.locale),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const cPanel = new CpanelAPI(process.env.CPANEL_USER, process.env.CPANEL_PASSWORD, `cpanel.${process.env.CPANEL_DOMAIN}`);
|
|
101
|
+
const data = await cPanel.callApi('Email', 'passwd_pop', {
|
|
102
|
+
domain: process.env.CPANEL_DOMAIN,
|
|
103
|
+
email: input.email,
|
|
104
|
+
password: input.password,
|
|
105
|
+
});
|
|
106
|
+
if (cPanel.isError) {
|
|
107
|
+
throw new TRPCError({
|
|
108
|
+
code: 'BAD_REQUEST',
|
|
109
|
+
message: cPanel.getError(),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return data;
|
|
113
|
+
}),
|
|
114
|
+
deleteEmail: pluginProcedure('plugin_cpanel_emails', 'D')
|
|
115
|
+
.input(z.string())
|
|
116
|
+
.mutation(async ({ input, ctx }) => {
|
|
117
|
+
if (!process.env.CPANEL_USER || !process.env.CPANEL_PASSWORD || !process.env.CPANEL_DOMAIN) {
|
|
118
|
+
throw new TRPCError({
|
|
119
|
+
code: 'BAD_REQUEST',
|
|
120
|
+
message: getString('cpanelCredentialsNotSet', ctx.session.user.locale),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const cPanel = new CpanelAPI(process.env.CPANEL_USER, process.env.CPANEL_PASSWORD, `cpanel.${process.env.CPANEL_DOMAIN}`);
|
|
124
|
+
const data = await cPanel.callApi('Email', 'delete_pop', {
|
|
125
|
+
domain: process.env.CPANEL_DOMAIN,
|
|
126
|
+
email: input,
|
|
127
|
+
});
|
|
128
|
+
if (cPanel.isError) {
|
|
129
|
+
throw new TRPCError({
|
|
130
|
+
code: 'BAD_REQUEST',
|
|
131
|
+
message: cPanel.getError(),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return data;
|
|
135
|
+
}),
|
|
136
|
+
});
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.tsx"],"names":[],"mappings":"AAOA,wBAA8B,kBAAkB,qDA6B/C"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { api, HydrateClient } from 'nextjs-cms/api/trpc/server';
|
|
3
|
+
import { CpanelEmailsPage } from './client/EmailsPage.js';
|
|
4
|
+
import { findPluginRouteByPath } from 'nextjs-cms/plugins/server';
|
|
5
|
+
import { resolveLocalizedString, resolveLocale } from 'nextjs-cms/translations';
|
|
6
|
+
import { getCMSConfig } from 'nextjs-cms/core';
|
|
7
|
+
import auth from 'nextjs-cms/auth';
|
|
8
|
+
export default async function CpanelEmailsServer() {
|
|
9
|
+
const helpers = api;
|
|
10
|
+
const prefetch = helpers.cpanelEmails?.getEmails?.prefetch;
|
|
11
|
+
if (!prefetch) {
|
|
12
|
+
throw new Error('[cpanel-emails] Missing cpanelEmails.getEmails prefetch helper.');
|
|
13
|
+
}
|
|
14
|
+
await prefetch();
|
|
15
|
+
// Resolve the plugin route title
|
|
16
|
+
const [route, session, config] = await Promise.all([
|
|
17
|
+
findPluginRouteByPath('/cpanel-emails'),
|
|
18
|
+
auth(),
|
|
19
|
+
getCMSConfig(),
|
|
20
|
+
]);
|
|
21
|
+
const { supportedLanguages, fallbackLanguage } = config.i18n;
|
|
22
|
+
const locale = resolveLocale(session?.user?.locale, supportedLanguages, fallbackLanguage);
|
|
23
|
+
const resolvedTitle = route ? resolveLocalizedString(route.title, locale, fallbackLanguage) : '';
|
|
24
|
+
return (_jsx(HydrateClient, { children: _jsx(CpanelEmailsPage, { title: resolvedTitle }) }));
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nextjscms/plugin-cpanel-emails",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./server": {
|
|
13
|
+
"types": "./dist/server.d.ts",
|
|
14
|
+
"default": "./dist/server.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/**/*",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"private": false,
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@trpc/server": "^11.4.2",
|
|
24
|
+
"zod": "4.1.12"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"react": "19.2.3",
|
|
28
|
+
"react-dom": "19.2.3",
|
|
29
|
+
"nextjs-cms": "0.7.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/react": "^19.2.7",
|
|
33
|
+
"@types/react-dom": "^19.2.3",
|
|
34
|
+
"typescript": "^5.9.2"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"dev": "tsc --watch",
|
|
39
|
+
"clean": "git clean -xdf .cache .turbo dist node_modules"
|
|
40
|
+
}
|
|
41
|
+
}
|