@boldvideo/bold-js 0.1.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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.github/workflow/main.yml +21 -0
- package/.github/workflow/publish.yml +29 -0
- package/README.md +67 -0
- package/dist/index.cjs +237 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +203 -0
- package/package.json +21 -0
- package/src/index.ts +3 -0
- package/src/lib/client.ts +41 -0
- package/src/lib/fetchers.ts +33 -0
- package/src/lib/tracking.ts +115 -0
- package/src/lib/types.ts +48 -0
- package/src/util/throttle.ts +29 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changesets
|
|
2
|
+
|
|
3
|
+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
+
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
+
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
6
|
+
|
|
7
|
+
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
|
|
3
|
+
"changelog": "@changesets/cli/changelog",
|
|
4
|
+
"commit": false,
|
|
5
|
+
"fixed": [],
|
|
6
|
+
"linked": [],
|
|
7
|
+
"access": "restricted",
|
|
8
|
+
"baseBranch": "main",
|
|
9
|
+
"updateInternalDependencies": "patch",
|
|
10
|
+
"ignore": []
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- "**"
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v3
|
|
12
|
+
- uses: pnpm/action-setup@v2
|
|
13
|
+
with:
|
|
14
|
+
version: 7
|
|
15
|
+
- uses: actions/setup-node@v3
|
|
16
|
+
with:
|
|
17
|
+
node-version: 16.x
|
|
18
|
+
cache: "pnpm"
|
|
19
|
+
|
|
20
|
+
- run: pnpm install --frozen-lockfile
|
|
21
|
+
- run: pnpm run lint && pnpm run build
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- "main"
|
|
6
|
+
|
|
7
|
+
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v3
|
|
14
|
+
- uses: pnpm/action-setup@v2
|
|
15
|
+
with:
|
|
16
|
+
version: 7
|
|
17
|
+
- uses: actions/setup-node@v3
|
|
18
|
+
with:
|
|
19
|
+
node-version: 16.x
|
|
20
|
+
cache: "pnpm"
|
|
21
|
+
|
|
22
|
+
- run: pnpm install --frozen-lockfile
|
|
23
|
+
- name: Create Release Pull Request or Publish
|
|
24
|
+
id: changesets
|
|
25
|
+
uses: changesets/action@v1
|
|
26
|
+
with:
|
|
27
|
+
publish: pnpm run build
|
|
28
|
+
env:
|
|
29
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://wearebold.af?utm_source=github.com&utm_medium=readme&utm_campaign=bold-js" align="center">
|
|
3
|
+
<img src="https://wearebold.af/bold-js-github-header.svg" alt="Bold Logo">
|
|
4
|
+
</a>
|
|
5
|
+
<h1 align="center rainbow">@boldvideo/bold-js</h1>
|
|
6
|
+
<p align="center">
|
|
7
|
+
The JavaScript SDK for interacting with the <a href="http://wearebold.af?utm_source=github.com&utm_medium=readme&utm_campaign=bold-js" target="_blank">Bold API</a>, to power your own business video platform.
|
|
8
|
+
</p>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://npmjs.com/package/@boldvideo/bold-js">
|
|
13
|
+
<img src="https://img.shields.io/npm/v/@boldvideo/bold-js/latest.svg?style=flat-square" alt="Bold JS" />
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://npmjs.com/package/@boldvideo/bold-js" rel="nofollow">
|
|
16
|
+
<img src="https://img.shields.io/npm/dt/@boldvideo/bold-js.svg?style=flat-square" alt="npm">
|
|
17
|
+
</a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<a href="https://twitter.com/intent/follow?screen_name=veryboldvideo">
|
|
22
|
+
<img src="https://img.shields.io/badge/Follow-%40veryboldvideo-09b3af?style=appveyor&logo=twitter" alt="Follow @veryboldvideo" />
|
|
23
|
+
</a>
|
|
24
|
+
<a href="https://https://app.boldvideo.io/register?utm_source=github.com&utm_medium=readme&utm_campaign=bold-js">
|
|
25
|
+
<img src="https://img.shields.io/badge/Try%20Bold-Free-09b3af?style=appveyor&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAmCAYAAADTGStiAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGFSURBVHgBxZg9SwNBEIZ34xUpVLCwEQQRtRARxV+g4M8QLO0sBPtgZS129gr+AbEWWyshOUSCkipBjB8cBHPrM4GVQ84qZuaFJTebj+feyczu3fmxEIIbXjnjjZEy7hm3feeunfdPf33B/xO4TBk/fMoZHXMCHU1wVBP3m8Cb2mDRI/AN4K9xouJ0NA9ovzih5Vj0jutZXHcl0HIsmkicW4uBJtiR2kUr8KQJGPVMwJ62sgJ//hxrtROQNsvnDO30JbGaY9xeROggVnLcY/FYAPwcJ7Qc7xahKmAAe33vz0vmRysK6rASQs2FUC3Oq1U1xZVSWVukvCWxWlXjbgnYFc6nVMEiXK+wQx0MjhX346gPWmtOe5MQjQPdsQBLylctUi3gholjnE6bgFHVCpxZgR+s/uOGVTvdWLTTCyvXurpj3J7IfbOqY0BpLrcx3mea22Id6LZAJdYA56T3COhy8dFE4kYkHN7xcgnwDGD79/sJH6i54SQ1ItfLXZx1GC2CehmsqG96m37o1gSKagAAAABJRU5ErkJggg==" alt="Try Bold Video" />
|
|
26
|
+
</a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
First, install the library:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm install @boldvideo/bold-js
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Next, instantiate the client to establish a connection to your Bold Channel:
|
|
38
|
+
```js
|
|
39
|
+
import { createClient } from "@boldvideo/bold-js";
|
|
40
|
+
|
|
41
|
+
const bold = createClient('YOUR_API_KEY');
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Now you're able to query any of your resources from Bold. For exmaple:
|
|
45
|
+
```js
|
|
46
|
+
// fetches your channel settings, menus and featured playlists
|
|
47
|
+
const settings = await bold.settings();
|
|
48
|
+
|
|
49
|
+
// fetches the latest videos
|
|
50
|
+
const videos = await bold.videos.list();
|
|
51
|
+
|
|
52
|
+
// fetches the latest playlists
|
|
53
|
+
const playlists = await bold.playlists.list();
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Related Links
|
|
58
|
+
|
|
59
|
+
- **[Bold API Documentation](https://docs.boldvideo.io/docs/api)**
|
|
60
|
+
|
|
61
|
+
## More Resources
|
|
62
|
+
|
|
63
|
+
### Support
|
|
64
|
+
|
|
65
|
+
- Bugs or Feature Requests? [Submit an issue](/../../issues/new).
|
|
66
|
+
|
|
67
|
+
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defProps = Object.defineProperties;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
9
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
10
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
13
|
+
var __spreadValues = (a, b) => {
|
|
14
|
+
for (var prop in b || (b = {}))
|
|
15
|
+
if (__hasOwnProp.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
if (__getOwnPropSymbols)
|
|
18
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
19
|
+
if (__propIsEnum.call(b, prop))
|
|
20
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
|
+
}
|
|
22
|
+
return a;
|
|
23
|
+
};
|
|
24
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
25
|
+
var __export = (target, all) => {
|
|
26
|
+
for (var name in all)
|
|
27
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
28
|
+
};
|
|
29
|
+
var __copyProps = (to, from, except, desc) => {
|
|
30
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
31
|
+
for (let key of __getOwnPropNames(from))
|
|
32
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
33
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
34
|
+
}
|
|
35
|
+
return to;
|
|
36
|
+
};
|
|
37
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
38
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
39
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
40
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
41
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
42
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
43
|
+
mod
|
|
44
|
+
));
|
|
45
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
46
|
+
var __async = (__this, __arguments, generator) => {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
var fulfilled = (value) => {
|
|
49
|
+
try {
|
|
50
|
+
step(generator.next(value));
|
|
51
|
+
} catch (e) {
|
|
52
|
+
reject(e);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var rejected = (value) => {
|
|
56
|
+
try {
|
|
57
|
+
step(generator.throw(value));
|
|
58
|
+
} catch (e) {
|
|
59
|
+
reject(e);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
63
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// src/index.ts
|
|
68
|
+
var src_exports = {};
|
|
69
|
+
__export(src_exports, {
|
|
70
|
+
createClient: () => createClient
|
|
71
|
+
});
|
|
72
|
+
module.exports = __toCommonJS(src_exports);
|
|
73
|
+
|
|
74
|
+
// src/lib/client.ts
|
|
75
|
+
var import_axios = __toESM(require("axios"), 1);
|
|
76
|
+
|
|
77
|
+
// src/lib/fetchers.ts
|
|
78
|
+
function get(client, url) {
|
|
79
|
+
return __async(this, null, function* () {
|
|
80
|
+
const res = yield client.get(url);
|
|
81
|
+
return res.data;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function fetchSettings(client) {
|
|
85
|
+
return (videoLimit = 12) => __async(this, null, function* () {
|
|
86
|
+
return get(client, `settings?limit=${videoLimit}`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function fetchVideos(client) {
|
|
90
|
+
return (videoLimit = 12) => __async(this, null, function* () {
|
|
91
|
+
return get(client, `videos/latest?limit=${videoLimit}`);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function fetchVideo(client) {
|
|
95
|
+
return (id) => __async(this, null, function* () {
|
|
96
|
+
return get(client, `videos/${id}`);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function fetchPlaylists(client) {
|
|
100
|
+
return () => __async(this, null, function* () {
|
|
101
|
+
return get(client, "playlists");
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function fetchPlaylist(client) {
|
|
105
|
+
return (id) => __async(this, null, function* () {
|
|
106
|
+
return get(client, `playlists/${id}`);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/util/throttle.ts
|
|
111
|
+
var throttle = (fn, delay) => {
|
|
112
|
+
let wait = false;
|
|
113
|
+
let timeout;
|
|
114
|
+
let cancelled = false;
|
|
115
|
+
return [
|
|
116
|
+
(...args) => {
|
|
117
|
+
if (cancelled)
|
|
118
|
+
return void 0;
|
|
119
|
+
if (wait)
|
|
120
|
+
return void 0;
|
|
121
|
+
const val = fn(...args);
|
|
122
|
+
wait = true;
|
|
123
|
+
timeout = window.setTimeout(() => {
|
|
124
|
+
wait = false;
|
|
125
|
+
}, delay);
|
|
126
|
+
return val;
|
|
127
|
+
},
|
|
128
|
+
() => {
|
|
129
|
+
cancelled = true;
|
|
130
|
+
clearTimeout(timeout);
|
|
131
|
+
}
|
|
132
|
+
];
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/lib/tracking.ts
|
|
136
|
+
function sendEvent(client, eventName, data, debug) {
|
|
137
|
+
const payload = {
|
|
138
|
+
n: eventName,
|
|
139
|
+
u: data.url,
|
|
140
|
+
usr: data.userId,
|
|
141
|
+
d: data.domain,
|
|
142
|
+
ua: data.userAgent,
|
|
143
|
+
w: data.deviceWidth,
|
|
144
|
+
vid: (data == null ? void 0 : data.videoId) || void 0,
|
|
145
|
+
vt: data.title,
|
|
146
|
+
vdur: (data == null ? void 0 : data.videoDuration) || void 0,
|
|
147
|
+
time: (data == null ? void 0 : data.timeStamp) || void 0
|
|
148
|
+
};
|
|
149
|
+
if (debug)
|
|
150
|
+
console.log(`Bold SDK - Logging event '${eventName}'`, payload);
|
|
151
|
+
client.post("/event", payload);
|
|
152
|
+
}
|
|
153
|
+
var [throttledSendEvent] = throttle(sendEvent, 5e3);
|
|
154
|
+
function trackEvent(client, userId, options) {
|
|
155
|
+
return (video, event) => {
|
|
156
|
+
const eventDetails = __spreadProps(__spreadValues({}, basicInfos()), {
|
|
157
|
+
userId,
|
|
158
|
+
videoId: video.id,
|
|
159
|
+
title: video.title,
|
|
160
|
+
videoDuration: video.duration,
|
|
161
|
+
timeStamp: event.timeStamp
|
|
162
|
+
});
|
|
163
|
+
if (event.type == "timeupdate") {
|
|
164
|
+
throttledSendEvent(
|
|
165
|
+
client,
|
|
166
|
+
getEventName(event),
|
|
167
|
+
eventDetails,
|
|
168
|
+
options.debug
|
|
169
|
+
);
|
|
170
|
+
} else {
|
|
171
|
+
sendEvent(client, getEventName(event), eventDetails, options.debug);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function trackPageView(client, userId, options) {
|
|
176
|
+
return (title) => {
|
|
177
|
+
const eventDetails = __spreadProps(__spreadValues({}, basicInfos()), {
|
|
178
|
+
userId,
|
|
179
|
+
title
|
|
180
|
+
});
|
|
181
|
+
sendEvent(client, "page_view", eventDetails, options.debug);
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function getEventName({ type }) {
|
|
185
|
+
switch (type) {
|
|
186
|
+
case "pause":
|
|
187
|
+
return "video_pause";
|
|
188
|
+
case "play":
|
|
189
|
+
return "video_resume";
|
|
190
|
+
case "loadedmetadata":
|
|
191
|
+
return "video_load";
|
|
192
|
+
case "timeupdate":
|
|
193
|
+
return "video_progress";
|
|
194
|
+
default:
|
|
195
|
+
return "unknown_event";
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function basicInfos() {
|
|
199
|
+
return {
|
|
200
|
+
url: location.href,
|
|
201
|
+
domain: "localhost:3000",
|
|
202
|
+
referrer: document.referrer || null,
|
|
203
|
+
deviceWidth: window.innerWidth,
|
|
204
|
+
userAgent: navigator.userAgent
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/lib/client.ts
|
|
209
|
+
function createClient(apiKey, options = { debug: false }) {
|
|
210
|
+
var _a;
|
|
211
|
+
const { debug } = options;
|
|
212
|
+
const apiClientOptions = {
|
|
213
|
+
baseURL: (_a = options.baseURL) != null ? _a : "https://app.boldvideo.io/api/v1/",
|
|
214
|
+
headers: {
|
|
215
|
+
Authorization: apiKey
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const apiClient = import_axios.default.create(apiClientOptions);
|
|
219
|
+
const userId = [...Array(30)].map(() => Math.random().toString(36)[2]).join("");
|
|
220
|
+
return {
|
|
221
|
+
settings: fetchSettings(apiClient),
|
|
222
|
+
videos: {
|
|
223
|
+
list: fetchVideos(apiClient),
|
|
224
|
+
get: fetchVideo(apiClient)
|
|
225
|
+
},
|
|
226
|
+
playlists: {
|
|
227
|
+
list: fetchPlaylists(apiClient),
|
|
228
|
+
get: fetchPlaylist(apiClient)
|
|
229
|
+
},
|
|
230
|
+
trackEvent: trackEvent(apiClient, userId, { debug }),
|
|
231
|
+
trackPageView: trackPageView(apiClient, userId, { debug })
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
235
|
+
0 && (module.exports = {
|
|
236
|
+
createClient
|
|
237
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
type Video = {
|
|
2
|
+
captions: string;
|
|
3
|
+
captions_label: string;
|
|
4
|
+
captions_lang: string;
|
|
5
|
+
description: string | null;
|
|
6
|
+
duration: number;
|
|
7
|
+
id: string;
|
|
8
|
+
imported_from: string | null;
|
|
9
|
+
legacy_video_url: null | null;
|
|
10
|
+
meta_data: [];
|
|
11
|
+
playback_id: string;
|
|
12
|
+
published_at: string;
|
|
13
|
+
stream_url: string;
|
|
14
|
+
teaser: string | null;
|
|
15
|
+
thumbnail: string;
|
|
16
|
+
title: string;
|
|
17
|
+
transcription: string;
|
|
18
|
+
type: string;
|
|
19
|
+
};
|
|
20
|
+
type Playlist = {
|
|
21
|
+
description?: string;
|
|
22
|
+
id: string;
|
|
23
|
+
is_private: boolean;
|
|
24
|
+
title: string;
|
|
25
|
+
type: string;
|
|
26
|
+
videos: Video[];
|
|
27
|
+
};
|
|
28
|
+
type MenuItem = {
|
|
29
|
+
icon: string;
|
|
30
|
+
is_ext: boolean;
|
|
31
|
+
label: string;
|
|
32
|
+
url: string;
|
|
33
|
+
};
|
|
34
|
+
type Settings = {
|
|
35
|
+
featured_playlists: Playlist[];
|
|
36
|
+
menu_items: MenuItem[];
|
|
37
|
+
meta_data: {
|
|
38
|
+
channel_name: string;
|
|
39
|
+
description: string;
|
|
40
|
+
image: string;
|
|
41
|
+
no_seo: boolean;
|
|
42
|
+
title: string;
|
|
43
|
+
title_suffix: string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type ClientOptions = {
|
|
48
|
+
baseURL?: string;
|
|
49
|
+
debug: boolean;
|
|
50
|
+
};
|
|
51
|
+
declare function createClient(apiKey: string, options?: ClientOptions): {
|
|
52
|
+
settings: (videoLimit?: number) => Promise<{
|
|
53
|
+
data: Settings;
|
|
54
|
+
}>;
|
|
55
|
+
videos: {
|
|
56
|
+
list: (videoLimit?: number) => Promise<{
|
|
57
|
+
data: Video[];
|
|
58
|
+
}>;
|
|
59
|
+
get: (id: string) => Promise<{
|
|
60
|
+
data: Video;
|
|
61
|
+
}>;
|
|
62
|
+
};
|
|
63
|
+
playlists: {
|
|
64
|
+
list: () => Promise<{
|
|
65
|
+
data: Playlist[];
|
|
66
|
+
}>;
|
|
67
|
+
get: (id: string) => Promise<{
|
|
68
|
+
data: Playlist;
|
|
69
|
+
}>;
|
|
70
|
+
};
|
|
71
|
+
trackEvent: (video: any, event: Event) => void;
|
|
72
|
+
trackPageView: (title: string) => void;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export { createClient };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __async = (__this, __arguments, generator) => {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
var fulfilled = (value) => {
|
|
23
|
+
try {
|
|
24
|
+
step(generator.next(value));
|
|
25
|
+
} catch (e) {
|
|
26
|
+
reject(e);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var rejected = (value) => {
|
|
30
|
+
try {
|
|
31
|
+
step(generator.throw(value));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
reject(e);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
37
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/lib/client.ts
|
|
42
|
+
import axios from "axios";
|
|
43
|
+
|
|
44
|
+
// src/lib/fetchers.ts
|
|
45
|
+
function get(client, url) {
|
|
46
|
+
return __async(this, null, function* () {
|
|
47
|
+
const res = yield client.get(url);
|
|
48
|
+
return res.data;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function fetchSettings(client) {
|
|
52
|
+
return (videoLimit = 12) => __async(this, null, function* () {
|
|
53
|
+
return get(client, `settings?limit=${videoLimit}`);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function fetchVideos(client) {
|
|
57
|
+
return (videoLimit = 12) => __async(this, null, function* () {
|
|
58
|
+
return get(client, `videos/latest?limit=${videoLimit}`);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function fetchVideo(client) {
|
|
62
|
+
return (id) => __async(this, null, function* () {
|
|
63
|
+
return get(client, `videos/${id}`);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function fetchPlaylists(client) {
|
|
67
|
+
return () => __async(this, null, function* () {
|
|
68
|
+
return get(client, "playlists");
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function fetchPlaylist(client) {
|
|
72
|
+
return (id) => __async(this, null, function* () {
|
|
73
|
+
return get(client, `playlists/${id}`);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/util/throttle.ts
|
|
78
|
+
var throttle = (fn, delay) => {
|
|
79
|
+
let wait = false;
|
|
80
|
+
let timeout;
|
|
81
|
+
let cancelled = false;
|
|
82
|
+
return [
|
|
83
|
+
(...args) => {
|
|
84
|
+
if (cancelled)
|
|
85
|
+
return void 0;
|
|
86
|
+
if (wait)
|
|
87
|
+
return void 0;
|
|
88
|
+
const val = fn(...args);
|
|
89
|
+
wait = true;
|
|
90
|
+
timeout = window.setTimeout(() => {
|
|
91
|
+
wait = false;
|
|
92
|
+
}, delay);
|
|
93
|
+
return val;
|
|
94
|
+
},
|
|
95
|
+
() => {
|
|
96
|
+
cancelled = true;
|
|
97
|
+
clearTimeout(timeout);
|
|
98
|
+
}
|
|
99
|
+
];
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/lib/tracking.ts
|
|
103
|
+
function sendEvent(client, eventName, data, debug) {
|
|
104
|
+
const payload = {
|
|
105
|
+
n: eventName,
|
|
106
|
+
u: data.url,
|
|
107
|
+
usr: data.userId,
|
|
108
|
+
d: data.domain,
|
|
109
|
+
ua: data.userAgent,
|
|
110
|
+
w: data.deviceWidth,
|
|
111
|
+
vid: (data == null ? void 0 : data.videoId) || void 0,
|
|
112
|
+
vt: data.title,
|
|
113
|
+
vdur: (data == null ? void 0 : data.videoDuration) || void 0,
|
|
114
|
+
time: (data == null ? void 0 : data.timeStamp) || void 0
|
|
115
|
+
};
|
|
116
|
+
if (debug)
|
|
117
|
+
console.log(`Bold SDK - Logging event '${eventName}'`, payload);
|
|
118
|
+
client.post("/event", payload);
|
|
119
|
+
}
|
|
120
|
+
var [throttledSendEvent] = throttle(sendEvent, 5e3);
|
|
121
|
+
function trackEvent(client, userId, options) {
|
|
122
|
+
return (video, event) => {
|
|
123
|
+
const eventDetails = __spreadProps(__spreadValues({}, basicInfos()), {
|
|
124
|
+
userId,
|
|
125
|
+
videoId: video.id,
|
|
126
|
+
title: video.title,
|
|
127
|
+
videoDuration: video.duration,
|
|
128
|
+
timeStamp: event.timeStamp
|
|
129
|
+
});
|
|
130
|
+
if (event.type == "timeupdate") {
|
|
131
|
+
throttledSendEvent(
|
|
132
|
+
client,
|
|
133
|
+
getEventName(event),
|
|
134
|
+
eventDetails,
|
|
135
|
+
options.debug
|
|
136
|
+
);
|
|
137
|
+
} else {
|
|
138
|
+
sendEvent(client, getEventName(event), eventDetails, options.debug);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function trackPageView(client, userId, options) {
|
|
143
|
+
return (title) => {
|
|
144
|
+
const eventDetails = __spreadProps(__spreadValues({}, basicInfos()), {
|
|
145
|
+
userId,
|
|
146
|
+
title
|
|
147
|
+
});
|
|
148
|
+
sendEvent(client, "page_view", eventDetails, options.debug);
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function getEventName({ type }) {
|
|
152
|
+
switch (type) {
|
|
153
|
+
case "pause":
|
|
154
|
+
return "video_pause";
|
|
155
|
+
case "play":
|
|
156
|
+
return "video_resume";
|
|
157
|
+
case "loadedmetadata":
|
|
158
|
+
return "video_load";
|
|
159
|
+
case "timeupdate":
|
|
160
|
+
return "video_progress";
|
|
161
|
+
default:
|
|
162
|
+
return "unknown_event";
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function basicInfos() {
|
|
166
|
+
return {
|
|
167
|
+
url: location.href,
|
|
168
|
+
domain: "localhost:3000",
|
|
169
|
+
referrer: document.referrer || null,
|
|
170
|
+
deviceWidth: window.innerWidth,
|
|
171
|
+
userAgent: navigator.userAgent
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/lib/client.ts
|
|
176
|
+
function createClient(apiKey, options = { debug: false }) {
|
|
177
|
+
var _a;
|
|
178
|
+
const { debug } = options;
|
|
179
|
+
const apiClientOptions = {
|
|
180
|
+
baseURL: (_a = options.baseURL) != null ? _a : "https://app.boldvideo.io/api/v1/",
|
|
181
|
+
headers: {
|
|
182
|
+
Authorization: apiKey
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const apiClient = axios.create(apiClientOptions);
|
|
186
|
+
const userId = [...Array(30)].map(() => Math.random().toString(36)[2]).join("");
|
|
187
|
+
return {
|
|
188
|
+
settings: fetchSettings(apiClient),
|
|
189
|
+
videos: {
|
|
190
|
+
list: fetchVideos(apiClient),
|
|
191
|
+
get: fetchVideo(apiClient)
|
|
192
|
+
},
|
|
193
|
+
playlists: {
|
|
194
|
+
list: fetchPlaylists(apiClient),
|
|
195
|
+
get: fetchPlaylist(apiClient)
|
|
196
|
+
},
|
|
197
|
+
trackEvent: trackEvent(apiClient, userId, { debug }),
|
|
198
|
+
trackPageView: trackPageView(apiClient, userId, { debug })
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
export {
|
|
202
|
+
createClient
|
|
203
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@boldvideo/bold-js",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
11
|
+
"lint": "tsc"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@changesets/cli": "^2.26.0",
|
|
15
|
+
"tsup": "^6.6.3",
|
|
16
|
+
"typescript": "^4.9.5"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"axios": "^1.3.4"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import axios, { AxiosInstance } from "axios";
|
|
2
|
+
|
|
3
|
+
import { fetchVideo, fetchVideos, fetchSettings, fetchPlaylist, fetchPlaylists } from './fetchers'
|
|
4
|
+
import { trackEvent, trackPageView } from './tracking'
|
|
5
|
+
|
|
6
|
+
type ClientOptions = {
|
|
7
|
+
baseURL?: string
|
|
8
|
+
debug: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function createClient(apiKey: string, options: ClientOptions = {debug: false}) {
|
|
12
|
+
const { debug } = options;
|
|
13
|
+
const apiClientOptions = {
|
|
14
|
+
baseURL: options.baseURL ?? "https://app.boldvideo.io/api/v1/",
|
|
15
|
+
headers: {
|
|
16
|
+
Authorization: apiKey,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const apiClient: AxiosInstance = axios.create(apiClientOptions);
|
|
21
|
+
|
|
22
|
+
const userId = [...Array(30)]
|
|
23
|
+
.map(() => Math.random().toString(36)[2])
|
|
24
|
+
.join("");
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
settings: fetchSettings(apiClient),
|
|
28
|
+
videos: {
|
|
29
|
+
list: fetchVideos(apiClient),
|
|
30
|
+
get: fetchVideo(apiClient),
|
|
31
|
+
},
|
|
32
|
+
playlists: {
|
|
33
|
+
list: fetchPlaylists(apiClient),
|
|
34
|
+
get: fetchPlaylist(apiClient),
|
|
35
|
+
},
|
|
36
|
+
trackEvent: trackEvent(apiClient, userId, { debug }),
|
|
37
|
+
trackPageView: trackPageView(apiClient, userId, { debug }),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { createClient };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Video, Playlist, Settings } from './types'
|
|
2
|
+
import { AxiosInstance } from 'axios'
|
|
3
|
+
|
|
4
|
+
type Response<T> = {
|
|
5
|
+
data: T
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type ApiClient = AxiosInstance;
|
|
9
|
+
|
|
10
|
+
async function get<TResponse>(client: ApiClient, url: string): Promise<TResponse> {
|
|
11
|
+
const res = await client.get(url);
|
|
12
|
+
return res.data as TResponse;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function fetchSettings(client: ApiClient) {
|
|
16
|
+
return async (videoLimit = 12) => get<Response<Settings>>(client, `settings?limit=${videoLimit}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function fetchVideos(client: ApiClient) {
|
|
20
|
+
return async (videoLimit = 12) => get<Response<Video[]>>(client, `videos/latest?limit=${videoLimit}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function fetchVideo(client: ApiClient) {
|
|
24
|
+
return async (id: string) => get<Response<Video>>(client, `videos/${id}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function fetchPlaylists(client: ApiClient) {
|
|
28
|
+
return async () => get<Response<Playlist[]>>(client, "playlists");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function fetchPlaylist(client: ApiClient) {
|
|
32
|
+
return async (id: string) => get<Response<Playlist>>(client, `playlists/${id}`);
|
|
33
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { AxiosInstance } from "axios";
|
|
2
|
+
import { throttle } from "util/throttle";
|
|
3
|
+
|
|
4
|
+
type ApiClient = AxiosInstance;
|
|
5
|
+
|
|
6
|
+
type Options = {
|
|
7
|
+
debug: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type EventData = {
|
|
11
|
+
url: string;
|
|
12
|
+
userId: string;
|
|
13
|
+
domain: string;
|
|
14
|
+
userAgent: string;
|
|
15
|
+
deviceWidth: number;
|
|
16
|
+
videoId?: string;
|
|
17
|
+
title: string;
|
|
18
|
+
videoDuration?: number;
|
|
19
|
+
timeStamp?: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function sendEvent(
|
|
23
|
+
client: ApiClient,
|
|
24
|
+
eventName: string,
|
|
25
|
+
data: EventData,
|
|
26
|
+
debug: boolean
|
|
27
|
+
) {
|
|
28
|
+
const payload = {
|
|
29
|
+
n: eventName,
|
|
30
|
+
u: data.url,
|
|
31
|
+
usr: data.userId,
|
|
32
|
+
d: data.domain,
|
|
33
|
+
ua: data.userAgent,
|
|
34
|
+
w: data.deviceWidth,
|
|
35
|
+
vid: data?.videoId || undefined,
|
|
36
|
+
vt: data.title,
|
|
37
|
+
vdur: data?.videoDuration || undefined,
|
|
38
|
+
time: data?.timeStamp || undefined,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (debug) console.log(`Bold SDK - Logging event '${eventName}'`, payload);
|
|
42
|
+
|
|
43
|
+
client.post("/event", payload);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const [throttledSendEvent] = throttle(sendEvent, 5000);
|
|
47
|
+
|
|
48
|
+
export function trackEvent(
|
|
49
|
+
client: ApiClient,
|
|
50
|
+
userId: string,
|
|
51
|
+
options: Options
|
|
52
|
+
) {
|
|
53
|
+
// TODO: verify event
|
|
54
|
+
return (video: any, event: Event) => {
|
|
55
|
+
const eventDetails = {
|
|
56
|
+
...basicInfos(),
|
|
57
|
+
userId,
|
|
58
|
+
videoId: video.id,
|
|
59
|
+
title: video.title,
|
|
60
|
+
videoDuration: video.duration,
|
|
61
|
+
timeStamp: event.timeStamp,
|
|
62
|
+
};
|
|
63
|
+
// debounce fast hitting timeupdate event
|
|
64
|
+
if (event.type == "timeupdate") {
|
|
65
|
+
throttledSendEvent(
|
|
66
|
+
client,
|
|
67
|
+
getEventName(event),
|
|
68
|
+
eventDetails,
|
|
69
|
+
options.debug
|
|
70
|
+
);
|
|
71
|
+
} else {
|
|
72
|
+
sendEvent(client, getEventName(event), eventDetails, options.debug);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function trackPageView(
|
|
78
|
+
client: ApiClient,
|
|
79
|
+
userId: string,
|
|
80
|
+
options: Options
|
|
81
|
+
) {
|
|
82
|
+
return (title: string) => {
|
|
83
|
+
const eventDetails = {
|
|
84
|
+
...basicInfos(),
|
|
85
|
+
userId,
|
|
86
|
+
title,
|
|
87
|
+
};
|
|
88
|
+
sendEvent(client, "page_view", eventDetails, options.debug);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getEventName({ type }: { type: string }) {
|
|
93
|
+
switch (type) {
|
|
94
|
+
case "pause":
|
|
95
|
+
return "video_pause";
|
|
96
|
+
case "play":
|
|
97
|
+
return "video_resume";
|
|
98
|
+
case "loadedmetadata":
|
|
99
|
+
return "video_load";
|
|
100
|
+
case "timeupdate":
|
|
101
|
+
return "video_progress";
|
|
102
|
+
default:
|
|
103
|
+
return "unknown_event";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function basicInfos() {
|
|
108
|
+
return {
|
|
109
|
+
url: location.href,
|
|
110
|
+
domain: "localhost:3000",
|
|
111
|
+
referrer: document.referrer || null,
|
|
112
|
+
deviceWidth: window.innerWidth,
|
|
113
|
+
userAgent: navigator.userAgent,
|
|
114
|
+
};
|
|
115
|
+
}
|
package/src/lib/types.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type Video = {
|
|
2
|
+
captions: string;
|
|
3
|
+
captions_label: string;
|
|
4
|
+
captions_lang: string;
|
|
5
|
+
description: string | null;
|
|
6
|
+
duration: number;
|
|
7
|
+
id: string;
|
|
8
|
+
imported_from: string | null;
|
|
9
|
+
legacy_video_url: null | null;
|
|
10
|
+
meta_data: [];
|
|
11
|
+
playback_id: string;
|
|
12
|
+
published_at: string;
|
|
13
|
+
stream_url: string;
|
|
14
|
+
teaser: string | null;
|
|
15
|
+
thumbnail: string;
|
|
16
|
+
title: string;
|
|
17
|
+
transcription: string;
|
|
18
|
+
type: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type Playlist = {
|
|
22
|
+
description?: string;
|
|
23
|
+
id: string;
|
|
24
|
+
is_private: boolean;
|
|
25
|
+
title: string;
|
|
26
|
+
type: string;
|
|
27
|
+
videos: Video[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type MenuItem = {
|
|
31
|
+
icon: string;
|
|
32
|
+
is_ext: boolean;
|
|
33
|
+
label: string;
|
|
34
|
+
url: string;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type Settings = {
|
|
38
|
+
featured_playlists: Playlist[];
|
|
39
|
+
menu_items: MenuItem[];
|
|
40
|
+
meta_data: {
|
|
41
|
+
channel_name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
image: string;
|
|
44
|
+
no_seo: boolean;
|
|
45
|
+
title: string;
|
|
46
|
+
title_suffix: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const throttle = <R, A extends any[]>(
|
|
2
|
+
fn: (...args: A) => R,
|
|
3
|
+
delay: number
|
|
4
|
+
): [(...args: A) => R | undefined, () => void] => {
|
|
5
|
+
let wait = false;
|
|
6
|
+
let timeout: undefined | number;
|
|
7
|
+
let cancelled = false;
|
|
8
|
+
|
|
9
|
+
return [
|
|
10
|
+
(...args: A) => {
|
|
11
|
+
if (cancelled) return undefined;
|
|
12
|
+
if (wait) return undefined;
|
|
13
|
+
|
|
14
|
+
const val = fn(...args);
|
|
15
|
+
|
|
16
|
+
wait = true;
|
|
17
|
+
|
|
18
|
+
timeout = window.setTimeout(() => {
|
|
19
|
+
wait = false;
|
|
20
|
+
}, delay);
|
|
21
|
+
|
|
22
|
+
return val;
|
|
23
|
+
},
|
|
24
|
+
() => {
|
|
25
|
+
cancelled = true;
|
|
26
|
+
clearTimeout(timeout);
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2016",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"forceConsistentCasingInFileNames": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"noUncheckedIndexedAccess": true,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"baseUrl": "src"
|
|
12
|
+
}
|
|
13
|
+
}
|