@nexly/web 0.14.0 → 0.15.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 +4 -0
- package/dist/events/index.d.ts +1 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +1 -0
- package/dist/events/outbound-links.d.ts +17 -0
- package/dist/events/outbound-links.d.ts.map +1 -0
- package/dist/events/outbound-links.js +188 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/nexly.d.ts +7 -0
- package/dist/nexly.d.ts.map +1 -1
- package/dist/nexly.js +24 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -67,3 +67,7 @@ await fetch('/api/link-visitor', {
|
|
|
67
67
|
`getVisitorId()` reads the persistent anonymous id Nexly stores in `localStorage`; `getSessionId()` reads the 30-minute tab session id from `sessionStorage`. Both are plain strings, safe to call from anywhere.
|
|
68
68
|
|
|
69
69
|
See the full recipe (backend storage + emitting linked events) in the [`@nexly/node` README](https://www.npmjs.com/package/@nexly/node).
|
|
70
|
+
|
|
71
|
+
## Bot detection
|
|
72
|
+
|
|
73
|
+
Bots and AI crawlers are classified server-side from the HTTP `User-Agent` header at ingest — do **not** try to compute or send an `is_bot` flag from your page code. Every event is stored (bots are not filtered out); the dashboard surfaces them in the dedicated "AI & Crawler activity" section and excludes them from standard visitor metrics.
|
package/dist/events/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA"}
|
package/dist/events/index.js
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CollectCredentials } from '@nexly/core';
|
|
2
|
+
type StopFn = () => void;
|
|
3
|
+
/**
|
|
4
|
+
* Attaches a delegated listener that auto-tracks four navigation cases on
|
|
5
|
+
* `<a>` elements:
|
|
6
|
+
* - external `http(s)` links — `outbound_link_clicked`
|
|
7
|
+
* - file downloads (by `download` attr or known extension) — `file_downloaded`
|
|
8
|
+
* - `mailto:` links — `mailto_clicked`
|
|
9
|
+
* - `tel:` links — `tel_clicked`
|
|
10
|
+
*
|
|
11
|
+
* All events use `type: 'navigation'`. Listens to both `click` and `auxclick`
|
|
12
|
+
* (middle-click). Skips elements (or their ancestors) marked with
|
|
13
|
+
* `[data-nexly-ignore]`. Returns a cleanup function.
|
|
14
|
+
*/
|
|
15
|
+
export declare function startOutboundLinkTracking(creds: CollectCredentials): StopFn;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=outbound-links.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-links.d.ts","sourceRoot":"","sources":["../../src/events/outbound-links.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAkKrD,KAAK,MAAM,GAAG,MAAM,IAAI,CAAA;AAExB;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CA0C3E"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { sendBeaconCollect } from '../beacon.js';
|
|
2
|
+
import { collectEventMeta } from '../browser-meta.js';
|
|
3
|
+
/**
|
|
4
|
+
* File extensions treated as downloadable assets when no explicit `download`
|
|
5
|
+
* attribute is present on the link. Mirrors the defaults used by Plausible's
|
|
6
|
+
* `fileDownloads` extension, with a few common additions.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_DOWNLOAD_EXTENSIONS = new Set([
|
|
9
|
+
'7z',
|
|
10
|
+
'avi',
|
|
11
|
+
'csv',
|
|
12
|
+
'dmg',
|
|
13
|
+
'doc',
|
|
14
|
+
'docx',
|
|
15
|
+
'exe',
|
|
16
|
+
'gz',
|
|
17
|
+
'key',
|
|
18
|
+
'mkv',
|
|
19
|
+
'mp3',
|
|
20
|
+
'mp4',
|
|
21
|
+
'mov',
|
|
22
|
+
'msi',
|
|
23
|
+
'numbers',
|
|
24
|
+
'odp',
|
|
25
|
+
'ods',
|
|
26
|
+
'odt',
|
|
27
|
+
'pages',
|
|
28
|
+
'pdf',
|
|
29
|
+
'pkg',
|
|
30
|
+
'ppt',
|
|
31
|
+
'pptx',
|
|
32
|
+
'rar',
|
|
33
|
+
'rtf',
|
|
34
|
+
'tar',
|
|
35
|
+
'tgz',
|
|
36
|
+
'txt',
|
|
37
|
+
'wav',
|
|
38
|
+
'webm',
|
|
39
|
+
'wma',
|
|
40
|
+
'xls',
|
|
41
|
+
'xlsx',
|
|
42
|
+
'xz',
|
|
43
|
+
'zip',
|
|
44
|
+
]);
|
|
45
|
+
const LINK_TEXT_MAX = 80;
|
|
46
|
+
const CLICK_THROTTLE_MS = 300;
|
|
47
|
+
function sendOutbound(creds, eventName, data) {
|
|
48
|
+
sendBeaconCollect({
|
|
49
|
+
collectUrl: creds.collectUrl,
|
|
50
|
+
credentials: { appId: creds.appId, apiToken: creds.apiToken },
|
|
51
|
+
client: creds.client,
|
|
52
|
+
eventName,
|
|
53
|
+
eventType: 'navigation',
|
|
54
|
+
context: collectEventMeta(),
|
|
55
|
+
data,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function getLinkText(link) {
|
|
59
|
+
const raw = link.innerText ?? link.textContent ?? '';
|
|
60
|
+
const trimmed = raw.replace(/\s+/g, ' ').trim().slice(0, LINK_TEXT_MAX);
|
|
61
|
+
return trimmed || undefined;
|
|
62
|
+
}
|
|
63
|
+
function getFileExtension(pathname) {
|
|
64
|
+
const lastSlash = pathname.lastIndexOf('/');
|
|
65
|
+
const fileName = lastSlash >= 0 ? pathname.slice(lastSlash + 1) : pathname;
|
|
66
|
+
const dot = fileName.lastIndexOf('.');
|
|
67
|
+
if (dot <= 0 || dot === fileName.length - 1)
|
|
68
|
+
return undefined;
|
|
69
|
+
return fileName.slice(dot + 1).toLowerCase();
|
|
70
|
+
}
|
|
71
|
+
function categorizeLink(link, hrefAttr, currentHost) {
|
|
72
|
+
let url;
|
|
73
|
+
try {
|
|
74
|
+
url = new URL(hrefAttr, window.location.href);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const linkText = getLinkText(link);
|
|
80
|
+
if (url.protocol === 'mailto:') {
|
|
81
|
+
const address = decodeURIComponent(url.pathname || hrefAttr.replace(/^mailto:/i, ''));
|
|
82
|
+
return {
|
|
83
|
+
eventName: 'mailto_clicked',
|
|
84
|
+
data: {
|
|
85
|
+
url: hrefAttr,
|
|
86
|
+
...(address ? { address } : {}),
|
|
87
|
+
...(linkText ? { link_text: linkText } : {}),
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
if (url.protocol === 'tel:') {
|
|
92
|
+
const number = decodeURIComponent(url.pathname || hrefAttr.replace(/^tel:/i, ''));
|
|
93
|
+
return {
|
|
94
|
+
eventName: 'tel_clicked',
|
|
95
|
+
data: {
|
|
96
|
+
url: hrefAttr,
|
|
97
|
+
...(number ? { number } : {}),
|
|
98
|
+
...(linkText ? { link_text: linkText } : {}),
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const isExternal = url.host !== currentHost;
|
|
106
|
+
const hasDownloadAttr = link.hasAttribute('download');
|
|
107
|
+
const ext = getFileExtension(url.pathname);
|
|
108
|
+
const isDownload = hasDownloadAttr || (ext !== undefined && DEFAULT_DOWNLOAD_EXTENSIONS.has(ext));
|
|
109
|
+
if (isDownload) {
|
|
110
|
+
const fileName = url.pathname.split('/').filter(Boolean).pop();
|
|
111
|
+
return {
|
|
112
|
+
eventName: 'file_downloaded',
|
|
113
|
+
data: {
|
|
114
|
+
url: url.href,
|
|
115
|
+
host: url.host,
|
|
116
|
+
...(fileName ? { file_name: fileName } : {}),
|
|
117
|
+
...(ext ? { file_extension: ext } : {}),
|
|
118
|
+
external: isExternal,
|
|
119
|
+
...(linkText ? { link_text: linkText } : {}),
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (isExternal) {
|
|
124
|
+
return {
|
|
125
|
+
eventName: 'outbound_link_clicked',
|
|
126
|
+
data: {
|
|
127
|
+
url: url.href,
|
|
128
|
+
host: url.host,
|
|
129
|
+
...(linkText ? { link_text: linkText } : {}),
|
|
130
|
+
...(link.target ? { target: link.target } : {}),
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Attaches a delegated listener that auto-tracks four navigation cases on
|
|
138
|
+
* `<a>` elements:
|
|
139
|
+
* - external `http(s)` links — `outbound_link_clicked`
|
|
140
|
+
* - file downloads (by `download` attr or known extension) — `file_downloaded`
|
|
141
|
+
* - `mailto:` links — `mailto_clicked`
|
|
142
|
+
* - `tel:` links — `tel_clicked`
|
|
143
|
+
*
|
|
144
|
+
* All events use `type: 'navigation'`. Listens to both `click` and `auxclick`
|
|
145
|
+
* (middle-click). Skips elements (or their ancestors) marked with
|
|
146
|
+
* `[data-nexly-ignore]`. Returns a cleanup function.
|
|
147
|
+
*/
|
|
148
|
+
export function startOutboundLinkTracking(creds) {
|
|
149
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
150
|
+
return () => { };
|
|
151
|
+
}
|
|
152
|
+
const ac = new AbortController();
|
|
153
|
+
const { signal } = ac;
|
|
154
|
+
let lastDispatch = { href: '', ts: 0 };
|
|
155
|
+
function handle(e) {
|
|
156
|
+
if (e.defaultPrevented)
|
|
157
|
+
return;
|
|
158
|
+
if (e.type === 'click' && e.button !== 0 && e.button !== 1)
|
|
159
|
+
return;
|
|
160
|
+
if (e.type === 'auxclick' && e.button !== 1)
|
|
161
|
+
return;
|
|
162
|
+
const target = e.target;
|
|
163
|
+
if (!target)
|
|
164
|
+
return;
|
|
165
|
+
const link = target.closest('a');
|
|
166
|
+
if (!link)
|
|
167
|
+
return;
|
|
168
|
+
if (link.closest('[data-nexly-ignore]'))
|
|
169
|
+
return;
|
|
170
|
+
const hrefAttr = link.getAttribute('href');
|
|
171
|
+
if (!hrefAttr)
|
|
172
|
+
return;
|
|
173
|
+
const category = categorizeLink(link, hrefAttr, window.location.host);
|
|
174
|
+
if (!category)
|
|
175
|
+
return;
|
|
176
|
+
const now = Date.now();
|
|
177
|
+
if (lastDispatch.href === hrefAttr && now - lastDispatch.ts < CLICK_THROTTLE_MS) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
lastDispatch = { href: hrefAttr, ts: now };
|
|
181
|
+
sendOutbound(creds, category.eventName, category.data);
|
|
182
|
+
}
|
|
183
|
+
document.addEventListener('click', handle, { signal, capture: true });
|
|
184
|
+
document.addEventListener('auxclick', handle, { signal, capture: true });
|
|
185
|
+
return () => {
|
|
186
|
+
ac.abort();
|
|
187
|
+
};
|
|
188
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type { NexlyEventInput, NexlyEventType, NexlyInit } from '@nexly/core';
|
|
|
6
6
|
export { collectBrowserMeta, collectSessionMeta, collectEventMeta } from './browser-meta.js';
|
|
7
7
|
export { getSessionId, getVisitorId } from './session.js';
|
|
8
8
|
export { sendBeaconCollect, type SendBeaconCollectInput } from './beacon.js';
|
|
9
|
-
export { getDefaultPathname, sendPageViewBeacon, startEngagementTracking } from './events/index.js';
|
|
9
|
+
export { getDefaultPathname, sendPageViewBeacon, startEngagementTracking, startOutboundLinkTracking, } from './events/index.js';
|
|
10
10
|
export type { CollectCredentials, IngestCredentials, TrackEventInput } from '@nexly/core';
|
|
11
11
|
export { buildCollectPayload } from '@nexly/core';
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAC5F,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAC5F,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -5,5 +5,5 @@ export { Nexly } from './nexly.js';
|
|
|
5
5
|
export { collectBrowserMeta, collectSessionMeta, collectEventMeta } from './browser-meta.js';
|
|
6
6
|
export { getSessionId, getVisitorId } from './session.js';
|
|
7
7
|
export { sendBeaconCollect } from './beacon.js';
|
|
8
|
-
export { getDefaultPathname, sendPageViewBeacon, startEngagementTracking } from './events/index.js';
|
|
8
|
+
export { getDefaultPathname, sendPageViewBeacon, startEngagementTracking, startOutboundLinkTracking, } from './events/index.js';
|
|
9
9
|
export { buildCollectPayload } from '@nexly/core';
|
package/dist/nexly.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { NexlyBase, type NexlyInit } from '@nexly/core';
|
|
|
5
5
|
*/
|
|
6
6
|
export declare class Nexly extends NexlyBase {
|
|
7
7
|
private engagementStop;
|
|
8
|
+
private outboundLinksStop;
|
|
8
9
|
/** Creates (or replaces) the browser singleton. Default `client` is `NexlyClient.Web`. */
|
|
9
10
|
static init(options: NexlyInit): Nexly;
|
|
10
11
|
/** Returns the browser singleton, or `null` if not yet initialized. */
|
|
@@ -20,5 +21,11 @@ export declare class Nexly extends NexlyBase {
|
|
|
20
21
|
* Returns a cleanup function.
|
|
21
22
|
*/
|
|
22
23
|
startEngagement(): () => void;
|
|
24
|
+
/**
|
|
25
|
+
* Attaches a delegated click listener that auto-tracks outbound links,
|
|
26
|
+
* file downloads, `mailto:` and `tel:` clicks. Idempotent: re-calling stops
|
|
27
|
+
* the previous subscription first. Returns a cleanup function.
|
|
28
|
+
*/
|
|
29
|
+
startOutboundLinks(): () => void;
|
|
23
30
|
}
|
|
24
31
|
//# sourceMappingURL=nexly.d.ts.map
|
package/dist/nexly.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nexly.d.ts","sourceRoot":"","sources":["../src/nexly.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"nexly.d.ts","sourceRoot":"","sources":["../src/nexly.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAA;AAOpE;;;GAGG;AACH,qBAAa,KAAM,SAAQ,SAAS;IAClC,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,iBAAiB,CAA4B;IAErD,0FAA0F;IAC1F,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,KAAK;IAMtC,uEAAuE;IACvE,MAAM,CAAC,WAAW,IAAI,KAAK,GAAG,IAAI;gBAItB,IAAI,EAAE,SAAS;cAIR,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;cAKpD,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;cAI9C,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI1D,cAAc,IAAI,MAAM;IAIjC;;;;OAIG;IACH,eAAe,IAAI,MAAM,IAAI;IAgB7B;;;;OAIG;IACH,kBAAkB,IAAI,MAAM,IAAI;CAejC"}
|
package/dist/nexly.js
CHANGED
|
@@ -2,6 +2,7 @@ import { NexlyBase, NexlyClient } from '@nexly/core';
|
|
|
2
2
|
import { sendPayloadBeacon } from './beacon.js';
|
|
3
3
|
import { collectEventMeta, collectSessionMeta } from './browser-meta.js';
|
|
4
4
|
import { startEngagementTracking } from './events/engagement.js';
|
|
5
|
+
import { startOutboundLinkTracking } from './events/outbound-links.js';
|
|
5
6
|
import { getDefaultPathname } from './events/pageview.js';
|
|
6
7
|
/**
|
|
7
8
|
* Browser-specific Nexly client. Implements transport via `navigator.sendBeacon`
|
|
@@ -9,6 +10,7 @@ import { getDefaultPathname } from './events/pageview.js';
|
|
|
9
10
|
*/
|
|
10
11
|
export class Nexly extends NexlyBase {
|
|
11
12
|
engagementStop = null;
|
|
13
|
+
outboundLinksStop = null;
|
|
12
14
|
/** Creates (or replaces) the browser singleton. Default `client` is `NexlyClient.Web`. */
|
|
13
15
|
static init(options) {
|
|
14
16
|
const instance = new Nexly({ ...options, client: options.client ?? NexlyClient.Web });
|
|
@@ -58,4 +60,26 @@ export class Nexly extends NexlyBase {
|
|
|
58
60
|
this.engagementStop = null;
|
|
59
61
|
};
|
|
60
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Attaches a delegated click listener that auto-tracks outbound links,
|
|
65
|
+
* file downloads, `mailto:` and `tel:` clicks. Idempotent: re-calling stops
|
|
66
|
+
* the previous subscription first. Returns a cleanup function.
|
|
67
|
+
*/
|
|
68
|
+
startOutboundLinks() {
|
|
69
|
+
if (this.disabled)
|
|
70
|
+
return () => { };
|
|
71
|
+
this.outboundLinksStop?.();
|
|
72
|
+
const stop = startOutboundLinkTracking({
|
|
73
|
+
collectUrl: this.collectUrl,
|
|
74
|
+
appId: this.appId,
|
|
75
|
+
apiToken: this.key,
|
|
76
|
+
client: this.client,
|
|
77
|
+
});
|
|
78
|
+
this.outboundLinksStop = stop;
|
|
79
|
+
return () => {
|
|
80
|
+
stop();
|
|
81
|
+
if (this.outboundLinksStop === stop)
|
|
82
|
+
this.outboundLinksStop = null;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
61
85
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexly/web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Nexly browser ingest SDK: sendBeacon transport, DOM metadata, engagement listeners on top of @nexly/core",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"node": ">=20"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@nexly/core": "0.
|
|
41
|
+
"@nexly/core": "0.15.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"typescript": "~6.0.2"
|