@commversion/libs 0.18.2 → 0.18.3
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/.cspell.json +149 -0
- package/.editorconfig +10 -0
- package/.husky/pre-commit +27 -0
- package/.husky/prepare-commit-msg +13 -0
- package/.markdownlint.json +4 -0
- package/.oxfmtrc.json +6 -0
- package/.oxlintrc.json +34 -0
- package/.release-it.json +9 -3
- package/.vscode/extensions.json +18 -0
- package/.vscode/settings.json +12 -0
- package/README.md +20 -10
- package/dist/lc-attribution.js +1 -0
- package/dist/lc-channel-widgets.js +7 -7
- package/dist/lc-cookie-banner-update-position.js +3 -3
- package/dist/lc-device.js +1 -1
- package/dist/lc-exit-intent-debounced.js +1 -1
- package/dist/lc-exit-intent.js +1 -1
- package/dist/lc-experiment.js +1 -1
- package/dist/lc-form-abandonment.js +1 -1
- package/dist/lc-form-submission.js +1 -1
- package/dist/lc-ga-initialize-event.js +1 -1
- package/dist/lc-ga-tags.js +1 -1
- package/dist/lc-gclid.js +1 -1
- package/dist/lc-geoblocking.js +1 -1
- package/dist/lc-gtm.js +1 -1
- package/dist/lc-input-error.js +1 -1
- package/dist/lc-kill-chat-persist.js +1 -1
- package/dist/lc-kill-chat.js +1 -1
- package/dist/lc-open-on-button-click.js +1 -1
- package/dist/lc-pause-on-url.js +1 -1
- package/dist/lc-powered-by.js +1 -1
- package/dist/lc-show-by-selector.js +1 -1
- package/dist/lc-show-hide.js +1 -1
- package/dist/lc-utm-params.js +1 -1
- package/dist/lc-whatsapp-widget-combo.js +4 -4
- package/dist/lc-whatsapp-widget-only.js +8 -8
- package/dist/schedule-event.js +1 -1
- package/global.d.ts +320 -0
- package/package.json +112 -87
- package/pnpm-workspace.yaml +33 -0
- package/templates/scaffold.ts +86 -0
- package/templates/script/README.md +11 -0
- package/templates/script/package.json +4 -0
- package/templates/script/src/NAME.ts +6 -0
- package/templates/script/src/index.html +57 -0
- package/templates/script/src/main.ts +5 -0
- package/templates/script/tests/NAME.test.ts +9 -0
- package/templates/script/vite.config.ts +19 -0
- package/tsconfig.json +32 -0
- package/vitest.config.ts +18 -0
- package/.prettierignore +0 -4
- package/.prettierrc +0 -3
package/global.d.ts
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
type AttributionChannel = "whatsapp" | "sms" | "facebook";
|
|
2
|
+
|
|
3
|
+
interface ChannelWidgetConfig {
|
|
4
|
+
readonly type: AttributionChannel;
|
|
5
|
+
readonly number?: string;
|
|
6
|
+
readonly mobile?: { readonly enabled?: boolean };
|
|
7
|
+
readonly desktop?: { readonly enabled?: boolean };
|
|
8
|
+
readonly popover?:
|
|
9
|
+
| boolean
|
|
10
|
+
| {
|
|
11
|
+
readonly enabled?: boolean;
|
|
12
|
+
readonly title?: string;
|
|
13
|
+
readonly description?: string;
|
|
14
|
+
readonly buttonLabel?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ChannelWidgetsConfig {
|
|
19
|
+
readonly chatWidgetSelector?: string;
|
|
20
|
+
readonly channels?: readonly ChannelWidgetConfig[];
|
|
21
|
+
readonly mobile?: { readonly gap?: string; readonly gapBelow?: string };
|
|
22
|
+
readonly desktop?: { readonly gap?: string; readonly gapBelow?: string };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface ChannelMessageConfig {
|
|
26
|
+
readonly defaultMessage?: string;
|
|
27
|
+
readonly buttonMessages?: Readonly<Record<string, string>>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface CommversionConfiguration {
|
|
31
|
+
readonly clientId: string;
|
|
32
|
+
readonly attributionUrl?: string;
|
|
33
|
+
readonly exitIntentDebounceMs?: number;
|
|
34
|
+
readonly exitIntentMargin?: number;
|
|
35
|
+
readonly formAbandonmentSelector?: string;
|
|
36
|
+
readonly formAbandonmentDelay?: number;
|
|
37
|
+
readonly formSubmissionSelector?: string;
|
|
38
|
+
readonly channelWidgetsConfig?: ChannelWidgetsConfig;
|
|
39
|
+
readonly whatsappConfig?: ChannelMessageConfig;
|
|
40
|
+
readonly smsConfig?: ChannelMessageConfig;
|
|
41
|
+
readonly facebookConfig?: ChannelMessageConfig;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
namespace LiveChat {
|
|
45
|
+
export type Availability = "online" | "offline";
|
|
46
|
+
|
|
47
|
+
export type Visibility = "maximized" | "minimized" | "hidden";
|
|
48
|
+
|
|
49
|
+
export type CustomerStatus = "queued" | "chatting" | "invited" | "browsing";
|
|
50
|
+
|
|
51
|
+
export type AuthorType = "customer" | "agent";
|
|
52
|
+
|
|
53
|
+
export type NewEventType = "message" | "rich_message" | "file";
|
|
54
|
+
|
|
55
|
+
export type FormSubmittedType = "prechat" | "postchat" | "ticket";
|
|
56
|
+
|
|
57
|
+
export type Rating = "good" | "bad" | "none";
|
|
58
|
+
|
|
59
|
+
export type SessionVariables = Record<string, string>;
|
|
60
|
+
|
|
61
|
+
export interface WidgetState {
|
|
62
|
+
readonly availability: Availability;
|
|
63
|
+
readonly visibility: Visibility;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface CustomerData {
|
|
67
|
+
readonly id: string;
|
|
68
|
+
readonly name: string | null;
|
|
69
|
+
readonly email: string | null;
|
|
70
|
+
readonly isReturning: boolean;
|
|
71
|
+
readonly status: CustomerStatus;
|
|
72
|
+
readonly sessionVariables: SessionVariables;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ChatData {
|
|
76
|
+
readonly chatId: string;
|
|
77
|
+
readonly threadId: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface Author {
|
|
81
|
+
readonly id: string;
|
|
82
|
+
readonly type: AuthorType;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface Greeting {
|
|
86
|
+
readonly id: number;
|
|
87
|
+
readonly uniqueId: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface ReadyData {
|
|
91
|
+
readonly state: WidgetState;
|
|
92
|
+
readonly customerData: CustomerData;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface AvailabilityChangedData {
|
|
96
|
+
readonly availability: Availability;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface VisibilityChangedData {
|
|
100
|
+
readonly visibility: Visibility;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface CustomerStatusChangedData {
|
|
104
|
+
readonly status: CustomerStatus;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface NewEventData {
|
|
108
|
+
readonly timestamp: number;
|
|
109
|
+
readonly type: NewEventType;
|
|
110
|
+
readonly author: Author;
|
|
111
|
+
readonly greeting?: Greeting;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface FormSubmittedData {
|
|
115
|
+
readonly type: FormSubmittedType;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface RichMessageButtonClickedData {
|
|
119
|
+
readonly eventId: string;
|
|
120
|
+
readonly postbackId: string;
|
|
121
|
+
readonly greeting?: Greeting;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface MaximizeOptions {
|
|
125
|
+
readonly messageDraft: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface SalesTrackerData {
|
|
129
|
+
readonly trackerId: string;
|
|
130
|
+
readonly orderPrice?: string;
|
|
131
|
+
readonly orderId?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface Widget {
|
|
135
|
+
on(event: "ready", handler: (data: ReadyData) => void): void;
|
|
136
|
+
on(event: "availability_changed", handler: (data: AvailabilityChangedData) => void): void;
|
|
137
|
+
on(event: "visibility_changed", handler: (data: VisibilityChangedData) => void): void;
|
|
138
|
+
on(event: "customer_status_changed", handler: (data: CustomerStatusChangedData) => void): void;
|
|
139
|
+
on(event: "new_event", handler: (data: NewEventData) => void): void;
|
|
140
|
+
on(event: "form_submitted", handler: (data: FormSubmittedData) => void): void;
|
|
141
|
+
on(event: "rating_submitted", handler: (rating: Rating) => void): void;
|
|
142
|
+
on(event: "greeting_displayed", handler: (greeting: Greeting) => void): void;
|
|
143
|
+
on(event: "greeting_hidden", handler: (greeting: Greeting) => void): void;
|
|
144
|
+
on(
|
|
145
|
+
event: "rich_message_button_clicked",
|
|
146
|
+
handler: (data: RichMessageButtonClickedData) => void,
|
|
147
|
+
): void;
|
|
148
|
+
|
|
149
|
+
once(event: "ready", handler: (data: ReadyData) => void): void;
|
|
150
|
+
once(event: "availability_changed", handler: (data: AvailabilityChangedData) => void): void;
|
|
151
|
+
once(event: "visibility_changed", handler: (data: VisibilityChangedData) => void): void;
|
|
152
|
+
once(
|
|
153
|
+
event: "customer_status_changed",
|
|
154
|
+
handler: (data: CustomerStatusChangedData) => void,
|
|
155
|
+
): void;
|
|
156
|
+
once(event: "new_event", handler: (data: NewEventData) => void): void;
|
|
157
|
+
once(event: "form_submitted", handler: (data: FormSubmittedData) => void): void;
|
|
158
|
+
once(event: "rating_submitted", handler: (rating: Rating) => void): void;
|
|
159
|
+
once(event: "greeting_displayed", handler: (greeting: Greeting) => void): void;
|
|
160
|
+
once(event: "greeting_hidden", handler: (greeting: Greeting) => void): void;
|
|
161
|
+
once(
|
|
162
|
+
event: "rich_message_button_clicked",
|
|
163
|
+
handler: (data: RichMessageButtonClickedData) => void,
|
|
164
|
+
): void;
|
|
165
|
+
|
|
166
|
+
off(event: "ready", handler: (data: ReadyData) => void): void;
|
|
167
|
+
off(event: "availability_changed", handler: (data: AvailabilityChangedData) => void): void;
|
|
168
|
+
off(event: "visibility_changed", handler: (data: VisibilityChangedData) => void): void;
|
|
169
|
+
off(event: "customer_status_changed", handler: (data: CustomerStatusChangedData) => void): void;
|
|
170
|
+
off(event: "new_event", handler: (data: NewEventData) => void): void;
|
|
171
|
+
off(event: "form_submitted", handler: (data: FormSubmittedData) => void): void;
|
|
172
|
+
off(event: "rating_submitted", handler: (rating: Rating) => void): void;
|
|
173
|
+
off(event: "greeting_displayed", handler: (greeting: Greeting) => void): void;
|
|
174
|
+
off(event: "greeting_hidden", handler: (greeting: Greeting) => void): void;
|
|
175
|
+
off(
|
|
176
|
+
event: "rich_message_button_clicked",
|
|
177
|
+
handler: (data: RichMessageButtonClickedData) => void,
|
|
178
|
+
): void;
|
|
179
|
+
|
|
180
|
+
call(method: "maximize", options?: MaximizeOptions): void;
|
|
181
|
+
call(method: "minimize"): void;
|
|
182
|
+
call(method: "hide"): void;
|
|
183
|
+
call(method: "destroy"): void;
|
|
184
|
+
call(method: "hide_greeting"): void;
|
|
185
|
+
call(method: "trigger_sales_tracker", data: SalesTrackerData): void;
|
|
186
|
+
call(method: "set_session_variables", sessionVariables: SessionVariables): void;
|
|
187
|
+
call(method: "update_session_variables", sessionVariables: SessionVariables): void;
|
|
188
|
+
call(method: "set_customer_name", name: string): void;
|
|
189
|
+
call(method: "set_customer_email", email: string): void;
|
|
190
|
+
|
|
191
|
+
get(data: "state"): WidgetState;
|
|
192
|
+
get(data: "customer_data"): CustomerData;
|
|
193
|
+
get(data: "chat_data"): ChatData;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface JQuery {}
|
|
198
|
+
|
|
199
|
+
namespace SegmentAnalytics {
|
|
200
|
+
export interface SegmentOpts {
|
|
201
|
+
integrations?: any;
|
|
202
|
+
anonymousId?: string | undefined;
|
|
203
|
+
context?: object | undefined;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface CookieOptions {
|
|
207
|
+
maxage?: number | undefined;
|
|
208
|
+
domain?: string | undefined;
|
|
209
|
+
path?: string | undefined;
|
|
210
|
+
secure?: boolean | undefined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface MetricsOptions {
|
|
214
|
+
host?: string | undefined;
|
|
215
|
+
sampleRate?: number | undefined;
|
|
216
|
+
flushTimer?: number | undefined;
|
|
217
|
+
maxQueueSize?: number | undefined;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export interface StoreOptions {
|
|
221
|
+
enabled?: boolean | undefined;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface UserOptions {
|
|
225
|
+
cookie?: { key: string; oldKey: string } | undefined;
|
|
226
|
+
localStorage?: { key: string } | undefined;
|
|
227
|
+
persist?: boolean | undefined;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface GroupOptions {
|
|
231
|
+
cookie?: { key: string } | undefined;
|
|
232
|
+
localStorage?: { key: string } | undefined;
|
|
233
|
+
persist?: boolean | undefined;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface InitOptions {
|
|
237
|
+
cookie?: CookieOptions | undefined;
|
|
238
|
+
metrics?: MetricsOptions | undefined;
|
|
239
|
+
localStorage?: StoreOptions | undefined;
|
|
240
|
+
user?: UserOptions | undefined;
|
|
241
|
+
group?: GroupOptions | undefined;
|
|
242
|
+
integrations?:
|
|
243
|
+
| { All?: boolean | undefined; [integration: string]: boolean | undefined }
|
|
244
|
+
| undefined;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface IntegrationsSettings {
|
|
248
|
+
[key: string]: any;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface AnalyticsJS {
|
|
252
|
+
use(plugin: (analytics: AnalyticsJS) => void): this;
|
|
253
|
+
init(settings?: IntegrationsSettings, options?: InitOptions): this;
|
|
254
|
+
addIntegration(integration: (options: any) => void): this;
|
|
255
|
+
setAnonymousId(id: string): this;
|
|
256
|
+
load(writeKey: string): void;
|
|
257
|
+
load(writeKey: string, options?: SegmentOpts): void;
|
|
258
|
+
identify(userId: string, traits?: Object, options?: SegmentOpts, callback?: () => void): void;
|
|
259
|
+
identify(userId: string, traits: Object, callback?: () => void): void;
|
|
260
|
+
identify(userId: string, callback?: () => void): void;
|
|
261
|
+
identify(traits?: Object, options?: SegmentOpts, callback?: () => void): void;
|
|
262
|
+
identify(traits?: Object, callback?: () => void): void;
|
|
263
|
+
identify(callback: () => void): void;
|
|
264
|
+
track(event: string, properties?: Object, options?: SegmentOpts, callback?: () => void): void;
|
|
265
|
+
track(event: string, properties?: Object, callback?: () => void): void;
|
|
266
|
+
track(event: string, callback?: () => void): void;
|
|
267
|
+
page(
|
|
268
|
+
category?: string,
|
|
269
|
+
name?: string,
|
|
270
|
+
properties?: Object,
|
|
271
|
+
options?: SegmentOpts,
|
|
272
|
+
callback?: () => void,
|
|
273
|
+
): void;
|
|
274
|
+
page(name?: string, properties?: Object, options?: SegmentOpts, callback?: () => void): void;
|
|
275
|
+
page(name?: string, properties?: Object, callback?: () => void): void;
|
|
276
|
+
page(name?: string, callback?: () => void): void;
|
|
277
|
+
page(properties?: Object, options?: SegmentOpts, callback?: () => void): void;
|
|
278
|
+
page(callback?: () => void): void;
|
|
279
|
+
group(groupId: string, traits?: Object, options?: SegmentOpts, callback?: () => void): void;
|
|
280
|
+
group(groupId: string, traits?: Object, callback?: () => void): void;
|
|
281
|
+
group(groupId: string, callback?: () => void): void;
|
|
282
|
+
alias(userId: string, previousId?: string, options?: SegmentOpts, callback?: () => void): void;
|
|
283
|
+
alias(userId: string, previousId?: string, callback?: () => void): void;
|
|
284
|
+
alias(userId: string, callback?: () => void): void;
|
|
285
|
+
alias(userId: string, options?: SegmentOpts, callback?: () => void): void;
|
|
286
|
+
trackLink(
|
|
287
|
+
elements: JQuery | Element[] | Element,
|
|
288
|
+
event: string | { (elm: Element): string },
|
|
289
|
+
properties?: Object | { (elm: Element): Object },
|
|
290
|
+
): void;
|
|
291
|
+
trackForm(
|
|
292
|
+
elements: JQuery | Element[] | Element,
|
|
293
|
+
event: string | { (elm: Element): string },
|
|
294
|
+
properties?: Object | { (elm: Element): Object },
|
|
295
|
+
): void;
|
|
296
|
+
ready(callback: () => void): void;
|
|
297
|
+
reset(): void;
|
|
298
|
+
user(): {
|
|
299
|
+
id(newId?: string | null): string | null | undefined;
|
|
300
|
+
logout(): void;
|
|
301
|
+
reset(): void;
|
|
302
|
+
anonymousId(newId?: string): string;
|
|
303
|
+
traits(newTraits?: Object): void;
|
|
304
|
+
};
|
|
305
|
+
group(): { id(): string; traits(newTraits?: Object): void };
|
|
306
|
+
debug(state?: boolean): void;
|
|
307
|
+
on(
|
|
308
|
+
event: string,
|
|
309
|
+
callback: { (event: string, properties: Object, options: SegmentOpts): void },
|
|
310
|
+
): void;
|
|
311
|
+
timeout(milliseconds: number): void;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
interface Window {
|
|
316
|
+
commversion: CommversionConfiguration;
|
|
317
|
+
readonly LiveChatWidget: LiveChat.Widget;
|
|
318
|
+
readonly gaGlobal?: { vid?: string };
|
|
319
|
+
readonly analytics?: SegmentAnalytics.AnalyticsJS;
|
|
320
|
+
}
|
package/package.json
CHANGED
|
@@ -1,89 +1,114 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
2
|
+
"name": "@commversion/libs",
|
|
3
|
+
"version": "0.18.3",
|
|
4
|
+
"license": "UNLICENSED",
|
|
5
|
+
"author": "Commversion",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build:lc-attribution": "vite build -c scripts/lc-attribution/vite.config.ts",
|
|
12
|
+
"build:lc-channel-widgets": "vite build -c scripts/lc-channel-widgets/vite.config.js",
|
|
13
|
+
"build:lc-cookie-banner-update-position": "vite build -c scripts/lc-cookie-banner-update-position/vite.config.js",
|
|
14
|
+
"build:lc-device": "vite build -c scripts/lc-device/vite.config.js",
|
|
15
|
+
"build:lc-exit-intent": "vite build -c scripts/lc-exit-intent/vite.config.js",
|
|
16
|
+
"build:lc-exit-intent-debounced": "vite build -c scripts/lc-exit-intent-debounced/vite.config.js",
|
|
17
|
+
"build:lc-experiment": "vite build -c scripts/lc-experiment/vite.config.js",
|
|
18
|
+
"build:lc-form-abandonment": "vite build -c scripts/lc-form-abandonment/vite.config.js",
|
|
19
|
+
"build:lc-form-submission": "vite build -c scripts/lc-form-submission/vite.config.js",
|
|
20
|
+
"build:lc-ga-initialize-event": "vite build -c scripts/lc-ga-initialize-event/vite.config.js",
|
|
21
|
+
"build:lc-ga-tags": "vite build -c scripts/lc-ga-tags/vite.config.js",
|
|
22
|
+
"build:lc-gclid": "vite build -c scripts/lc-gclid/vite.config.js",
|
|
23
|
+
"build:lc-geoblocking": "vite build -c scripts/lc-geoblocking/vite.config.js",
|
|
24
|
+
"build:lc-gtm": "vite build -c scripts/lc-gtm/vite.config.js",
|
|
25
|
+
"build:lc-input-error": "vite build -c scripts/lc-input-error/vite.config.js",
|
|
26
|
+
"build:lc-kill-chat": "vite build -c scripts/lc-kill-chat/vite.config.js",
|
|
27
|
+
"build:lc-kill-chat-persist": "vite build -c scripts/lc-kill-chat-persist/vite.config.js",
|
|
28
|
+
"build:lc-open-on-button-click": "vite build -c scripts/lc-open-on-button-click/vite.config.js",
|
|
29
|
+
"build:lc-pause-on-url": "vite build -c scripts/lc-pause-on-url/vite.config.js",
|
|
30
|
+
"build:lc-powered-by": "vite build -c scripts/lc-powered-by/vite.config.js",
|
|
31
|
+
"build:lc-show-by-selector": "vite build -c scripts/lc-show-by-selector/vite.config.js",
|
|
32
|
+
"build:lc-show-hide": "vite build -c scripts/lc-show-hide/vite.config.js",
|
|
33
|
+
"build:lc-utm-params": "vite build -c scripts/lc-utm-params/vite.config.js",
|
|
34
|
+
"build:lc-whatsapp-widget-combo": "vite build -c scripts/lc-whatsapp-widget-combo/vite.config.js",
|
|
35
|
+
"build:lc-whatsapp-widget-only": "vite build -c scripts/lc-whatsapp-widget-only/vite.config.js",
|
|
36
|
+
"build:schedule-event": "vite build -c scripts/schedule-event/vite.config.js",
|
|
37
|
+
"dev:lc-attribution": "vite serve scripts/lc-attribution/src/",
|
|
38
|
+
"dev:lc-channel-widgets": "vite serve scripts/lc-channel-widgets/src/",
|
|
39
|
+
"dev:lc-cookie-banner-update-position": "vite serve scripts/lc-cookie-banner-update-position/src/",
|
|
40
|
+
"dev:lc-device": "vite serve scripts/lc-device/src/",
|
|
41
|
+
"dev:lc-exit-intent": "vite serve scripts/lc-exit-intent/src/",
|
|
42
|
+
"dev:lc-exit-intent-debounced": "vite serve scripts/lc-exit-intent-debounced/src/",
|
|
43
|
+
"dev:lc-experiment": "vite serve scripts/lc-experiment/src/",
|
|
44
|
+
"dev:lc-form-abandonment": "vite serve scripts/lc-form-abandonment/src/",
|
|
45
|
+
"dev:lc-form-submission": "vite serve scripts/lc-form-submission/src/",
|
|
46
|
+
"dev:lc-ga-initialize-event": "vite serve scripts/lc-ga-initialize-event/src/",
|
|
47
|
+
"dev:lc-ga-tags": "vite serve scripts/lc-ga-tags/src/",
|
|
48
|
+
"dev:lc-gclid": "vite serve scripts/lc-gclid/src/",
|
|
49
|
+
"dev:lc-geoblocking": "vite serve scripts/lc-geoblocking/src/",
|
|
50
|
+
"dev:lc-gtm": "vite serve scripts/lc-gtm/src/",
|
|
51
|
+
"dev:lc-input-error": "vite serve scripts/lc-input-error/src/",
|
|
52
|
+
"dev:lc-kill-chat": "vite serve scripts/lc-kill-chat/src/",
|
|
53
|
+
"dev:lc-kill-chat-persist": "vite serve scripts/lc-kill-chat-persist/src/",
|
|
54
|
+
"dev:lc-open-on-button-click": "vite serve scripts/lc-open-on-button-click/src/",
|
|
55
|
+
"dev:lc-pause-on-url": "vite serve scripts/lc-pause-on-url/src/",
|
|
56
|
+
"dev:lc-powered-by": "vite serve scripts/lc-powered-by/src/",
|
|
57
|
+
"dev:lc-show-by-selector": "vite serve scripts/lc-show-by-selector/src/",
|
|
58
|
+
"dev:lc-show-hide": "vite serve scripts/lc-show-hide/src/",
|
|
59
|
+
"dev:lc-utm-params": "vite serve scripts/lc-utm-params/src/",
|
|
60
|
+
"dev:lc-whatsapp-widget-combo": "vite serve scripts/lc-whatsapp-widget-combo/src/",
|
|
61
|
+
"dev:lc-whatsapp-widget-only": "vite serve scripts/lc-whatsapp-widget-only/src/",
|
|
62
|
+
"dev:schedule-event": "vite serve scripts/schedule-event/src/",
|
|
63
|
+
"fmt": "oxfmt",
|
|
64
|
+
"fmt:check": "oxfmt --check",
|
|
65
|
+
"lint": "oxlint --type-aware --type-check --report-unused-disable-directives-severity error",
|
|
66
|
+
"lint:fix": "pnpm run lint --fix",
|
|
67
|
+
"new": "node templates/scaffold.ts",
|
|
68
|
+
"prepack": "concurrently pnpm:build:*",
|
|
69
|
+
"prepare": "is-ci || husky",
|
|
70
|
+
"preview:lc-powered-by": "pnpm run build:lc-powered-by && vite preview --host 0.0.0.0",
|
|
71
|
+
"release": "release-it",
|
|
72
|
+
"release:pre": "release-it --preRelease=pre",
|
|
73
|
+
"test": "vitest run",
|
|
74
|
+
"test:watch": "vitest"
|
|
75
|
+
},
|
|
76
|
+
"dependencies": {
|
|
77
|
+
"zod": "^4.4.3"
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@types/node": "^25.9.1",
|
|
81
|
+
"@typescript/native-preview": "7.0.0-dev.20260519.1",
|
|
82
|
+
"@vitest/browser": "^4.1.7",
|
|
83
|
+
"@vitest/browser-playwright": "^4.1.7",
|
|
84
|
+
"concurrently": "^9.2.1",
|
|
85
|
+
"fast-check": "^4.8.0",
|
|
86
|
+
"gitmoji-cli": "^9.7.0",
|
|
87
|
+
"husky": "^9.1.7",
|
|
88
|
+
"is-ci": "^4.1.0",
|
|
89
|
+
"lint-staged": "^17.0.5",
|
|
90
|
+
"mongodb": "^7.2.0",
|
|
91
|
+
"oxfmt": "^0.51.0",
|
|
92
|
+
"oxlint": "^1.66.0",
|
|
93
|
+
"oxlint-tsgolint": "^0.23.0",
|
|
94
|
+
"playwright": "^1.60.0",
|
|
95
|
+
"release-it": "^20.0.1",
|
|
96
|
+
"rimraf": "^6.1.3",
|
|
97
|
+
"typescript": "^6.0.3",
|
|
98
|
+
"vite": "^8.0.13",
|
|
99
|
+
"vitest": "^4.1.7"
|
|
100
|
+
},
|
|
101
|
+
"lint-staged": {
|
|
102
|
+
"**/*.{js,ts,mjs,cjs,jsx,tsx}": [
|
|
103
|
+
"oxlint --fix",
|
|
104
|
+
"oxfmt"
|
|
105
|
+
],
|
|
106
|
+
"**/*.{json,md,yml,yaml}": [
|
|
107
|
+
"oxfmt"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
"engines": {
|
|
111
|
+
"node": ">=24"
|
|
112
|
+
},
|
|
113
|
+
"packageManager": "pnpm@11.3.0+sha512.2c403d6594527287672b1f7056343a1f7c3634036a67ffabfcc2b3d7595d843768f8787148d1b57cf7956c90606bbd192857c363af19e96d2d0ec9ec5741d215"
|
|
89
114
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# CV-496 (PR #67 review): pnpm supply-chain hardening.
|
|
2
|
+
# Mirrors the gen2-monorepo-base baseline; package-specific entries reflect
|
|
3
|
+
# only what is actually present in this repo's dependency tree.
|
|
4
|
+
|
|
5
|
+
# Delay installing newly published packages by 7 days to mitigate
|
|
6
|
+
# rapid-publish supply-chain attacks.
|
|
7
|
+
minimumReleaseAge: 10080
|
|
8
|
+
minimumReleaseAgeExclude: []
|
|
9
|
+
|
|
10
|
+
# Hardening flags: fetch full metadata, block exotic dep specifiers,
|
|
11
|
+
# warn if node_modules is stale, enforce engines field,
|
|
12
|
+
# fail audits on critical findings, deny postinstall scripts by default.
|
|
13
|
+
#
|
|
14
|
+
# `verifyDepsBeforeRun: warn` (not `error`) — pnpm 11.3.0 has an open bug
|
|
15
|
+
# (pnpm/pnpm#9777, comment #4598452327) where `error` false-positives any
|
|
16
|
+
# time `overrides:` is set, blocking every `pnpm run` immediately after a
|
|
17
|
+
# clean install. Flip to `error` once the upstream fix lands.
|
|
18
|
+
fullMetadata: true
|
|
19
|
+
blockExoticSubdeps: true
|
|
20
|
+
verifyDepsBeforeRun: warn
|
|
21
|
+
engineStrict: true
|
|
22
|
+
auditLevel: critical
|
|
23
|
+
dangerouslyAllowAllBuilds: false
|
|
24
|
+
|
|
25
|
+
# Pin patched versions for in-tree packages so a future downgrade can't
|
|
26
|
+
# silently reintroduce a known CVE. Each entry listed below has been
|
|
27
|
+
# verified to appear in this repo's transitive tree.
|
|
28
|
+
overrides:
|
|
29
|
+
vite@>=7.0.0 <7.3.2: ^7.3.2
|
|
30
|
+
yaml@>=2.0.0 <2.8.3: ^2.8.3
|
|
31
|
+
brace-expansion@>=4.0.0 <5.0.6: ^5.0.6
|
|
32
|
+
postcss@<8.5.10: ^8.5.10
|
|
33
|
+
ws@>=8.0.0 <8.20.1: ^8.20.1
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join, relative } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
7
|
+
const TEMPLATE_DIR = join(REPO_ROOT, "templates", "script");
|
|
8
|
+
const SCRIPTS_DIR = join(REPO_ROOT, "scripts");
|
|
9
|
+
const README_MARKER = "<!-- scaffold:scripts -->";
|
|
10
|
+
const NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
11
|
+
|
|
12
|
+
const toCamel = (name: string): string =>
|
|
13
|
+
name.replace(/-([a-z0-9])/g, (_, c: string) => c.toUpperCase());
|
|
14
|
+
|
|
15
|
+
const substitute = (input: string, name: string, camelName: string): string =>
|
|
16
|
+
input.replaceAll("CAMEL_NAME", camelName).replaceAll("NAME", name);
|
|
17
|
+
|
|
18
|
+
const walk = async (dir: string): Promise<string[]> => {
|
|
19
|
+
const out: string[] = [];
|
|
20
|
+
for (const entry of await readdir(dir)) {
|
|
21
|
+
const full = join(dir, entry);
|
|
22
|
+
if ((await stat(full)).isDirectory()) {
|
|
23
|
+
out.push(...(await walk(full)));
|
|
24
|
+
} else {
|
|
25
|
+
out.push(full);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const die = (msg: string): never => {
|
|
32
|
+
console.error(`scaffold: ${msg}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const updatePackageJson = async (name: string): Promise<void> => {
|
|
37
|
+
const path = join(REPO_ROOT, "package.json");
|
|
38
|
+
const pkg = JSON.parse(await readFile(path, "utf8")) as {
|
|
39
|
+
scripts: Record<string, string>;
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
};
|
|
42
|
+
pkg.scripts[`dev:${name}`] = `vite serve scripts/${name}/src/`;
|
|
43
|
+
pkg.scripts[`build:${name}`] = `vite build -c scripts/${name}/vite.config.ts`;
|
|
44
|
+
await writeFile(path, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const updateReadme = async (name: string): Promise<void> => {
|
|
48
|
+
const path = join(REPO_ROOT, "README.md");
|
|
49
|
+
const text = await readFile(path, "utf8");
|
|
50
|
+
if (!text.includes(README_MARKER)) {
|
|
51
|
+
die(
|
|
52
|
+
`README.md is missing the "${README_MARKER}" marker. Add it on its own line at the end of the script list.`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
await writeFile(path, text.replace(README_MARKER, `- ${name}\n${README_MARKER}`));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const main = async (): Promise<void> => {
|
|
59
|
+
const name = process.argv[2] ?? die("usage: pnpm new <script-name>");
|
|
60
|
+
if (!NAME_PATTERN.test(name)) {
|
|
61
|
+
die(`invalid name "${name}" — must match ${NAME_PATTERN}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const target = join(SCRIPTS_DIR, name);
|
|
65
|
+
if (existsSync(target)) die(`${relative(REPO_ROOT, target)} already exists`);
|
|
66
|
+
|
|
67
|
+
const camelName = toCamel(name);
|
|
68
|
+
const templateFiles = await walk(TEMPLATE_DIR);
|
|
69
|
+
|
|
70
|
+
for (const src of templateFiles) {
|
|
71
|
+
const rel = relative(TEMPLATE_DIR, src);
|
|
72
|
+
const destRel = substitute(rel, name, camelName);
|
|
73
|
+
const dest = join(target, destRel);
|
|
74
|
+
const contents = substitute(await readFile(src, "utf8"), name, camelName);
|
|
75
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
76
|
+
await writeFile(dest, contents);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await updatePackageJson(name);
|
|
80
|
+
await updateReadme(name);
|
|
81
|
+
|
|
82
|
+
console.log(`created scripts/${name}/`);
|
|
83
|
+
console.log(`next: pnpm install && pnpm dev:${name}`);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
await main();
|