@avsbhq/cli 1.0.0 → 3.7.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.
@@ -0,0 +1,413 @@
1
+ // TypeScript declarations for `window.avsb`, the A vs B web-snippet API.
2
+ //
3
+ // SOURCE OF TRUTH for two consumers: this package (`@avsbhq/snippet-types`), and
4
+ // the dashboard code editor's ambient lib at `snippet/types/avsb.d.ts`, which is
5
+ // a generated copy (run `npm run sync:types` here after editing; `sync.test.ts`
6
+ // fails if it drifts).
7
+ //
8
+ // Every shape mirrors the runtime's own types in `snippet/src/types.ts` (plus
9
+ // `utils/types.ts`, `purchase.ts`, `datasets.ts`, `recs.ts`, `commerceTypes.ts`),
10
+ // and `sync.test.ts` asserts that `AvsbApi` and `AvsbTrackFunction` carry exactly
11
+ // the members of `AvsbPublicAPI` and `TrackFunction` there, so an API added to the
12
+ // snippet cannot quietly go missing here.
13
+ //
14
+ // Two rules for editing:
15
+ //
16
+ // - Keep every interface member on ONE line. The sync test reads members by line.
17
+ // - Never add an `import` or `export`. That turns the file into a module, which
18
+ // hides every name below and stops `interface Window` merging with the
19
+ // browser's own, so consumers following the documented setup get nothing.
20
+ // Names are FROZEN at launch: rename nothing, add only.
21
+
22
+ // --- Tracking ---
23
+
24
+ interface AvsbTrackEventProperties {
25
+ /** Monetary amount for this event. Feeds revenue metrics. Plain number, no currency symbol. */
26
+ revenue?: number
27
+ /** Continuous measurement (order value, load time, scroll depth) for percentile and value metrics. */
28
+ value?: number
29
+ }
30
+
31
+ interface AvsbPurchaseItem {
32
+ sku: string
33
+ /** Parent product id when `sku` is a variant. Defaults to `sku` server-side. */
34
+ productKey?: string
35
+ name?: string
36
+ price?: number
37
+ quantity?: number
38
+ category?: string
39
+ }
40
+
41
+ /** An order passed to `avsb.track.purchase`. Money is decimal, in the project currency. */
42
+ interface AvsbPurchaseOrder {
43
+ /** Unique order id. Required. */
44
+ orderId: string
45
+ /** Order total as a decimal, e.g. 99.95. Required. */
46
+ total: number
47
+ /** ISO 4217 code. Defaults to the project currency. */
48
+ currency?: string
49
+ subtotal?: number
50
+ shipping?: number
51
+ tax?: number
52
+ discount?: number
53
+ coupon?: string
54
+ /** Stored but excluded from every calculation. For testing your integration. */
55
+ test?: boolean
56
+ items?: AvsbPurchaseItem[]
57
+ }
58
+
59
+ interface AvsbTrackFunction {
60
+ /** Fire a custom event by its metric event key. Numbers are coerced to strings, so a numeric key works when the metric's key is those digits. An unmatched key warns and lists the keys that do work. */
61
+ event(eventKey: string | number, properties?: AvsbTrackEventProperties): void
62
+ /** Record a visitor attribute you can slice results by. */
63
+ segment(segmentKey: string, segmentValue: string): void
64
+ /** Send an order immediately. Not batched. */
65
+ purchase(order: AvsbPurchaseOrder): void
66
+ /** Tell the snippet the current cart total, for commerce audience conditions. `totalMinor` wins when both are set. */
67
+ cart(cart: { total?: number; totalMinor?: number }): void
68
+ }
69
+
70
+ // --- Event bus record ---
71
+
72
+ type AvsbIntegrationEventType =
73
+ | 'exposure'
74
+ | 'goal'
75
+ | 'purchase'
76
+ | 'rec_impression'
77
+ | 'rec_click'
78
+ | 'custom'
79
+ | 'test'
80
+
81
+ /**
82
+ * The record delivered to `avsb.on('event')` subscribers, one per dispatched
83
+ * exposure, goal, purchase, or rec event. snake_case, shaped for analytics tools.
84
+ */
85
+ interface AvsbIntegrationRecord {
86
+ /** Experiment shortId as a string. */
87
+ experiment_id: string
88
+ /** Display name; falls back to the shortId, never an empty string. */
89
+ experiment_name: string
90
+ /** Variation shortId as a string. */
91
+ variation_id: string
92
+ /** Display name; falls back to the shortId, never an empty string. */
93
+ variation_name: string
94
+ event_type: AvsbIntegrationEventType
95
+ /** Rendered event name (native defaults plus your configured overrides). */
96
+ event_name: string
97
+ /** UUID; matches the AvsB event id for tracker-queued events. */
98
+ event_id: string
99
+ revenue: number | null
100
+ value: number | null
101
+ /** Purchases only. */
102
+ currency?: string
103
+ /** Purchases only: the order id. */
104
+ transaction_id?: string
105
+ /** Goals and custom events: metric `type:shortId` or the developer eventKey. */
106
+ goal_key?: string
107
+ visitor_id: string
108
+ page_url: string
109
+ timestamp: number
110
+ sdk_version: string
111
+ /** Recommendation product data (recipe, items, position, ...). */
112
+ attributes?: Record<string, string | number>
113
+ /** Set to 'preview' or 'internal' on QA traffic; absent for live visitors. */
114
+ source?: 'preview' | 'internal'
115
+ }
116
+
117
+ // --- Waiting ---
118
+
119
+ // A wait target: a CSS selector, a `window.x.y` global path, or a predicate.
120
+ type AvsbWaitTarget<T = unknown> = string | (() => T)
121
+
122
+ interface AvsbWaitOptions {
123
+ /** Milliseconds before the wait rejects. Default 10000. */
124
+ timeout?: number
125
+ /** Resolve a selector with an array of all matches (querySelectorAll). */
126
+ all?: boolean
127
+ }
128
+
129
+ // Promise-like whose `.catch()` is OPTIONAL: a failed wait logs gracefully rather
130
+ // than raising an unhandled rejection. `.stop()` cancels it.
131
+ interface AvsbGuardedThenable<T> extends PromiseLike<T> {
132
+ then<R1 = T, R2 = never>(
133
+ onFulfilled?: ((value: T) => R1 | PromiseLike<R1>) | null,
134
+ onRejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | null
135
+ ): AvsbGuardedThenable<R1 | R2>
136
+ catch<R = never>(
137
+ onRejected?: ((reason: unknown) => R | PromiseLike<R>) | null
138
+ ): AvsbGuardedThenable<T | R>
139
+ finally(onFinally?: (() => void) | null): AvsbGuardedThenable<T>
140
+ stop(): void
141
+ }
142
+
143
+ interface AvsbWaitUntilFn {
144
+ /** Wait for a selector / `window.x.y` path / predicate to resolve. */
145
+ <T = unknown>(target: AvsbWaitTarget<T>, opts?: AvsbWaitOptions): AvsbGuardedThenable<T>
146
+ /** Wait for several targets at once; resolves with an array of results. */
147
+ <T extends unknown[]>(targets: AvsbWaitTarget[], opts?: AvsbWaitOptions): AvsbGuardedThenable<T>
148
+ }
149
+
150
+ // --- Consent ---
151
+
152
+ /** Per-category consent flags. An absent key means "not expressed" (allowed). */
153
+ interface AvsbConsentState {
154
+ analytics?: boolean
155
+ marketing?: boolean
156
+ }
157
+
158
+ /**
159
+ * Visitor consent, the hook your cookie banner calls. `set` persists for 1 year in
160
+ * the first-party `avsb_consent` cookie and wins over the inferred Google signal.
161
+ */
162
+ interface AvsbConsentApi {
163
+ set(state: AvsbConsentState): void
164
+ get(): AvsbConsentState
165
+ }
166
+
167
+ // --- Datasets ---
168
+
169
+ interface AvsbDatasetGetResult {
170
+ found: boolean
171
+ /** FEED only: the row's ordered items array. */
172
+ items?: unknown[]
173
+ /** TABLE only: the full row object. */
174
+ row?: unknown
175
+ /** LIST only: whether the key is a member of the list. */
176
+ member?: boolean
177
+ meta: { slug: string; version: number | null }
178
+ }
179
+
180
+ interface AvsbDatasetHandle {
181
+ get(key: string): Promise<AvsbDatasetGetResult>
182
+ has(key: string): Promise<boolean>
183
+ }
184
+
185
+ // --- Recommendations ---
186
+
187
+ interface AvsbRecProduct {
188
+ id: string
189
+ title?: string
190
+ image?: string
191
+ href?: string
192
+ category?: string
193
+ /** MINOR units (ISO-4217). */
194
+ price?: number
195
+ /** MINOR units. */
196
+ compareAtPrice?: number
197
+ currency?: string
198
+ availability?: 'in_stock' | 'out_of_stock' | 'removed'
199
+ }
200
+
201
+ interface AvsbRecsRequest {
202
+ recipe: string
203
+ context?: { seed?: string; seeds?: string[]; recentlyViewed?: number }
204
+ maxItems?: number
205
+ excludeOutOfStock?: boolean
206
+ /** Which rec surface this call serves, for multi-surface pages. */
207
+ surface?: string
208
+ }
209
+
210
+ interface AvsbRecsResult {
211
+ items: AvsbRecProduct[]
212
+ served: boolean
213
+ recipe: string
214
+ /** Slug of the chain step that served, null on a miss. */
215
+ source: string | null
216
+ fallbackStep: number | null
217
+ /** True when the resolve failed (timeout, network, HTTP, parse). */
218
+ degraded: boolean
219
+ }
220
+
221
+ interface AvsbRecsClient {
222
+ /** Resolve items for a recipe. Auto-fires rec:impression on success. Never throws. */
223
+ get(req: AvsbRecsRequest): Promise<AvsbRecsResult>
224
+ /** Fire a rec:click for a product the visitor clicked. */
225
+ trackClick(productId: string, opts?: { position?: number }): void
226
+ /** Record a product view (feeds recently-viewed and commerce audiences). */
227
+ trackView(sku: string, meta?: { category?: string }): void
228
+ }
229
+
230
+ // --- Commerce data contract ---
231
+
232
+ interface AvsbContractProduct {
233
+ /** Required. The merchant's product id. */
234
+ sku: string
235
+ /** Product-grain canonical key. Defaults to `sku`. */
236
+ productKey?: string
237
+ title?: string
238
+ /** Major units as displayed. */
239
+ price?: number
240
+ /** Already-minor integer. Wins over `price`. */
241
+ priceMinor?: number
242
+ compareAtPrice?: number
243
+ compareAtPriceMinor?: number
244
+ currency?: string
245
+ image?: string
246
+ url?: string
247
+ brand?: string
248
+ category?: string
249
+ categories?: string[]
250
+ availability?: 'in_stock' | 'out_of_stock' | 'preorder'
251
+ stock?: number
252
+ variant?: { variantSku: string; options?: Record<string, string>; price?: number; priceMinor?: number; stock?: number }
253
+ customFields?: Record<string, string | number | boolean>
254
+ /** ms-epoch product createdAt. */
255
+ createdAt?: number
256
+ }
257
+
258
+ interface AvsbContractCartLine {
259
+ sku: string
260
+ productKey?: string
261
+ quantity: number
262
+ price?: number
263
+ priceMinor?: number
264
+ variantSku?: string
265
+ }
266
+
267
+ interface AvsbContractCart {
268
+ items: AvsbContractCartLine[]
269
+ total?: number
270
+ totalMinor?: number
271
+ currency?: string
272
+ }
273
+
274
+ interface AvsbCommerceApi {
275
+ productView(p: AvsbContractProduct): void
276
+ /** Category / collection impressions. */
277
+ productList(items: AvsbContractProduct[], meta?: { listId?: string }): void
278
+ addToCart(line: AvsbContractCartLine): void
279
+ removeFromCart(line: AvsbContractCartLine): void
280
+ /** Full cart snapshot. */
281
+ cart(cart: AvsbContractCart): void
282
+ checkoutStep(step: { step: number | string; cart?: AvsbContractCart }): void
283
+ search(q: { query: string; resultCount?: number; skus?: string[] }): void
284
+ categoryView(c: { category: string; skus?: string[] }): void
285
+ wishlist(w: { sku: string; action: 'add' | 'remove' }): void
286
+ }
287
+
288
+ // --- Utils toolkit (avsb.utils.* and options.utils.*) ---
289
+ interface AvsbCookieApi {
290
+ get(name: string): string | null
291
+ set(name: string, value: string, opts?: { days?: number; path?: string; domain?: string; sameSite?: 'Lax' | 'Strict' | 'None'; secure?: boolean }): void
292
+ remove(name: string): void
293
+ }
294
+
295
+ interface AvsbKVStore {
296
+ get<T = unknown>(key: string): T | null
297
+ set(key: string, value: unknown): void
298
+ remove(key: string): void
299
+ }
300
+
301
+ interface AvsbElementProps {
302
+ class?: string
303
+ id?: string
304
+ text?: string
305
+ html?: string
306
+ attrs?: Record<string, string>
307
+ style?: Record<string, string>
308
+ on?: Record<string, EventListener>
309
+ }
310
+
311
+ interface AvsbUtils {
312
+ /** Guarded, promise-based wait. `.catch()` optional; failures log gracefully. */
313
+ waitUntil: AvsbWaitUntilFn
314
+ /** Alias of waitUntil (Qubit `poll` compatibility). */
315
+ poll: AvsbWaitUntilFn
316
+ /** Resolve once a single selector is present. */
317
+ waitForElement(selector: string, opts?: { timeout?: number; root?: ParentNode }): AvsbGuardedThenable<Element>
318
+ /** Run a callback for each matching element, now and on future mutations. Supports shadow roots via `root`. */
319
+ onMutation(selector: string, callback: (el: Element) => void, opts?: { root?: ParentNode; once?: boolean; attributes?: boolean }): { stop(): void }
320
+ once<F extends (...args: never[]) => unknown>(fn: F): F
321
+ throttle<F extends (...args: never[]) => void>(fn: F, ms: number): F & { cancel(): void }
322
+ debounce<F extends (...args: never[]) => void>(fn: F, ms: number): F & { cancel(): void }
323
+ raf(fn: FrameRequestCallback): { cancel(): void }
324
+ idle(fn: () => void, opts?: { timeout?: number }): { cancel(): void }
325
+ domReady(): AvsbGuardedThenable<void>
326
+ retry<T>(fn: () => Promise<T> | T, opts?: { attempts?: number; delay?: number; factor?: number }): Promise<T>
327
+ $(selector: string, root?: ParentNode): Element | null
328
+ $$(selector: string, root?: ParentNode): Element[]
329
+ createElement(tag: string, props?: AvsbElementProps, children?: (Node | string)[]): HTMLElement
330
+ insertAfter(newNode: Node, ref: Node): void
331
+ insertBefore(newNode: Node, ref: Node): void
332
+ wrap(node: Node, wrapper: HTMLElement): void
333
+ remove(node: Node): void
334
+ setText(node: Node, text: string): void
335
+ /** Sets innerHTML; scrubs scripts and handlers unless `{ raw: true }`. */
336
+ setHtml(node: Element, html: string, opts?: { raw?: boolean }): void
337
+ /** Direct listener, or (with a selector string target) a delegated listener that also catches future nodes. */
338
+ on(target: EventTarget | string, type: string, handler: (event: Event, matched?: Element) => void, opts?: AddEventListenerOptions): { off(): void }
339
+ /** Fires on client-side route changes. */
340
+ onUrlChange(callback: (url: string) => void): { off(): void }
341
+ cookie: AvsbCookieApi
342
+ query: { get(name: string): string | null; getAll(): Record<string, string> }
343
+ storage: { local: AvsbKVStore; session: AvsbKVStore }
344
+ /** Share values between triggers.js and variation.js of the same experiment. */
345
+ state: { get<T = unknown>(key: string): T | undefined; set(key: string, value: unknown): void }
346
+ /** Scoped logger: debug/info emit only in debug, preview, or dev mode; warn always. */
347
+ log: { debug(...args: unknown[]): void; info(...args: unknown[]): void; warn(...args: unknown[]): void }
348
+ }
349
+
350
+ // --- Experiment decisions ---
351
+
352
+ /** Why an experiment did or did not run for this visit. `variant` / `control` mean the visitor is IN the test. */
353
+ type AvsbDecisionStatus = 'variant' | 'control' | 'trigger-pending' | 'not-targeted' | 'audience-mismatch' | 'excluded' | 'traffic-holdout' | 'capped' | 'scheduled-off' | 'error'
354
+
355
+ /** One row of `avsb.getExperimentDecisions()`. The variation fields are present only when a variation was assigned. */
356
+ interface AvsbExperimentDecision {
357
+ experimentId: string
358
+ status: AvsbDecisionStatus
359
+ variationId?: string
360
+ variationName?: string
361
+ }
362
+
363
+ // --- The global API ---
364
+
365
+ interface AvsbApi {
366
+ /** Consent mode only: start the snippet once the visitor has agreed. No effect otherwise. */
367
+ init(): void | Promise<void>
368
+ /** Stop everything and forget the visitor: tracking off, timers and listeners cleared, variations reverted, visitor cookie expired. */
369
+ disable(): void
370
+ track: AvsbTrackFunction
371
+ /** The visitor's id, or null when there isn't one (before `init()` in consent mode, or for a visitor who denied analytics). */
372
+ getVisitorId(): string | null
373
+ /** Replace the visitor id to stitch a browser onto a logged-in account. Drops sticky assignments and re-evaluates, so the variation can change. Returns false for an unusable id. */
374
+ setVisitorId(visitorId: string): boolean
375
+ /** The variation this visitor is assigned in the experiment, or null. Pass the numeric **Experiment ID** from the experiment details panel (a number or its string form); the value returned is that variation's numeric **Variation ID**. Internal UUIDs are not accepted. */
376
+ getVariation(experimentId: string | number): string | null
377
+ /** Force a variation, for QA, by the numeric **Experiment ID** and **Variation ID** shown in the experiment details panel. `{ track: false }` applies it without recording an exposure. */
378
+ forceVariation(experimentId: string | number, variationId: string | number, options?: { track?: boolean }): boolean
379
+ waitUntil: AvsbWaitUntilFn
380
+ utils: AvsbUtils
381
+ /** Subscribe to every experiment event. Returns an unsubscribe function. Absent in the preview bypass runtime. */
382
+ on?(event: 'event', callback: (record: AvsbIntegrationRecord) => void): () => void
383
+ /** Run a callback once experiments have been evaluated. Safe to call before the snippet loads. */
384
+ ready?(callback: () => void): void
385
+ /** @deprecated Use `ready`. Same machinery. */
386
+ onReady(callback: () => void): void
387
+ /** Visitor consent: `set` from your banner, `get` for the effective state. Absent in the preview bypass runtime. */
388
+ consent?: AvsbConsentApi
389
+ /** Experiments this visitor is active in on this page, as the same numeric dashboard ids `getVariation` takes, in string form. */
390
+ getActiveExperiments(): Array<{ experimentId: string; variationId: string }>
391
+ /** One row per experiment on the page: what happened to this visit and why (held out, mismatched, pending, running). Rebuilt on every evaluation; empty before evaluation and after `disable()`. Optional: absent on snippet builds that predate it, so read it as `avsb.getExperimentDecisions?.()`. */
392
+ getExperimentDecisions?(): AvsbExperimentDecision[]
393
+ /** Read a server-side dataset. Never throws: unknown slugs resolve `{ found: false }`. */
394
+ dataset(slug: string): AvsbDatasetHandle
395
+ /** Headless recommendations. Inside variation code prefer `options.recs`, which attributes automatically. */
396
+ recs: AvsbRecsClient
397
+ /** Commerce events. Buffered until the commerce chunk loads. */
398
+ commerce: AvsbCommerceApi
399
+ /** Leave a shared preview link: clears the preview token and reloads. */
400
+ exitPreview(): void
401
+ /** Re-run every experiment against the page as it is now. For app-driven navigation the History API never sees. */
402
+ refresh(): void
403
+ /** The snippet build running on this page, e.g. `1.1.0`. */
404
+ version: string
405
+ }
406
+
407
+ /** `window.avsb`. `q` is the install tag's early-call queue, drained by the runtime. */
408
+ interface Window {
409
+ avsb: AvsbApi & { q?: Array<[string, ...unknown[]]> }
410
+ }
411
+
412
+ /** The same object as `window.avsb`, so `avsb.track.event(...)` reads cleanly. */
413
+ declare const avsb: AvsbApi
@@ -0,0 +1,72 @@
1
+ // TypeScript declarations for code you write INSIDE A vs B: variation code,
2
+ // trigger code, and project code. Companion to `avsb.d.ts`, which types the
3
+ // `window.avsb` global and must be loaded alongside this file.
4
+ //
5
+ // Kept separate because these are authoring globals (`options`, `activate`,
6
+ // `initVariation`, ...). A site consuming `@avsbhq/snippet-types` for
7
+ // `window.avsb` should not have them in its global scope, so they live behind
8
+ // the `@avsbhq/snippet-types/variation-code` subpath.
9
+ //
10
+ // SOURCE OF TRUTH. The dashboard code editor's copy at
11
+ // `snippet/types/variation-code.d.ts` is generated: run `npm run sync:types` in
12
+ // this package after editing. Mirrors `HarnessOptions` in
13
+ // `snippet/src/userCodeHarness.ts`.
14
+ //
15
+ // Not a module, for the same reason as `avsb.d.ts`: these are global names, and
16
+ // an `export` would hide all of them. Frozen at launch: rename nothing, add only.
17
+
18
+ /** Recommendations client pre-bound to the running experiment and variation. */
19
+ interface AvsbBoundRecsClient extends AvsbRecsClient {
20
+ /** Resolve THIS variation's bound recipe, so one code block serves every variation. */
21
+ getBound(req?: Omit<AvsbRecsRequest, 'recipe'>): Promise<AvsbRecsResult>
22
+ }
23
+
24
+ /** What every user-code surface receives. Self-cleaning helpers are torn down for you. */
25
+ interface AvsbCodeOptions {
26
+ /** Present in variation and trigger code. */
27
+ experimentId?: string
28
+ experimentName?: string
29
+ variationId?: string
30
+ variationName?: string
31
+ variationType?: 'control' | 'variant'
32
+ /** Present in project code only. */
33
+ projectId?: string
34
+ /** Runs when the variation is activated. In variation code it fires as soon as your function returns. */
35
+ onActivation(cb: () => void): void
36
+ /** Runs when the variation is removed (client-side navigation, teardown, forced switch). */
37
+ onRemove(cb: () => void): void
38
+ track: AvsbTrackFunction
39
+ /** Impressions and clicks attribute to this variation automatically. */
40
+ recs: AvsbBoundRecsClient
41
+ getVisitorId(): string | null
42
+ /** The visitor's numeric **Variation ID** in that experiment, or null. Takes the numeric **Experiment ID** from the experiment details panel, NOT the `experimentId` above (that one is the internal id). */
43
+ getVariation(experimentId: string | number): string | null
44
+ /** Experiments running on this page, as the same numeric dashboard ids. */
45
+ getActiveExperiments(): Array<{ experimentId: string; variationId: string }>
46
+ /** Force a variation by the numeric **Experiment ID** and **Variation ID** from the experiment details panel. */
47
+ forceVariation(experimentId: string | number, variationId: string | number, options?: { track?: boolean }): boolean
48
+ /** Cancelled automatically on teardown, unlike `avsb.waitUntil`. */
49
+ waitUntil: AvsbWaitUntilFn
50
+ utils: AvsbUtils
51
+ /** Same numeric handle as the browser's own. Cancelled for you on teardown. */
52
+ setTimeout(handler: () => void, ms?: number): number
53
+ setInterval(handler: () => void, ms?: number): number
54
+ addEventListener(target: EventTarget, type: string, handler: EventListenerOrEventListenerObject, opts?: AddEventListenerOptions | boolean): void
55
+ }
56
+
57
+ type AvsbTriggerOptions = AvsbCodeOptions
58
+ type AvsbVariationOptions = AvsbCodeOptions
59
+ type AvsbProjectOptions = AvsbCodeOptions
60
+
61
+ // Ambient declarations for standalone authoring files. They look unused to
62
+ // ESLint because nothing in this declaration file references them: they are the
63
+ // names your own trigger, variation, and project code calls into, so they must
64
+ // stay literal.
65
+ /* eslint-disable @typescript-eslint/no-unused-vars */
66
+ declare const options: AvsbCodeOptions
67
+ declare function activate(): void
68
+ declare function deactivate(): void
69
+ declare function initVariation(options: AvsbVariationOptions): void
70
+ declare function initTrigger(options: AvsbTriggerOptions, activate: () => void, deactivate: () => void): void
71
+ declare function initProject(options: AvsbProjectOptions): void
72
+ /* eslint-enable @typescript-eslint/no-unused-vars */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avsbhq/cli",
3
- "version": "1.0.0",
3
+ "version": "3.7.0",
4
4
  "description": "CLI tool for local A/B experiment development with the A vs B platform",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -25,14 +25,18 @@
25
25
  },
26
26
  "repository": {
27
27
  "type": "git",
28
- "url": "git+https://github.com/main1479/a-vs-b.git",
28
+ "url": "git+https://github.com/avsbhq/a-vs-b.git",
29
29
  "directory": "cli"
30
30
  },
31
- "homepage": "https://github.com/main1479/a-vs-b/tree/main/cli#readme",
31
+ "homepage": "https://github.com/avsbhq/a-vs-b/tree/main/cli#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/avsbhq/a-vs-b/issues"
34
+ },
32
35
  "scripts": {
33
36
  "build": "node build.mjs",
34
37
  "dev": "node --import tsx src/cli.ts",
35
38
  "link": "npm link",
39
+ "test": "vitest run",
36
40
  "prepublishOnly": "node build.mjs"
37
41
  },
38
42
  "dependencies": {