@campfire-interactive/shell-header 0.1.1
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/index.d.ts +43 -0
- package/dist/index.js +221 -0
- package/package.json +41 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface AppDefinition {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
/** Local dev port (e.g., 3000). Omit if the app doesn't run locally. */
|
|
8
|
+
localPort?: number;
|
|
9
|
+
}
|
|
10
|
+
interface ShellUser {
|
|
11
|
+
name: string;
|
|
12
|
+
email: string;
|
|
13
|
+
avatarUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
interface ShellHeaderProps {
|
|
16
|
+
/** Current app ID — used to highlight the active app in the switcher */
|
|
17
|
+
appId: string;
|
|
18
|
+
/** Current user info for the avatar menu */
|
|
19
|
+
user: ShellUser;
|
|
20
|
+
/** App IDs the user is authorized to access in the current tenant */
|
|
21
|
+
authorizedApps: string[];
|
|
22
|
+
/** Unread notification count */
|
|
23
|
+
notificationCount?: number;
|
|
24
|
+
/** Called when the notification bell is clicked */
|
|
25
|
+
onNotificationClick?: () => void;
|
|
26
|
+
/** Called when logout is clicked */
|
|
27
|
+
onLogout?: () => void;
|
|
28
|
+
/** Optional center content (breadcrumbs, page title, etc.) */
|
|
29
|
+
children?: React.ReactNode;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
declare function ShellHeader({ appId, user, authorizedApps, notificationCount, onNotificationClick, onLogout, children, }: ShellHeaderProps): react_jsx_runtime.JSX.Element;
|
|
33
|
+
|
|
34
|
+
declare const appCatalog: AppDefinition[];
|
|
35
|
+
/**
|
|
36
|
+
* Derive the app URL from the current hostname.
|
|
37
|
+
* - localhost → localhost:<localPort>
|
|
38
|
+
* - *.dev.campfiresuite.com → <id>.dev.campfiresuite.com
|
|
39
|
+
* - *.campfiresuite.com → <id>.campfiresuite.com
|
|
40
|
+
*/
|
|
41
|
+
declare function getAppUrl(app: AppDefinition): string;
|
|
42
|
+
|
|
43
|
+
export { type AppDefinition, ShellHeader, type ShellHeaderProps, type ShellUser, appCatalog, getAppUrl };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// src/ShellHeader.tsx
|
|
2
|
+
import "@campfire-interactive/design-tokens/tokens.css";
|
|
3
|
+
|
|
4
|
+
// #style-inject:#style-inject
|
|
5
|
+
function styleInject(css, { insertAt } = {}) {
|
|
6
|
+
if (!css || typeof document === "undefined") return;
|
|
7
|
+
const head = document.head || document.getElementsByTagName("head")[0];
|
|
8
|
+
const style = document.createElement("style");
|
|
9
|
+
style.type = "text/css";
|
|
10
|
+
if (insertAt === "top") {
|
|
11
|
+
if (head.firstChild) {
|
|
12
|
+
head.insertBefore(style, head.firstChild);
|
|
13
|
+
} else {
|
|
14
|
+
head.appendChild(style);
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
head.appendChild(style);
|
|
18
|
+
}
|
|
19
|
+
if (style.styleSheet) {
|
|
20
|
+
style.styleSheet.cssText = css;
|
|
21
|
+
} else {
|
|
22
|
+
style.appendChild(document.createTextNode(css));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/styles.css
|
|
27
|
+
styleInject(".cfi-sh-header {\n display: flex;\n align-items: center;\n height: var(--cfi-shell-header-height, 48px);\n padding: 0 var(--cfi-spacing-md, 1rem);\n background: var(--cfi-color-gray-900, #111827);\n color: white;\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n box-shadow: var(--cfi-shadow-md, 0 4px 6px rgba(0, 0, 0, 0.07));\n position: relative;\n z-index: 50;\n}\n.cfi-sh-left {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n}\n.cfi-sh-center {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 var(--cfi-spacing-md, 1rem);\n overflow: hidden;\n}\n.cfi-sh-right {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 0.25rem);\n flex-shrink: 0;\n}\n.cfi-sh-app-switcher {\n position: relative;\n}\n.cfi-sh-app-trigger {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n padding: var(--cfi-spacing-xs, 0.25rem) var(--cfi-spacing-sm, 0.5rem);\n background: transparent;\n border: 1px solid transparent;\n border-radius: var(--cfi-radius-md, 0.375rem);\n color: white;\n cursor: pointer;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n font-family: inherit;\n transition: background 150ms, border-color 150ms;\n}\n.cfi-sh-app-trigger:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.15);\n}\n.cfi-sh-app-name {\n font-weight: 500;\n}\n.cfi-sh-chevron-open {\n transform: rotate(180deg);\n}\n.cfi-sh-app-dropdown {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 220px;\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n padding: var(--cfi-spacing-xs, 0.25rem);\n z-index: 100;\n}\n.cfi-sh-app-item {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n border-radius: var(--cfi-radius-md, 0.375rem);\n color: var(--cfi-color-gray-700, #374151);\n text-decoration: none;\n cursor: pointer;\n transition: background 100ms;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n font-family: inherit;\n}\n.cfi-sh-app-item:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-app-item-active {\n background: var(--cfi-color-primary-50, #fff7ed);\n color: var(--cfi-color-primary-700, #c2410c);\n font-weight: 500;\n}\n.cfi-sh-app-item-active:hover {\n background: var(--cfi-color-primary-100, #ffedd5);\n}\n.cfi-sh-icon-btn {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: transparent;\n border: none;\n border-radius: var(--cfi-radius-md, 0.375rem);\n color: var(--cfi-color-gray-300, #d1d5db);\n cursor: pointer;\n transition: background 150ms, color 150ms;\n}\n.cfi-sh-icon-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n color: white;\n}\n.cfi-sh-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--cfi-color-error, #ef4444);\n color: white;\n font-size: 10px;\n font-weight: 600;\n line-height: 16px;\n text-align: center;\n border-radius: 99px;\n}\n.cfi-sh-user-menu {\n position: relative;\n}\n.cfi-sh-avatar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: var(--cfi-color-primary-600, #ea580c);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: opacity 150ms;\n}\n.cfi-sh-avatar-btn:hover {\n opacity: 0.85;\n}\n.cfi-sh-avatar-img {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n object-fit: cover;\n}\n.cfi-sh-avatar-initials {\n color: white;\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-weight: 600;\n font-family: inherit;\n}\n.cfi-sh-user-dropdown {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 100;\n}\n.cfi-sh-user-header {\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n display: flex;\n flex-direction: column;\n}\n.cfi-sh-user-name {\n font-weight: 500;\n color: var(--cfi-color-gray-900, #111827);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n}\n.cfi-sh-user-email {\n color: var(--cfi-color-gray-500, #6b7280);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n}\n.cfi-sh-divider {\n height: 1px;\n background: var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-sh-menu-item {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n width: 100%;\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n background: none;\n border: none;\n color: var(--cfi-color-gray-700, #374151);\n cursor: pointer;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n font-family: inherit;\n transition: background 100ms;\n}\n.cfi-sh-menu-item:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n");
|
|
28
|
+
|
|
29
|
+
// src/AppSwitcher.tsx
|
|
30
|
+
import { useState, useRef, useEffect } from "react";
|
|
31
|
+
|
|
32
|
+
// src/appCatalog.ts
|
|
33
|
+
var appCatalog = [
|
|
34
|
+
{ id: "si", name: "Supplier Intelligence", icon: "Building2", localPort: 3e3 },
|
|
35
|
+
{ id: "masterdata", name: "Master Data", icon: "Database", localPort: 3100 },
|
|
36
|
+
{ id: "forecast", name: "Forecasting", icon: "TrendingUp", localPort: 3200 },
|
|
37
|
+
{ id: "pim", name: "Price Index", icon: "BarChart3", localPort: 3300 },
|
|
38
|
+
{ id: "cpq", name: "CPQ", icon: "Calculator", localPort: 3400 },
|
|
39
|
+
{ id: "omsf", name: "OMSF", icon: "FileText", localPort: 3500 },
|
|
40
|
+
{ id: "identity", name: "Identity", icon: "Shield", localPort: 3600 }
|
|
41
|
+
];
|
|
42
|
+
function getAppUrl(app) {
|
|
43
|
+
const host = typeof window !== "undefined" ? window.location.hostname : "";
|
|
44
|
+
const protocol = typeof window !== "undefined" ? window.location.protocol : "https:";
|
|
45
|
+
if (host === "localhost" || host === "127.0.0.1") {
|
|
46
|
+
return app.localPort ? `http://localhost:${app.localPort}` : "#";
|
|
47
|
+
}
|
|
48
|
+
if (host.includes(".dev.")) {
|
|
49
|
+
return `${protocol}//${app.id}.dev.campfiresuite.com`;
|
|
50
|
+
}
|
|
51
|
+
return `${protocol}//${app.id}.campfiresuite.com`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/icons.tsx
|
|
55
|
+
import {
|
|
56
|
+
Building2,
|
|
57
|
+
Database,
|
|
58
|
+
TrendingUp,
|
|
59
|
+
BarChart3,
|
|
60
|
+
Calculator,
|
|
61
|
+
FileText,
|
|
62
|
+
Shield,
|
|
63
|
+
LayoutGrid,
|
|
64
|
+
Bell,
|
|
65
|
+
ChevronDown,
|
|
66
|
+
LogOut,
|
|
67
|
+
User
|
|
68
|
+
} from "lucide-react";
|
|
69
|
+
var iconMap = {
|
|
70
|
+
Building2,
|
|
71
|
+
Database,
|
|
72
|
+
TrendingUp,
|
|
73
|
+
BarChart3,
|
|
74
|
+
Calculator,
|
|
75
|
+
FileText,
|
|
76
|
+
Shield
|
|
77
|
+
};
|
|
78
|
+
function getIcon(name) {
|
|
79
|
+
return iconMap[name] || LayoutGrid;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/AppSwitcher.tsx
|
|
83
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
84
|
+
function AppSwitcher({ currentAppId, authorizedApps }) {
|
|
85
|
+
const [open, setOpen] = useState(false);
|
|
86
|
+
const ref = useRef(null);
|
|
87
|
+
const currentApp = appCatalog.find((a) => a.id === currentAppId);
|
|
88
|
+
const visibleApps = appCatalog.filter((a) => authorizedApps.includes(a.id));
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
function handleClickOutside(e) {
|
|
91
|
+
if (ref.current && !ref.current.contains(e.target)) {
|
|
92
|
+
setOpen(false);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (open) document.addEventListener("mousedown", handleClickOutside);
|
|
96
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
97
|
+
}, [open]);
|
|
98
|
+
const CurrentIcon = currentApp ? getIcon(currentApp.icon) : LayoutGrid;
|
|
99
|
+
return /* @__PURE__ */ jsxs("div", { className: "cfi-sh-app-switcher", ref, children: [
|
|
100
|
+
/* @__PURE__ */ jsxs(
|
|
101
|
+
"button",
|
|
102
|
+
{
|
|
103
|
+
className: "cfi-sh-app-trigger",
|
|
104
|
+
onClick: () => setOpen(!open),
|
|
105
|
+
"aria-expanded": open,
|
|
106
|
+
"aria-haspopup": "true",
|
|
107
|
+
children: [
|
|
108
|
+
/* @__PURE__ */ jsx(CurrentIcon, { size: 18 }),
|
|
109
|
+
/* @__PURE__ */ jsx("span", { className: "cfi-sh-app-name", children: currentApp?.name || "Apps" }),
|
|
110
|
+
/* @__PURE__ */ jsx(ChevronDown, { size: 14, className: open ? "cfi-sh-chevron-open" : void 0 })
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
),
|
|
114
|
+
open && /* @__PURE__ */ jsx("div", { className: "cfi-sh-app-dropdown", children: visibleApps.map((app) => {
|
|
115
|
+
const Icon = getIcon(app.icon);
|
|
116
|
+
const isCurrent = app.id === currentAppId;
|
|
117
|
+
return /* @__PURE__ */ jsxs(
|
|
118
|
+
"a",
|
|
119
|
+
{
|
|
120
|
+
href: isCurrent ? void 0 : getAppUrl(app),
|
|
121
|
+
className: `cfi-sh-app-item ${isCurrent ? "cfi-sh-app-item-active" : ""}`,
|
|
122
|
+
onClick: isCurrent ? (e) => {
|
|
123
|
+
e.preventDefault();
|
|
124
|
+
setOpen(false);
|
|
125
|
+
} : void 0,
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ jsx(Icon, { size: 16 }),
|
|
128
|
+
/* @__PURE__ */ jsx("span", { children: app.name })
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
app.id
|
|
132
|
+
);
|
|
133
|
+
}) })
|
|
134
|
+
] });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/NotificationBell.tsx
|
|
138
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
139
|
+
function NotificationBell({ count = 0, onClick }) {
|
|
140
|
+
return /* @__PURE__ */ jsxs2("button", { className: "cfi-sh-icon-btn", onClick, "aria-label": "Notifications", children: [
|
|
141
|
+
/* @__PURE__ */ jsx2(Bell, { size: 18 }),
|
|
142
|
+
count > 0 && /* @__PURE__ */ jsx2("span", { className: "cfi-sh-badge", children: count > 99 ? "99+" : count })
|
|
143
|
+
] });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/UserMenu.tsx
|
|
147
|
+
import { useState as useState2, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
148
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
149
|
+
function UserMenu({ user, onLogout }) {
|
|
150
|
+
const [open, setOpen] = useState2(false);
|
|
151
|
+
const ref = useRef2(null);
|
|
152
|
+
useEffect2(() => {
|
|
153
|
+
function handleClickOutside(e) {
|
|
154
|
+
if (ref.current && !ref.current.contains(e.target)) {
|
|
155
|
+
setOpen(false);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (open) document.addEventListener("mousedown", handleClickOutside);
|
|
159
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
160
|
+
}, [open]);
|
|
161
|
+
const initials = user.name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
|
|
162
|
+
return /* @__PURE__ */ jsxs3("div", { className: "cfi-sh-user-menu", ref, children: [
|
|
163
|
+
/* @__PURE__ */ jsx3(
|
|
164
|
+
"button",
|
|
165
|
+
{
|
|
166
|
+
className: "cfi-sh-avatar-btn",
|
|
167
|
+
onClick: () => setOpen(!open),
|
|
168
|
+
"aria-expanded": open,
|
|
169
|
+
"aria-haspopup": "true",
|
|
170
|
+
children: user.avatarUrl ? /* @__PURE__ */ jsx3("img", { src: user.avatarUrl, alt: user.name, className: "cfi-sh-avatar-img" }) : /* @__PURE__ */ jsx3("span", { className: "cfi-sh-avatar-initials", children: initials })
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
open && /* @__PURE__ */ jsxs3("div", { className: "cfi-sh-user-dropdown", children: [
|
|
174
|
+
/* @__PURE__ */ jsxs3("div", { className: "cfi-sh-user-header", children: [
|
|
175
|
+
/* @__PURE__ */ jsx3("span", { className: "cfi-sh-user-name", children: user.name }),
|
|
176
|
+
/* @__PURE__ */ jsx3("span", { className: "cfi-sh-user-email", children: user.email })
|
|
177
|
+
] }),
|
|
178
|
+
/* @__PURE__ */ jsx3("div", { className: "cfi-sh-divider" }),
|
|
179
|
+
/* @__PURE__ */ jsxs3(
|
|
180
|
+
"button",
|
|
181
|
+
{
|
|
182
|
+
className: "cfi-sh-menu-item",
|
|
183
|
+
onClick: () => {
|
|
184
|
+
setOpen(false);
|
|
185
|
+
onLogout?.();
|
|
186
|
+
},
|
|
187
|
+
children: [
|
|
188
|
+
/* @__PURE__ */ jsx3(LogOut, { size: 14 }),
|
|
189
|
+
/* @__PURE__ */ jsx3("span", { children: "Sign out" })
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
] })
|
|
194
|
+
] });
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// src/ShellHeader.tsx
|
|
198
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
199
|
+
function ShellHeader({
|
|
200
|
+
appId,
|
|
201
|
+
user,
|
|
202
|
+
authorizedApps,
|
|
203
|
+
notificationCount,
|
|
204
|
+
onNotificationClick,
|
|
205
|
+
onLogout,
|
|
206
|
+
children
|
|
207
|
+
}) {
|
|
208
|
+
return /* @__PURE__ */ jsxs4("header", { className: "cfi-sh-header", children: [
|
|
209
|
+
/* @__PURE__ */ jsx4("div", { className: "cfi-sh-left", children: /* @__PURE__ */ jsx4(AppSwitcher, { currentAppId: appId, authorizedApps }) }),
|
|
210
|
+
/* @__PURE__ */ jsx4("div", { className: "cfi-sh-center", children }),
|
|
211
|
+
/* @__PURE__ */ jsxs4("div", { className: "cfi-sh-right", children: [
|
|
212
|
+
/* @__PURE__ */ jsx4(NotificationBell, { count: notificationCount, onClick: onNotificationClick }),
|
|
213
|
+
/* @__PURE__ */ jsx4(UserMenu, { user, onLogout })
|
|
214
|
+
] })
|
|
215
|
+
] });
|
|
216
|
+
}
|
|
217
|
+
export {
|
|
218
|
+
ShellHeader,
|
|
219
|
+
appCatalog,
|
|
220
|
+
getAppUrl
|
|
221
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@campfire-interactive/shell-header",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Shared shell header with app switcher for Campfire Suite",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"dev": "tsup --watch"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
23
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@campfire-interactive/design-tokens": "*",
|
|
27
|
+
"lucide-react": "^0.460.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/react": "^19.0.0",
|
|
31
|
+
"esbuild-css-modules-plugin": "^3.1.5",
|
|
32
|
+
"react": "^19.0.0",
|
|
33
|
+
"react-dom": "^19.0.0",
|
|
34
|
+
"tsup": "^8.0.0",
|
|
35
|
+
"typescript": "^5.0.0"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"registry": "https://registry.npmjs.org",
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|