astro-indexnow 2.3.4 โ 2.3.5
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 +42 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -18
- package/package.json +2 -1
package/README.MD
CHANGED
|
@@ -6,11 +6,23 @@ to **IndexNow** after each build.
|
|
|
6
6
|
This package is designed for **modern CI/CD pipelines**, **Docker-based deployments**, and
|
|
7
7
|
**large static sites**, while remaining fully deterministic and explicit.
|
|
8
8
|
|
|
9
|
-
> **Current release:** v2.3.
|
|
9
|
+
> **Current release:** v2.3.5
|
|
10
10
|
> **Stateful by design. `changed` by default, `all` available. Batch-safe. CI-aware.**
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## Compatibility Matrix
|
|
15
|
+
|
|
16
|
+
| Platform | Supported | Notes |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| Astro | 4.x, 5.x, 6.x, 7.x | Build-time integration works in static and hybrid builds |
|
|
19
|
+
| Node.js | `>=22.12.0` | Matches Astro v7 runtime floor |
|
|
20
|
+
| Static builds | Yes | Primary supported use case |
|
|
21
|
+
| Hybrid builds | Yes | Works for prerendered output generated at build time |
|
|
22
|
+
| SSR request-time submission | No | Use a webhook or server-side helper instead |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
14
26
|
## What is IndexNow?
|
|
15
27
|
|
|
16
28
|
[IndexNow](https://www.indexnow.org/) is a protocol supported by search engines such as **Bing**
|
|
@@ -31,6 +43,7 @@ Instead of waiting for crawlers, your site tells search engines exactly which UR
|
|
|
31
43
|
- ๐งช Optional `dryRun` plans submissions without sending requests
|
|
32
44
|
- ๐ฃ Optional `logMode` controls verbosity with `quiet`, `normal`, and `verbose`
|
|
33
45
|
- ๐ฆ Optional `batchSize` lets you lower the submit batch size for testing
|
|
46
|
+
- ๐ Optional retry controls let you tune transient failure handling
|
|
34
47
|
- ๐งช Fully **CI/CD and Docker safe**
|
|
35
48
|
- ๐ No secrets prompted, stored, or mutated
|
|
36
49
|
- ๐งฉ No client-side or runtime code added
|
|
@@ -306,6 +319,33 @@ indexnow({
|
|
|
306
319
|
|
|
307
320
|
---
|
|
308
321
|
|
|
322
|
+
### `retryAttempts` (optional)
|
|
323
|
+
|
|
324
|
+
Type: `number`
|
|
325
|
+
Default: `3`
|
|
326
|
+
|
|
327
|
+
Controls how many times a failed batch submission is retried.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
### `retryBaseDelayMs` (optional)
|
|
332
|
+
|
|
333
|
+
Type: `number`
|
|
334
|
+
Default: `1000`
|
|
335
|
+
|
|
336
|
+
Controls the starting delay for exponential backoff between retries.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
### `retryMaxDelayMs` (optional)
|
|
341
|
+
|
|
342
|
+
Type: `number`
|
|
343
|
+
Default: `8000`
|
|
344
|
+
|
|
345
|
+
Controls the maximum backoff delay between retries.
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
309
349
|
## IndexNow Limits & Batching
|
|
310
350
|
|
|
311
351
|
- IndexNow allows **up to 10,000 URLs per request**
|
|
@@ -321,6 +361,7 @@ indexnow({
|
|
|
321
361
|
- No prompts or side effects
|
|
322
362
|
- No reliance on Git history
|
|
323
363
|
- Deterministic output-based change detection
|
|
364
|
+
- Intended for static and hybrid builds, not SSR request-time submission
|
|
324
365
|
|
|
325
366
|
---
|
|
326
367
|
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export interface IndexNowOptions {
|
|
|
8
8
|
logMode?: "quiet" | "normal" | "verbose";
|
|
9
9
|
submissionMode?: "changed" | "all";
|
|
10
10
|
batchSize?: number;
|
|
11
|
+
retryAttempts?: number;
|
|
12
|
+
retryBaseDelayMs?: number;
|
|
13
|
+
retryMaxDelayMs?: number;
|
|
11
14
|
}
|
|
12
15
|
export default function indexNow(options?: IndexNowOptions): AstroIntegration;
|
|
13
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAM9C,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,cAAc,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAM9C,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,cAAc,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC9B,OAAO,GAAE,eAAoB,GAC5B,gBAAgB,CAuTlB"}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,15 @@ export default function indexNow(options = {}) {
|
|
|
14
14
|
const batchSize = typeof options.batchSize === "number" && options.batchSize > 0
|
|
15
15
|
? Math.floor(options.batchSize)
|
|
16
16
|
: INDEXNOW_BATCH_SIZE;
|
|
17
|
+
const retryAttempts = typeof options.retryAttempts === "number" && options.retryAttempts > 0
|
|
18
|
+
? Math.floor(options.retryAttempts)
|
|
19
|
+
: 3;
|
|
20
|
+
const retryBaseDelayMs = typeof options.retryBaseDelayMs === "number" && options.retryBaseDelayMs > 0
|
|
21
|
+
? Math.floor(options.retryBaseDelayMs)
|
|
22
|
+
: 1000;
|
|
23
|
+
const retryMaxDelayMs = typeof options.retryMaxDelayMs === "number" && options.retryMaxDelayMs > 0
|
|
24
|
+
? Math.floor(options.retryMaxDelayMs)
|
|
25
|
+
: 8000;
|
|
17
26
|
/* =========================================================
|
|
18
27
|
Helpers
|
|
19
28
|
========================================================= */
|
|
@@ -57,6 +66,9 @@ export default function indexNow(options = {}) {
|
|
|
57
66
|
}
|
|
58
67
|
return chunks;
|
|
59
68
|
}
|
|
69
|
+
function sleep(ms) {
|
|
70
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
71
|
+
}
|
|
60
72
|
function isQuiet() {
|
|
61
73
|
return options.logMode === "quiet";
|
|
62
74
|
}
|
|
@@ -75,6 +87,47 @@ export default function indexNow(options = {}) {
|
|
|
75
87
|
if (isVerbose())
|
|
76
88
|
logger.info(message);
|
|
77
89
|
}
|
|
90
|
+
function isRetryableStatus(status) {
|
|
91
|
+
return status === 429 || (status >= 500 && status < 600);
|
|
92
|
+
}
|
|
93
|
+
async function submitBatch(logger, batch, batchIndex) {
|
|
94
|
+
for (let attempt = 1; attempt <= retryAttempts; attempt++) {
|
|
95
|
+
try {
|
|
96
|
+
const response = await fetch(INDEXNOW_ENDPOINT, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: { "Content-Type": "application/json" },
|
|
99
|
+
body: JSON.stringify({
|
|
100
|
+
host: new URL(site).host,
|
|
101
|
+
key: options.key,
|
|
102
|
+
keyLocation: `${site}/${options.key}.txt`,
|
|
103
|
+
urlList: batch,
|
|
104
|
+
}),
|
|
105
|
+
});
|
|
106
|
+
if (response.ok) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (!isRetryableStatus(response.status) || attempt === retryAttempts) {
|
|
110
|
+
logWarn(logger, `batch ${batchIndex} failed (${response.status})`);
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const delay = Math.min(retryBaseDelayMs * 2 ** (attempt - 1), retryMaxDelayMs) +
|
|
114
|
+
Math.floor(Math.random() * 250);
|
|
115
|
+
logWarn(logger, `batch ${batchIndex} attempt ${attempt} failed (${response.status}), retrying in ${delay}ms`);
|
|
116
|
+
await sleep(delay);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
if (attempt === retryAttempts) {
|
|
120
|
+
logWarn(logger, `batch ${batchIndex} submission failed (network error)`);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
const delay = Math.min(retryBaseDelayMs * 2 ** (attempt - 1), retryMaxDelayMs) +
|
|
124
|
+
Math.floor(Math.random() * 250);
|
|
125
|
+
logWarn(logger, `batch ${batchIndex} submission failed (network error), retrying in ${delay}ms`);
|
|
126
|
+
await sleep(delay);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
78
131
|
/* =========================================================
|
|
79
132
|
Integration
|
|
80
133
|
========================================================= */
|
|
@@ -159,30 +212,22 @@ export default function indexNow(options = {}) {
|
|
|
159
212
|
logInfo(logger, "dry run enabled, skipping submission");
|
|
160
213
|
return;
|
|
161
214
|
}
|
|
215
|
+
let anyBatchFailed = false;
|
|
162
216
|
for (let i = 0; i < batches.length; i++) {
|
|
163
217
|
const batch = batches[i];
|
|
164
218
|
logVerbose(logger, `submitting batch ${i + 1}/${batches.length} (${batch.length} URLs)`);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
headers: { "Content-Type": "application/json" },
|
|
169
|
-
body: JSON.stringify({
|
|
170
|
-
host: new URL(site).host,
|
|
171
|
-
key: options.key,
|
|
172
|
-
keyLocation: `${site}/${options.key}.txt`,
|
|
173
|
-
urlList: batch,
|
|
174
|
-
}),
|
|
175
|
-
});
|
|
176
|
-
if (!response.ok) {
|
|
177
|
-
logWarn(logger, `batch ${i + 1} failed (${response.status})`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
logWarn(logger, `batch ${i + 1} submission failed (network error)`);
|
|
219
|
+
const batchSucceeded = await submitBatch(logger, batch, i + 1);
|
|
220
|
+
if (!batchSucceeded) {
|
|
221
|
+
anyBatchFailed = true;
|
|
182
222
|
}
|
|
183
223
|
}
|
|
184
224
|
saveCache(logger, nextCache);
|
|
185
|
-
|
|
225
|
+
if (anyBatchFailed) {
|
|
226
|
+
logWarn(logger, `IndexNow submission failed`);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
logInfo(logger, `IndexNow submission complete`);
|
|
230
|
+
}
|
|
186
231
|
},
|
|
187
232
|
},
|
|
188
233
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-indexnow",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.5",
|
|
4
4
|
"description": "Astro integration to submit pages to IndexNow automatically after build",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsc",
|
|
14
|
+
"release:check": "node ./scripts/release-check.mjs",
|
|
14
15
|
"prepublishOnly": "npm run build"
|
|
15
16
|
},
|
|
16
17
|
"keywords": [
|