@nextad/auction 0.1.2 → 0.1.4

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,50 @@
1
+ import { Bid, BidResponse } from 'iab-openrtb/v26';
2
+
3
+ interface CurrencyRates {
4
+ /** ISO 4217 Currency Code (Example: USD, JPY, EUR) */
5
+ [currency: string]: number;
6
+ }
7
+ interface ConversionRates {
8
+ /** convert rate of base currency */
9
+ [baseCurrency: string]: CurrencyRates;
10
+ }
11
+ interface CurrencyConversionData {
12
+ dataAsOf: string;
13
+ generatedAt: string;
14
+ conversions: ConversionRates;
15
+ }
16
+
17
+ type AuctionType = "open" | "closed";
18
+ type AuctionOptions = {
19
+ lossProcessing?: boolean;
20
+ currencyConversionData?: CurrencyConversionData;
21
+ };
22
+ declare class Auction {
23
+ private losingBids;
24
+ private bids;
25
+ private itemIds;
26
+ private status;
27
+ private options;
28
+ private bidInformation;
29
+ constructor(itemOrImpressionIds: string | string[], options?: AuctionOptions);
30
+ getStatus(): AuctionType;
31
+ getLosingBids(): {
32
+ v26: Bid[];
33
+ };
34
+ placeBidResponseV26(bidResponse: BidResponse): this;
35
+ end(): Bid;
36
+ private setLosingBids;
37
+ private handleLossBids;
38
+ private handleLossBid;
39
+ }
40
+
41
+ declare class BidNotFoundException {
42
+ name: string;
43
+ message: string;
44
+ }
45
+ declare class AlreadyEndedAuctionException {
46
+ name: string;
47
+ message: string;
48
+ }
49
+
50
+ export { AlreadyEndedAuctionException, Auction, BidNotFoundException };
@@ -0,0 +1,50 @@
1
+ import { Bid, BidResponse } from 'iab-openrtb/v26';
2
+
3
+ interface CurrencyRates {
4
+ /** ISO 4217 Currency Code (Example: USD, JPY, EUR) */
5
+ [currency: string]: number;
6
+ }
7
+ interface ConversionRates {
8
+ /** convert rate of base currency */
9
+ [baseCurrency: string]: CurrencyRates;
10
+ }
11
+ interface CurrencyConversionData {
12
+ dataAsOf: string;
13
+ generatedAt: string;
14
+ conversions: ConversionRates;
15
+ }
16
+
17
+ type AuctionType = "open" | "closed";
18
+ type AuctionOptions = {
19
+ lossProcessing?: boolean;
20
+ currencyConversionData?: CurrencyConversionData;
21
+ };
22
+ declare class Auction {
23
+ private losingBids;
24
+ private bids;
25
+ private itemIds;
26
+ private status;
27
+ private options;
28
+ private bidInformation;
29
+ constructor(itemOrImpressionIds: string | string[], options?: AuctionOptions);
30
+ getStatus(): AuctionType;
31
+ getLosingBids(): {
32
+ v26: Bid[];
33
+ };
34
+ placeBidResponseV26(bidResponse: BidResponse): this;
35
+ end(): Bid;
36
+ private setLosingBids;
37
+ private handleLossBids;
38
+ private handleLossBid;
39
+ }
40
+
41
+ declare class BidNotFoundException {
42
+ name: string;
43
+ message: string;
44
+ }
45
+ declare class AlreadyEndedAuctionException {
46
+ name: string;
47
+ message: string;
48
+ }
49
+
50
+ export { AlreadyEndedAuctionException, Auction, BidNotFoundException };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";var u=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var f=(e,i)=>{for(var s in i)u(e,s,{get:i[s],enumerable:!0})},g=(e,i,s,r)=>{if(i&&typeof i=="object"||typeof i=="function")for(let t of l(i))!v.call(e,t)&&t!==s&&u(e,t,{get:()=>i[t],enumerable:!(r=B(i,t))||r.enumerable});return e};var m=e=>g(u({},"__esModule",{value:!0}),e);var y={};f(y,{AlreadyEndedAuctionException:()=>a,Auction:()=>h,BidNotFoundException:()=>n});module.exports=m(y);var d=class{static getHighestBidV26(i,s,r){return r?i.reduce((t,o)=>{let c=this.convertPrice(t,s,r);return this.convertPrice(o,s,r)>c?o:t}):i.reduce((t,o)=>{let c=t.price*100;return o.price*100>c?o:t})}static convertPrice(i,s,r){let t=i.price,o=r.conversions[s.get(i)?.currency||"USD"];if(!o)return t*100;let p=o["USD"];return t*(p||1)*100}};var n=class{name="BidNotFoundException";message="Bid is not found."},a=class{name="AlreadyEndedAuctionException";message="Auction is already ended."};var h=class{losingBids;bids;itemIds=[];status;options;bidInformation;constructor(i,s={}){this.options={lossProcessing:!0,...s},this.bids={v26:[]},this.losingBids={v26:[]},this.status="open",this.bidInformation=new WeakMap,typeof i=="string"?this.itemIds.push(i):this.itemIds.push(...i)}getStatus(){return this.status}getLosingBids(){return this.losingBids}placeBidResponseV26(i){if(i.seatbid){let s=i.seatbid.flatMap(r=>r.bid.map(t=>(this.bidInformation.set(t,{currency:i.cur,version:"2.6",seat:r.seat}),t)));this.bids.v26.push(...s)}return this}end(){if(this.status!=="open")throw new a;if(!this.bids.v26.length)throw new n;let i=d.getHighestBidV26(this.bids.v26,this.bidInformation,this.options.currencyConversionData);return this.setLosingBids(i),this.handleLossBids(),this.status="closed",i}setLosingBids(i){this.losingBids.v26.push(...this.bids.v26.filter(s=>s.id!==i.id))}handleLossBids(){this.losingBids.v26.forEach(i=>{this.handleLossBid(i)})}handleLossBid(i){this.options.lossProcessing&&i.lurl&&fetch(i.lurl,{keepalive:!0})}};0&&(module.exports={AlreadyEndedAuctionException,Auction,BidNotFoundException});
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ var n=class{static getHighestBidV26(i,s,e){return e?i.reduce((t,r)=>{let o=this.convertPrice(t,s,e);return this.convertPrice(r,s,e)>o?r:t}):i.reduce((t,r)=>{let o=t.price*100;return r.price*100>o?r:t})}static convertPrice(i,s,e){let t=i.price,r=e.conversions[s.get(i)?.currency||"USD"];if(!r)return t*100;let p=r["USD"];return t*(p||1)*100}};var a=class{name="BidNotFoundException";message="Bid is not found."},c=class{name="AlreadyEndedAuctionException";message="Auction is already ended."};var u=class{losingBids;bids;itemIds=[];status;options;bidInformation;constructor(i,s={}){this.options={lossProcessing:!0,...s},this.bids={v26:[]},this.losingBids={v26:[]},this.status="open",this.bidInformation=new WeakMap,typeof i=="string"?this.itemIds.push(i):this.itemIds.push(...i)}getStatus(){return this.status}getLosingBids(){return this.losingBids}placeBidResponseV26(i){if(i.seatbid){let s=i.seatbid.flatMap(e=>e.bid.map(t=>(this.bidInformation.set(t,{currency:i.cur,version:"2.6",seat:e.seat}),t)));this.bids.v26.push(...s)}return this}end(){if(this.status!=="open")throw new c;if(!this.bids.v26.length)throw new a;let i=n.getHighestBidV26(this.bids.v26,this.bidInformation,this.options.currencyConversionData);return this.setLosingBids(i),this.handleLossBids(),this.status="closed",i}setLosingBids(i){this.losingBids.v26.push(...this.bids.v26.filter(s=>s.id!==i.id))}handleLossBids(){this.losingBids.v26.forEach(i=>{this.handleLossBid(i)})}handleLossBid(i){this.options.lossProcessing&&i.lurl&&fetch(i.lurl,{keepalive:!0})}};export{c as AlreadyEndedAuctionException,u as Auction,a as BidNotFoundException};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextad/auction",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "author": "Kai Miyamoto",
@@ -25,6 +25,11 @@
25
25
  "import": "./dist/index.mjs",
26
26
  "require": "./dist/index.js"
27
27
  },
28
+ "files": [
29
+ "dist",
30
+ "README.md",
31
+ "LICENSE"
32
+ ],
28
33
  "scripts": {
29
34
  "test": "vitest",
30
35
  "build": "tsup"
package/.editorconfig DELETED
File without changes
package/src/Auction.ts DELETED
@@ -1,109 +0,0 @@
1
- import { BidComparator } from "./BidComparator";
2
- import { BidFactory } from "./BidFactory";
3
- import {
4
- AlreadyEndedAuctionException,
5
- BidNotFoundException,
6
- } from "./exceptions";
7
- import type { BaseBidResponseV26, BidV26, CurrencyConversionData } from "./types";
8
-
9
- type AuctionType = "open" | "closed";
10
-
11
- type AuctionOptions = {
12
- lossProcessing?: boolean;
13
- currencyConversionData?: CurrencyConversionData;
14
- };
15
-
16
- export class Auction {
17
- private losingBids: {
18
- v26: BidV26[];
19
- };
20
- private bids: {
21
- v26: BidV26[];
22
- };
23
-
24
- private itemIds: string[] = [];
25
- private currencyConversionData?: CurrencyConversionData;
26
- private status: AuctionType;
27
- private options: AuctionOptions;
28
-
29
- public constructor(
30
- itemOrImpressionIds: string | string[],
31
- options: AuctionOptions = {}
32
- ) {
33
- this.options = {
34
- lossProcessing: true,
35
- ...options,
36
- };
37
-
38
- this.bids = {
39
- v26: [],
40
- };
41
- this.losingBids = {
42
- v26: [],
43
- };
44
- this.currencyConversionData = options.currencyConversionData;
45
- this.status = "open";
46
-
47
- if (typeof itemOrImpressionIds === "string") {
48
- this.itemIds.push(itemOrImpressionIds);
49
- } else {
50
- this.itemIds.push(...itemOrImpressionIds);
51
- }
52
- }
53
-
54
- public getStatus(): AuctionType {
55
- return this.status;
56
- }
57
-
58
- public getLosingBids(): { v26: BidV26[] } {
59
- return this.losingBids;
60
- }
61
-
62
- public placeBidResponseV26(bidResponse: BaseBidResponseV26): this {
63
- if (bidResponse.seatbid) {
64
- this.bids.v26.push(
65
- ...BidFactory.createV26Bids(bidResponse, this.itemIds)
66
- );
67
- }
68
-
69
- return this;
70
- }
71
-
72
- public end(): BidV26 {
73
- if (this.status !== "open") {
74
- throw new AlreadyEndedAuctionException();
75
- }
76
-
77
- if (!this.bids.v26.length) {
78
- throw new BidNotFoundException();
79
- }
80
-
81
- const highestBid = BidComparator.getHighestBidV26(this.bids.v26, this.options.currencyConversionData);
82
-
83
- this.setLosingBids(highestBid);
84
- this.handleLossBids();
85
- this.status = "closed";
86
-
87
- return highestBid;
88
- }
89
-
90
- private setLosingBids(winningBid: BidV26): void {
91
- this.losingBids.v26.push(
92
- ...this.bids.v26.filter((bid) => bid.id !== winningBid.id)
93
- );
94
- }
95
-
96
- private handleLossBids(): void {
97
- this.losingBids.v26.forEach((bid) => {
98
- this.handleLossBid(bid);
99
- });
100
- }
101
-
102
- private handleLossBid(bid: BidV26): void {
103
- if (this.options.lossProcessing && bid.lurl) {
104
- fetch(bid.lurl, {
105
- keepalive: true,
106
- });
107
- }
108
- }
109
- }
@@ -1,38 +0,0 @@
1
- import type { BidV26, CurrencyConversionData } from "./types";
2
-
3
- export class BidComparator {
4
- public static getHighestBidV26(
5
- bids: BidV26[],
6
- currencyConversionData?: CurrencyConversionData
7
- ): BidV26 {
8
- if (!currencyConversionData) {
9
- return bids.reduce((highest, current) => {
10
- const highestPrice = highest.price * 100;
11
- const currentPrice = current.price * 100;
12
- return currentPrice > highestPrice ? current : highest;
13
- });
14
- }
15
-
16
- return bids.reduce((highest, current) => {
17
- const highestPrice = this.convertPrice(highest, currencyConversionData);
18
- const currentPrice = this.convertPrice(current, currencyConversionData);
19
- return currentPrice > highestPrice ? current : highest;
20
- });
21
- }
22
-
23
- private static convertPrice(
24
- bid: BidV26,
25
- conversionData: CurrencyConversionData
26
- ): number {
27
- const price = bid.price;
28
- const rates = conversionData.conversions[bid.ext.nextadjs.currency];
29
-
30
- if (!rates) {
31
- return price * 100;
32
- }
33
-
34
- const targetCurrency = "USD";
35
- const rate = rates[targetCurrency];
36
- return price * (rate || 1) * 100;
37
- }
38
- }
package/src/BidFactory.ts DELETED
@@ -1,32 +0,0 @@
1
- import type { BaseBidResponseV26, BidV26 } from "./types";
2
-
3
- export class BidFactory {
4
- public static createV26Bids(
5
- bidResponse: BaseBidResponseV26,
6
- itemIds: string[]
7
- ): BidV26[] {
8
- let bids: BidV26[] = [];
9
-
10
- if (bidResponse.seatbid) {
11
- bidResponse.seatbid.forEach((seatBid) => {
12
- seatBid.bid.forEach((bid) => {
13
- if (itemIds.some((itemId) => bid.impid === itemId)) {
14
- bids.push({
15
- ...bid,
16
- ext: {
17
- ...bid.ext,
18
- nextadjs: {
19
- openrtbVersion: "2.6",
20
- currency: bidResponse.cur || "USD",
21
- seat: seatBid.seat,
22
- },
23
- },
24
- });
25
- }
26
- });
27
- });
28
- }
29
-
30
- return bids;
31
- }
32
- }
@@ -1,9 +0,0 @@
1
- export class BidNotFoundException {
2
- name = "BidNotFoundException";
3
- message = "Bid is not found.";
4
- }
5
-
6
- export class AlreadyEndedAuctionException {
7
- name = "AlreadyEndedAuctionException";
8
- message = "Auction is already ended.";
9
- }
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './Auction';
2
- export * from '@/exceptions';
@@ -1,43 +0,0 @@
1
- import type {
2
- Bid as BaseBidV26,
3
- BidResponse as BaseBidResponseV26,
4
- SeatBid as BaseSeatBidV26,
5
- } from "iab-openrtb/v26";
6
- export type {
7
- BidResponse as BaseBidResponseV26,
8
- Bid as BaseBidV26,
9
- } from "iab-openrtb/v26";
10
-
11
- export interface BidResponseV26 extends BaseBidResponseV26 {
12
- seatbid?: SeatBidV26[];
13
- }
14
- export interface SeatBidV26 extends BaseSeatBidV26 {
15
- bid: BidV26[];
16
- }
17
-
18
- export interface BidV26 extends BaseBidV26 {
19
- ext: {
20
- nextadjs: {
21
- openrtbVersion: "2.6";
22
- seat?: string;
23
- currency: string;
24
- };
25
- };
26
- }
27
-
28
-
29
- export interface CurrencyRates {
30
- /** ISO 4217 Currency Code (Example: USD, JPY, EUR) */
31
- [currency: string]: number;
32
- }
33
-
34
- interface ConversionRates {
35
- /** convert rate of base currency */
36
- [baseCurrency: string]: CurrencyRates;
37
- }
38
-
39
- export interface CurrencyConversionData {
40
- dataAsOf: string;
41
- generatedAt: string;
42
- conversions: ConversionRates;
43
- }
@@ -1,12 +0,0 @@
1
- {
2
- "extends": "../tsconfig.json",
3
- "compilerOptions": {
4
- "moduleResolution": "bundler",
5
- "types": ["vitest/globals"],
6
- "baseUrl": "..",
7
- "paths": {
8
- "@/*": ["src/*"]
9
- }
10
- },
11
- "include": ["./**/*.ts"]
12
- }
@@ -1,176 +0,0 @@
1
- import { openrtbFaker } from "@nextad/faker";
2
- import { Auction } from "@/Auction";
3
- import {
4
- AlreadyEndedAuctionException,
5
- BidNotFoundException,
6
- } from "@/exceptions";
7
-
8
- describe("Auction", () => {
9
- it("returns highest bid from bids with specified item(impression) when auction ends", () => {
10
- const sut = new Auction("impid-1");
11
- const bidResponse = openrtbFaker.v26.bidResponse
12
- .addBannerBid({ impid: "impid-1", price: 10 })
13
- .make();
14
- const bidResponse2 = openrtbFaker.v26.bidResponse
15
- .addBannerBid({ impid: "impid-1", price: 20 })
16
- .make();
17
- sut.placeBidResponseV26(bidResponse);
18
- sut.placeBidResponseV26(bidResponse2);
19
-
20
- const result = sut.end();
21
-
22
- expect(result.id).toBe(bidResponse2.seatbid![0].bid[0].id);
23
- });
24
-
25
- it("returns highest bid from bids with specified items(impressions) when auction ends", () => {
26
- const sut = new Auction(["impid-1", "impid-2"]);
27
- const bidResponse = openrtbFaker.v26.bidResponse
28
- .addBannerBid({ impid: "impid-1", price: 10 })
29
- .make();
30
- const bidResponse2 = openrtbFaker.v26.bidResponse
31
- .addBannerBid({ impid: "impid-1", price: 20 })
32
- .addVideoBid({ impid: "impid-2", price: 30 })
33
- .make();
34
- sut.placeBidResponseV26(bidResponse);
35
- sut.placeBidResponseV26(bidResponse2);
36
-
37
- const result = sut.end();
38
-
39
- expect(result.id).toBe(bidResponse2.seatbid![0].bid[1].id);
40
- });
41
-
42
- it("returns highest bid considering currency when auction ends", () => {
43
- const sut = new Auction("impid-1", {
44
- currencyConversionData: {
45
- dataAsOf: "2021-01-01",
46
- generatedAt: "2021-01-01",
47
- conversions: {
48
- JPY: {
49
- USD: 0.09,
50
- },
51
- },
52
- },
53
- });
54
- const bidResponse = openrtbFaker.v26.bidResponse
55
- .withCurrency("JPY")
56
- .addBannerBid({ impid: "impid-1", price: 10 })
57
- .make();
58
- const bidResponse2 = openrtbFaker.v26.bidResponse
59
- .withCurrency("USD")
60
- .addBannerBid({ impid: "impid-1", price: 5 })
61
- .make();
62
- sut.placeBidResponseV26(bidResponse);
63
- sut.placeBidResponseV26(bidResponse2);
64
-
65
- const result = sut.end();
66
-
67
- expect(result.id).toBe(bidResponse2.seatbid![0].bid[0].id);
68
- });
69
-
70
- it("throws error when attempting to end auction without bids", () => {
71
- const sut = new Auction("impid-1");
72
-
73
- expect(() => sut.end()).toThrow(BidNotFoundException);
74
- });
75
- it("returns losing bids when auction ends", () => {
76
- const sut = new Auction(["impid-1", "impid-2"]);
77
- const bidResponse = openrtbFaker.v26.bidResponse
78
- .addBannerBid({
79
- impid: "impid-1",
80
- price: 10,
81
- })
82
- .addBannerBid({
83
- impid: "impid-2",
84
- price: 20,
85
- })
86
- .make();
87
- sut.placeBidResponseV26(bidResponse);
88
-
89
- sut.end();
90
-
91
- const losingBids = sut.getLosingBids();
92
- expect(losingBids.v26.length).toBe(1);
93
- expect(losingBids.v26[0].id).toBe(bidResponse.seatbid![0].bid[0].id);
94
- });
95
-
96
- it("throws error when attempting to already ended auction", () => {
97
- const sut = new Auction("impid-1");
98
- const bidResponse = openrtbFaker.v26.bidResponse
99
- .addBannerBid({ impid: "impid-1", price: 10 })
100
- .make();
101
- sut.placeBidResponseV26(bidResponse);
102
- sut.end();
103
-
104
- expect(() => sut.end()).toThrow(AlreadyEndedAuctionException);
105
- });
106
-
107
- it("sends loss notification when bid contains loss notice url", () => {
108
- const fetchMock = vi.fn();
109
- vi.stubGlobal("fetch", fetchMock);
110
- const sut = new Auction(["impid-1", "impid-2"]);
111
- const bidResponse = openrtbFaker.v26.bidResponse
112
- .addBannerBid({
113
- impid: "impid-1",
114
- price: 10,
115
- lurl: "https://example.com/lurl",
116
- })
117
- .addBannerBid({
118
- impid: "impid-2",
119
- price: 20,
120
- })
121
- .make();
122
- sut.placeBidResponseV26(bidResponse);
123
-
124
- sut.end();
125
-
126
- expect(fetchMock).toHaveBeenCalledOnce();
127
- expect(fetchMock).toHaveBeenCalledWith("https://example.com/lurl", {
128
- keepalive: true,
129
- });
130
- });
131
-
132
- it("does not send loss notification when bid does not contain loss notice url", () => {
133
- const fetchMock = vi.fn();
134
- vi.stubGlobal("fetch", fetchMock);
135
- const sut = new Auction(["impid-1", "impid-2"]);
136
- const bidResponse = openrtbFaker.v26.bidResponse
137
- .addBannerBid({
138
- impid: "impid-1",
139
- price: 10,
140
- })
141
- .addBannerBid({
142
- impid: "impid-2",
143
- price: 20,
144
- })
145
- .make();
146
- sut.placeBidResponseV26(bidResponse);
147
-
148
- sut.end();
149
-
150
- expect(fetchMock).not.toHaveBeenCalled();
151
- });
152
-
153
- it("does not send loss notification when loss processing is specified as false", () => {
154
- const fetchMock = vi.fn();
155
- vi.stubGlobal("fetch", fetchMock);
156
- const sut = new Auction(["impid-1", "impid-2"], {
157
- lossProcessing: false,
158
- });
159
- const bidResponse = openrtbFaker.v26.bidResponse
160
- .addBannerBid({
161
- impid: "impid-1",
162
- price: 10,
163
- lurl: "https://example.com/lurl",
164
- })
165
- .addBannerBid({
166
- impid: "impid-2",
167
- price: 20,
168
- })
169
- .make();
170
- sut.placeBidResponseV26(bidResponse);
171
-
172
- sut.end();
173
-
174
- expect(fetchMock).not.toHaveBeenCalled();
175
- });
176
- });
package/tsconfig.json DELETED
@@ -1,29 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2022",
4
- "lib": ["es2022", "esnext.disposable", "dom"],
5
-
6
- "module": "ESNext",
7
- "moduleDetection": "force",
8
- "allowJs": true,
9
-
10
- "moduleResolution": "Bundler",
11
- "allowImportingTsExtensions": true,
12
- "verbatimModuleSyntax": true,
13
- "isolatedModules": true,
14
- "preserveConstEnums": true,
15
- "noEmit": true,
16
-
17
- "skipLibCheck": true,
18
- "strict": true,
19
- "noFallthroughCasesInSwitch": true,
20
- "forceConsistentCasingInFileNames": true,
21
-
22
- "baseUrl": ".",
23
- "paths": {
24
- "@/*": ["src/*"]
25
- }
26
- },
27
- "include": ["**/*.ts"],
28
- "exclude": ["node_modules"]
29
- }
package/tsup.config.ts DELETED
@@ -1,9 +0,0 @@
1
- import { defineConfig } from "tsup";
2
-
3
- export default defineConfig({
4
- format: ["esm", "cjs"],
5
- clean: true,
6
- minify: true,
7
- dts: true,
8
- entry: ["src/index.ts"],
9
- });
package/vitest.config.ts DELETED
@@ -1,14 +0,0 @@
1
- import { fileURLToPath } from "node:url";
2
- import path from "node:path";
3
- import { defineConfig } from "vitest/config";
4
-
5
- const __dirname = fileURLToPath(new URL(".", import.meta.url));
6
-
7
- export default defineConfig({
8
- test: {
9
- globals: true,
10
- alias: {
11
- "@": path.resolve(__dirname, "src"),
12
- },
13
- },
14
- });