decoy-duck 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -52
- package/README.ru.md +182 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
+
[English](README.md) · [Русский](README.ru.md)
|
|
2
|
+
|
|
1
3
|
# decoy-duck
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
Detects whether a browser ad filter is on. Four probes collapse into a verdict with a confidence level.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
The filter looks at the request URL. Four bait files sit on the site as ordinary static files and the browser requests them at known paths. They are not part of the application bundle.
|
|
6
8
|
|
|
7
|
-
##
|
|
9
|
+
## Install
|
|
8
10
|
|
|
9
11
|
```
|
|
10
12
|
npm install decoy-duck
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
The package is public. No custom registry is required. Package page: [decoy-duck](https://www.npmjs.com/package/decoy-duck).
|
|
14
16
|
|
|
15
|
-
##
|
|
17
|
+
## Setup
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
Two steps: call the check and place the bait files at the site root.
|
|
18
20
|
|
|
19
21
|
```js
|
|
20
22
|
import { detectAdblock } from 'decoy-duck'
|
|
@@ -22,18 +24,18 @@ import { detectAdblock } from 'decoy-duck'
|
|
|
22
24
|
const result = await detectAdblock()
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
Copy the files from `node_modules/decoy-duck/src/filter-check/baits/` into the build output directory. Keep these names:
|
|
26
28
|
|
|
27
|
-
|
|
|
29
|
+
| File in the package | URL on the site |
|
|
28
30
|
|---|---|
|
|
29
31
|
| `ad_header.js` | `/ad_header.js` |
|
|
30
32
|
| `assets/ctrl.js` | `/assets/ctrl.js` |
|
|
31
33
|
| `assets/pixel.png` | `/assets/pixel.png` |
|
|
32
34
|
| `ads/images/pixel.png` | `/ads/images/pixel.png` |
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
A hash in the filename changes the URL, and the filter rule no longer matches it.
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
Webpack does this with `copy-webpack-plugin`:
|
|
37
39
|
|
|
38
40
|
```js
|
|
39
41
|
import CopyPlugin from 'copy-webpack-plugin'
|
|
@@ -52,9 +54,9 @@ export default {
|
|
|
52
54
|
}
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
Leave these four files as static assets. Importing them into your module pulls their contents into the bundle: the browser never requests the expected URL, and the filter sees nothing.
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
A site at the domain root needs no extra URLs. If the page is served from `/app/`, the files live at `/app/ad_header.js` and the other three paths, and the check receives those URLs explicitly:
|
|
58
60
|
|
|
59
61
|
```js
|
|
60
62
|
import { detectAdblock, defaultBait } from 'decoy-duck'
|
|
@@ -70,18 +72,18 @@ const result = await detectAdblock({
|
|
|
70
72
|
})
|
|
71
73
|
```
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
Without the plugin, a path that starts with `/` is requested exactly as written in `bait`. The Vite plugin prefixes such a path with `base`. An absolute `https://` URL is passed through unchanged in both cases.
|
|
74
76
|
|
|
75
|
-
##
|
|
77
|
+
## Result
|
|
76
78
|
|
|
77
|
-
`detected`
|
|
79
|
+
`detected` is `true` only when the status is `active`. `false` means no filter was found. `null` means some probes did not answer, so there is no conclusion.
|
|
78
80
|
|
|
79
81
|
```js
|
|
80
82
|
{
|
|
81
83
|
detected: true,
|
|
82
84
|
status: 'active', // active | inactive | unknown
|
|
83
85
|
confidence: 'high', // high | medium | low
|
|
84
|
-
probability: 90, // 0–100,
|
|
86
|
+
probability: 90, // 0–100, chance the filter is on
|
|
85
87
|
signals: {
|
|
86
88
|
cosmetic: 'clear', // blocked | clear | inconclusive
|
|
87
89
|
script: 'blocked',
|
|
@@ -92,28 +94,28 @@ const result = await detectAdblock({
|
|
|
92
94
|
}
|
|
93
95
|
```
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
The four probes start in parallel. The script and the image each have a neutral control. If the control also fails to load, the probe stays `inconclusive`.
|
|
96
98
|
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
99
|
+
- A blocked script or image on your own domain means `active`, high confidence.
|
|
100
|
+
- A hidden element together with an unreachable third-party ad host means `active`, high confidence.
|
|
101
|
+
- A hidden element alone means `active`, medium confidence.
|
|
102
|
+
- A third-party host alone, while the other probes loaded, means `active`, medium confidence. That signal is "the ad host is unreachable": a filter, a proxy, DNS, or the host itself.
|
|
103
|
+
- Your own probes loaded, and the third-party probe is off (`skipped`) or also loaded, means `inactive`, high confidence.
|
|
104
|
+
- Anything else is `unknown`.
|
|
103
105
|
|
|
104
|
-
`probability`
|
|
106
|
+
`probability` is the chance the filter is on, from 0 to 100:
|
|
105
107
|
|
|
106
|
-
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
108
|
+
- both same-origin files are blocked — 98
|
|
109
|
+
- one of them is blocked — 90
|
|
110
|
+
- the element is hidden and the third-party host is unreachable — 85
|
|
111
|
+
- only the element is hidden — 60
|
|
112
|
+
- only the third-party host is unreachable — 40
|
|
113
|
+
- the same-origin probes loaded — 5
|
|
114
|
+
- there is no conclusion — 50
|
|
113
115
|
|
|
114
|
-
`decide(signals)`
|
|
116
|
+
`decide(signals)` is a pure function of the same rule. Types ship next to the package entry.
|
|
115
117
|
|
|
116
|
-
##
|
|
118
|
+
## Options
|
|
117
119
|
|
|
118
120
|
```js
|
|
119
121
|
import { detectAdblock, defaultBait } from 'decoy-duck'
|
|
@@ -128,15 +130,15 @@ const result = await detectAdblock({
|
|
|
128
130
|
})
|
|
129
131
|
```
|
|
130
132
|
|
|
131
|
-
`timeout`
|
|
133
|
+
`timeout` is the limit for network probes in milliseconds. The default is 2500. `signal` cancels the check.
|
|
132
134
|
|
|
133
|
-
`thirdParty: false`
|
|
135
|
+
`thirdParty: false` skips the request to the ad host. By default the check requests `pagead2.googlesyndication.com` once. Cookies and the referrer are not sent, but the host sees the IP and the User-Agent. The Google script itself does not run.
|
|
134
136
|
|
|
135
|
-
|
|
137
|
+
A dropped request is not proof of a filter. A CSP, a corporate proxy, a DNS failure, and the host being down look the same. A third-party probe on its own therefore yields `active` at medium confidence. High confidence comes from a blocked script or image on your own domain.
|
|
136
138
|
|
|
137
139
|
## Vite
|
|
138
140
|
|
|
139
|
-
|
|
141
|
+
On a Vite project the same four files can be laid out by the plugin. This path is optional: the check is still called through `detectAdblock()`.
|
|
140
142
|
|
|
141
143
|
```js
|
|
142
144
|
import { defineConfig } from 'vite'
|
|
@@ -147,34 +149,34 @@ export default defineConfig({
|
|
|
147
149
|
})
|
|
148
150
|
```
|
|
149
151
|
|
|
150
|
-
|
|
152
|
+
In dev the plugin serves the files at the `defaultBait` URLs, including the Vite `base`. On `vite build` it copies them into `build.outDir`. That directory is resolved from the config `root`, not from the process working directory. The files stay at the root of the output directory: `base` is a URL prefix, not a nested folder. Your own `bait` paths that start with `/` receive that prefix automatically.
|
|
151
153
|
|
|
152
|
-
|
|
154
|
+
In dev, importing the package is compiled to a virtual module with a neutral id. Otherwise Vite would request a file from `node_modules/decoy-duck/`, and a blocker could strip the detector itself.
|
|
153
155
|
|
|
154
|
-
|
|
156
|
+
If a file at the same path is already in the output directory and the bytes differ, the build stops and does not overwrite it.
|
|
155
157
|
|
|
156
|
-
##
|
|
158
|
+
## Developing this repository
|
|
157
159
|
|
|
158
|
-
|
|
160
|
+
Check without a browser: `npm test`.
|
|
159
161
|
|
|
160
|
-
|
|
162
|
+
Browser run against live extensions: `npm run test:browser`. It does not open a window. To watch the demo on screen, one extension at a time: `HEADED=1 npm run test:browser`. That run is not part of `npm test` and does not run before publish. Playwright downloads Chromium. The script downloads extension builds into `.cache/extensions`. The page opens as `localtest.me`, not `localhost`: filter lists leave the local host alone.
|
|
161
163
|
|
|
162
|
-
|
|
164
|
+
The run currently covers plain Chromium, uBlock Origin Lite (optimal and complete modes), AdGuard, [Adblock Plus](https://adblockplus.org/), and Ghostery. The full uBlock Origin release is still Manifest V2, and Chromium does not load it.
|
|
163
165
|
|
|
164
|
-
`npm run dev`
|
|
166
|
+
`npm run dev` in this repository opens the demo through the same public entry and the Vite plugin.
|
|
165
167
|
|
|
166
|
-
##
|
|
168
|
+
## Publishing
|
|
167
169
|
|
|
168
|
-
|
|
170
|
+
The package is public and unscoped. Repository: `github.com/N3P0m/decoy-duck`. Later versions are sent by GitHub Actions on a `v*` tag, workflow `.github/workflows/publish.yml`. The version in the tag must match `version` in `package.json`. Before upload, `prepublishOnly` runs the tests.
|
|
169
171
|
|
|
170
|
-
|
|
172
|
+
The first publish of a name that is not on the registry yet is done locally: `npm login`, then `npm publish`. npm asks for the 2FA code. Trusted Publishing can be configured only after the package exists, so the workflow does not use an `NPM_TOKEN` secret.
|
|
171
173
|
|
|
172
|
-
|
|
174
|
+
Right after the package appears on npmjs.com, open it → Settings → Trusted Publisher → GitHub Actions:
|
|
173
175
|
|
|
174
176
|
- Organization or user: `N3P0m`
|
|
175
177
|
- Repository: `decoy-duck`
|
|
176
178
|
- Workflow filename: `publish.yml`
|
|
177
|
-
- Environment
|
|
178
|
-
-
|
|
179
|
+
- Leave Environment empty
|
|
180
|
+
- Allow direct publishing with `npm publish`. New configurations allow only `npm stage publish` by default.
|
|
179
181
|
|
|
180
|
-
|
|
182
|
+
The first successful publish through this publisher has to happen within 48 hours, or the configuration expires. `repository.url` in `package.json` must stay `git+https://github.com/N3P0m/decoy-duck.git`: npm compares it with the repository that produced the OIDC token. The repository must be public, or provenance is omitted.
|
package/README.ru.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
[English](README.md) · [Русский](README.ru.md)
|
|
2
|
+
|
|
3
|
+
# decoy-duck
|
|
4
|
+
|
|
5
|
+
Проверка фильтра рекламы в браузере. Четыре пробы сводятся в вердикт с уровнем уверенности.
|
|
6
|
+
|
|
7
|
+
Фильтр смотрит на URL запроса. Четыре файла-приманки лежат на сайте как обычная статика и запрашиваются браузером по известным путям. В бандл приложения они не входят.
|
|
8
|
+
|
|
9
|
+
## Установка
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
npm install decoy-duck
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Пакет публичный, отдельный registry не нужен. Страница на npm: [decoy-duck](https://www.npmjs.com/package/decoy-duck).
|
|
16
|
+
|
|
17
|
+
## Подключение
|
|
18
|
+
|
|
19
|
+
Два шага: вызвать проверку и положить файлы-приманки в корень сайта.
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import { detectAdblock } from 'decoy-duck'
|
|
23
|
+
|
|
24
|
+
const result = await detectAdblock()
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Скопируйте файлы из `node_modules/decoy-duck/src/filter-check/baits/` в выходной каталог сборки. Имена остаются такими:
|
|
28
|
+
|
|
29
|
+
| Файл в пакете | Адрес на сайте |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `ad_header.js` | `/ad_header.js` |
|
|
32
|
+
| `assets/ctrl.js` | `/assets/ctrl.js` |
|
|
33
|
+
| `assets/pixel.png` | `/assets/pixel.png` |
|
|
34
|
+
| `ads/images/pixel.png` | `/ads/images/pixel.png` |
|
|
35
|
+
|
|
36
|
+
Хеш в имени файла меняет URL, и правило фильтра его уже не узнает.
|
|
37
|
+
|
|
38
|
+
В Webpack это делает `copy-webpack-plugin`:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
import CopyPlugin from 'copy-webpack-plugin'
|
|
42
|
+
|
|
43
|
+
export default {
|
|
44
|
+
plugins: [
|
|
45
|
+
new CopyPlugin({
|
|
46
|
+
patterns: [
|
|
47
|
+
{ from: 'node_modules/decoy-duck/src/filter-check/baits/ad_header.js', to: 'ad_header.js' },
|
|
48
|
+
{ from: 'node_modules/decoy-duck/src/filter-check/baits/assets/ctrl.js', to: 'assets/ctrl.js' },
|
|
49
|
+
{ from: 'node_modules/decoy-duck/src/filter-check/baits/assets/pixel.png', to: 'assets/pixel.png' },
|
|
50
|
+
{ from: 'node_modules/decoy-duck/src/filter-check/baits/ads/images/pixel.png', to: 'ads/images/pixel.png' },
|
|
51
|
+
],
|
|
52
|
+
}),
|
|
53
|
+
],
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Эти четыре файла оставляют статикой. Импорт их в свой модуль затягивает содержимое в бандл: браузер не делает запрос по нужному URL, и фильтр ничего не видит.
|
|
58
|
+
|
|
59
|
+
Сайт из корня домена дополнительных адресов не требует. Если страница открывается из `/app/`, файлы лежат по `/app/ad_header.js` и остальным трём путям, а проверка получает эти адреса явно:
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import { detectAdblock, defaultBait } from 'decoy-duck'
|
|
63
|
+
|
|
64
|
+
const result = await detectAdblock({
|
|
65
|
+
bait: {
|
|
66
|
+
...defaultBait,
|
|
67
|
+
scriptUrl: '/app/ad_header.js',
|
|
68
|
+
imageUrl: '/app/ads/images/pixel.png',
|
|
69
|
+
controlScriptUrl: '/app/assets/ctrl.js',
|
|
70
|
+
controlImageUrl: '/app/assets/pixel.png',
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Без плагина путь с ведущим `/` уходит как написан в `bait`. Плагин Vite сам добавляет к такому пути `base`. Абсолютный `https://` в обоих случаях передаётся как есть.
|
|
76
|
+
|
|
77
|
+
## Результат
|
|
78
|
+
|
|
79
|
+
`detected` равен `true`, только если статус `active`. `false` — фильтр не найден. `null` — часть проб не ответила, вывода нет.
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
{
|
|
83
|
+
detected: true,
|
|
84
|
+
status: 'active', // active | inactive | unknown
|
|
85
|
+
confidence: 'high', // high | medium | low
|
|
86
|
+
probability: 90, // 0–100, вероятность что фильтр включён
|
|
87
|
+
signals: {
|
|
88
|
+
cosmetic: 'clear', // blocked | clear | inconclusive
|
|
89
|
+
script: 'blocked',
|
|
90
|
+
image: 'clear',
|
|
91
|
+
thirdParty: 'clear', // blocked | clear | inconclusive | skipped
|
|
92
|
+
},
|
|
93
|
+
elapsedMs: 1040,
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Четыре пробы стартуют параллельно. У скрипта и картинки есть нейтральный контроль. Если не открылся и он, проба остаётся `inconclusive`.
|
|
98
|
+
|
|
99
|
+
- Заблокированный скрипт или картинка на своём домене — `active`, уверенность высокая.
|
|
100
|
+
- Вместе скрытый элемент и недоступный сторонний рекламный хост — `active`, уверенность высокая.
|
|
101
|
+
- Только скрытый элемент — `active`, уверенность средняя.
|
|
102
|
+
- Только сторонний хост, а остальные пробы открылись — `active`, уверенность средняя. Это «рекламный хост недоступен»: фильтр, прокси, DNS или сам хост.
|
|
103
|
+
- Все свои пробы открылись, а сторонняя выключена (`skipped`) или тоже открылась — `inactive`, уверенность высокая.
|
|
104
|
+
- Иначе — `unknown`.
|
|
105
|
+
|
|
106
|
+
`probability` — вероятность, что фильтр включён, от 0 до 100:
|
|
107
|
+
|
|
108
|
+
- оба своих файла закрыты — 98
|
|
109
|
+
- закрыт один из них — 90
|
|
110
|
+
- скрыт элемент и недоступен сторонний хост — 85
|
|
111
|
+
- скрыт только элемент — 60
|
|
112
|
+
- недоступен только сторонний хост — 40
|
|
113
|
+
- свои пробы открылись — 5
|
|
114
|
+
- вывода нет — 50
|
|
115
|
+
|
|
116
|
+
`decide(signals)` — чистая функция того же правила. Типы лежат рядом с входом пакета.
|
|
117
|
+
|
|
118
|
+
## Опции
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
import { detectAdblock, defaultBait } from 'decoy-duck'
|
|
122
|
+
|
|
123
|
+
const controller = new AbortController()
|
|
124
|
+
|
|
125
|
+
const result = await detectAdblock({
|
|
126
|
+
timeout: 2500,
|
|
127
|
+
signal: controller.signal,
|
|
128
|
+
thirdParty: false,
|
|
129
|
+
bait: { ...defaultBait },
|
|
130
|
+
})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`timeout` — предел сетевых проб в миллисекундах, по умолчанию 2500. `signal` отменяет проверку.
|
|
134
|
+
|
|
135
|
+
`thirdParty: false` не отправляет запрос к рекламному хосту. По умолчанию проверка один раз запрашивает `pagead2.googlesyndication.com`. Cookies и referrer не уходят, но хост видит IP и User-Agent. Скрипт Google при этом не выполняется.
|
|
136
|
+
|
|
137
|
+
Обрыв этого запроса — не доказательство фильтра. Так же выглядят CSP, корпоративный прокси, сбой DNS и недоступность самого хоста. Поэтому одна только сторонняя проба даёт `active` со средней уверенностью. Высокую уверенность дают заблокированные скрипт или картинка на своём домене.
|
|
138
|
+
|
|
139
|
+
## Vite
|
|
140
|
+
|
|
141
|
+
В проекте на Vite те же четыре файла может разложить плагин. Это необязательный путь: проверка по-прежнему вызывается через `detectAdblock()`.
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
import { defineConfig } from 'vite'
|
|
145
|
+
import { filterCheck } from 'decoy-duck/vite'
|
|
146
|
+
|
|
147
|
+
export default defineConfig({
|
|
148
|
+
plugins: [filterCheck()],
|
|
149
|
+
})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Плагин в dev отдаёт файлы по адресам из `defaultBait` с учётом Vite `base` и при `vite build` копирует их в `build.outDir`. Этот каталог считается от `root` конфига, а не от текущей папки процесса. Файлы остаются в корне выходного каталога: `base` — это префикс URL, а не вложенная папка. Свои пути с ведущим `/` в `bait` получают этот префикс сами.
|
|
153
|
+
|
|
154
|
+
Импорт пакета в dev собирается в виртуальный модуль с нейтральным id: иначе Vite запросил бы файл из `node_modules/decoy-duck/`, и блокировщик мог бы вырезать сам детектор.
|
|
155
|
+
|
|
156
|
+
Если файл с тем же путём уже лежит в выходном каталоге и байты отличаются, сборка останавливается и не затирает его.
|
|
157
|
+
|
|
158
|
+
## Разработка этого репозитория
|
|
159
|
+
|
|
160
|
+
Проверка без браузера: `npm test`.
|
|
161
|
+
|
|
162
|
+
Браузерный прогон с живыми расширениями: `npm run test:browser`. Окно при этом не открывается. Чтобы смотреть демо на экране, по одному расширению за раз: `HEADED=1 npm run test:browser`. Он не входит в `npm test` и перед публикацией не запускается. Chromium качает Playwright, сборки расширений — скрипт, в `.cache/extensions`. Страница открывается как `localtest.me`, а не `localhost`: списки фильтров не трогают локальный хост.
|
|
163
|
+
|
|
164
|
+
Сейчас в прогоне чистый Chromium, uBlock Origin Lite (оптимальный и полный режим), AdGuard, [Adblock Plus](https://adblockplus.org/ru/) и Ghostery. Полный uBlock Origin в текущем релизе всё ещё Manifest V2, Chromium его не загружает.
|
|
165
|
+
|
|
166
|
+
`npm run dev` в этом репозитории открывает демо через тот же публичный вход и плагин Vite.
|
|
167
|
+
|
|
168
|
+
## Публикация
|
|
169
|
+
|
|
170
|
+
Пакет публичный, без scope. Репозиторий: `github.com/N3P0m/decoy-duck`. Следующие версии отправляет GitHub Actions по тегу `v*`, файл `.github/workflows/publish.yml`. Версия в теге должна совпасть с `version` в `package.json`. Перед отправкой `prepublishOnly` запускает тесты.
|
|
171
|
+
|
|
172
|
+
Первый выпуск имени, которого ещё нет в реестре, делается локально: `npm login`, затем `npm publish`. npm спросит код 2FA. Trusted Publishing настраивается только у уже существующего пакета, поэтому секрет `NPM_TOKEN` workflow не использует.
|
|
173
|
+
|
|
174
|
+
Сразу после появления пакета на npmjs.com откройте его → Settings → Trusted Publisher → GitHub Actions:
|
|
175
|
+
|
|
176
|
+
- Organization or user: `N3P0m`
|
|
177
|
+
- Repository: `decoy-duck`
|
|
178
|
+
- Workflow filename: `publish.yml`
|
|
179
|
+
- Environment оставьте пустым
|
|
180
|
+
- Разрешите прямую публикацию через `npm publish`. Новые настройки по умолчанию пускают только `npm stage publish`.
|
|
181
|
+
|
|
182
|
+
Первая успешная публикация через этот publisher должна пройти в течение 48 часов, иначе настройка сгорает. Поле `repository.url` в `package.json` должно остаться `git+https://github.com/N3P0m/decoy-duck.git`: npm сверяет его с репозиторием, из которого пришёл OIDC-токен. Репозиторий должен быть публичным, иначе provenance не появится.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "decoy-duck",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Detect whether a browser ad filter is on: four probes and a probability. An optional Vite plugin serves the bait files.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"files": [
|
|
27
27
|
"src/filter-check",
|
|
28
28
|
"README.md",
|
|
29
|
+
"README.ru.md",
|
|
29
30
|
"!src/filter-check/**/*.test.js"
|
|
30
31
|
],
|
|
31
32
|
"scripts": {
|