Repository navigation
Releases
0.15.0
Added
indexnowkit.clock(Clock\SystemClock, aliased toPsr\Clock\ClockInterface): the one service every piece
that reads the time takes it from —indexnowkit.throttle, thememoryindexnowkit.debounce_store,
indexnowkit.submitter,indexnowkit.command_submitter_factoryand, withverify.enabled, the pre-flight
decorators. Replace it withIndexNowKit\Testing\FrozenClockin a compiler pass and the debounce window, the
throttle window and the time a submission record gets all move together (audit 0.13 A5; docs/extending.md,
docs/testing.md).indexnowkit.check.locales(the core'sCheck\LocalesCheckoverCheck\MappedClasses, coderouter.locales):
oneindexnow:checkwarning when a#[IndexNow(locales: 'all')]rule meets an emptyframework.enabled_locales,
which until now silently produced one URL without a locale instead of one per locale (audit 0.13 W14; the class
moved to the core in wave M, spec 19 §4.4, one text for the three adapters that print it).- The router bridge warns once per process when
locales: 'all'meets an emptyframework.enabled_locales
(indexnowkit.route_url_resolvertakes the logger now, on theindexnowchannel): the rule silently collapsing
to one URL was, until now, a line ofcheckonly. The expansion, the pinned origin and the exception text are the
core'sUrl\RouteOrigin(wave M, spec 19 §4.6).
Changed
-
Wave M (spec 19): the bundle's copies of what the family shares are the core's or the packages' classes.
Check\LocalesCheckandCheck\EntitySamplerare removed — the service ids stay (indexnowkit.check.localesis the
core'sCheck\LocalesCheckover the newCheck\MappedClasses,indexnowkit.check.entity_sampler.callableis
Console\SubjectSamplerofindexnowkit/console).Command\EntityLoaderextendsConsole\AbstractSubjectLoader
(its constructor andmanager()are unchanged).Messenger\MessengerDispatcheris the Messenger push around the
core'sDispatch\BatchingDispatcher: its constructor takes theConfig(indexnowkit.config) where it took
$logUrlsand$batchMaxUrls— an internal service (indexnowkit.dispatcher), not indocs/bc.md— and its log
lines are the core's ({count} URL(s) queued as message {id},cannot queue {count} URL(s) (message {id}), they are lost: {error}; docs/messenger.md).SubmitUrlsMessage::newId()delegates toBatchingDispatcher::newJobId().
EventListener\FlushListenertakes(CollectorInterface, Closure(): IndexNowKit)instead of a PSR-11 service
locator (PSR-11 says a container should not be passed in for an object to fetch its own dependencies; a
service_closure('indexnowkit')is as lazy). Migration: aFlushListenerbuilt by hand passes
static fn () => $container->get('indexnowkit').Check\CacheProbewrites the core'sDebounceStoreCheck::PROBE_KEY
(it only read a key). The nine literal'memory'/'none'comparisons of the loader are
DebounceStoreFactory::isShared(); thestatusline of the debounce store isHistoryServices::describeStore()
ofindexnowkit/history(cache.app (missing)when the pool is not a service, where the bundle printed the bare id). -
The command classes are the packages',
Command\*of the bundle is gone (wave L, spec 18).indexnow:check,
indexnow:config,indexnow:submit,indexnow:submit-entity,indexnow:explain,indexnow:key:generateand the
three "not installed" stubs areIndexNowKit\Console\Command\*ofindexnowkit/console0.5 (submit-entityis
SubmitSubjectsCommand, named by the vocabulary),indexnow:sitemapisIndexNowKit\Sitemap\Console\SitemapCommand
(sitemap 0.8),indexnow:historyandindexnow:statusareIndexNowKit\History\Console\HistoryCommand/
StatusCommand(history 0.4). The bundle registers them under their class names with the same runners
(indexnowkit.console.*), the same names, arguments, options, exit codes and--json; the Yii3 package registers
the very same classes. Whatcheckandconfigread isDependencyInjection\ConsoleConfigSource
(indexnowkit.console.config_source, aConsole\ConfigSourceInterface) instead of three constructor arguments.
Everyconsole.commandstays lazy (#[AsCommand], or thecommand+descriptionattributes of the tag for
SubmitSubjectsCommand), which the bundle's own test now asserts.Command\EntityLoaderstays where it is.
Migration: only a direct reference toIndexNowKit\SymfonyBundle\Command\*Commandbreaks — adecorates:on one of
those ids, aninstanceof, a#[AsCommand]subclass (they werefinal). Decorate the runner instead
(indexnowkit.console.submit_entity, …), or register a command of your own under the same name
(docs/extending.md "Replacing a command"). -
The
--samplegate ofindexnow:checkis the core's:indexnowkit.check.samplesis
IndexNowKit\Check\SampleOptionsandindexnowkit.check.verify_sampleisIndexNowKit\Check\SampleGateCheck
(core 0.13.0) instead of the bundle's own byte-identical copies, which are removed —
IndexNowKit\SymfonyBundle\Check\SampleOptionsandIndexNowKit\SymfonyBundle\Check\VerifySampleCheckare gone.
Same service ids, same lines, sameverify.installedcode; only a direct reference to those two classes breaks
(audit 0.13 A2). -
indexnowkit.verify.submitterandindexnowkit.verify.command_submitter_factorypass their arguments by name
($inner,$transport, …) rather than by position, so a parameter added toVerify\VerifyingSubmitterfails the
compilation instead of shifting values into the wrong slots (audit 0.13 A16). -
DispatcherFactory::SYNCinstead of the'sync'literal inDependencyInjection\VerifyServices(audit 0.13 A19).
Fixed
- The profiler panel no longer prints the submission store's raw exception message: a failing store shows the
exception class plus a message whose DSN credentials are masked the wayindexnow:configmasks them, so a panel
screenshot in a bug report carries no database user or password (audit 0.13 S12). - Fixed: the bundle was a fatal without
indexnowkit/sitemap,indexnowkit/verifyorindexnowkit/history
(Class "IndexNowKit\Sitemap\Adapter\SitemapServices" not foundwhile compiling the container): the configuration
tree and the loader asked the packages'*Services::package()whether the package is installed, and those classes
live in the packages. They now ask the core'sAdapter\OptionalPackage::sitemap()/verify()/history()
(core 0.13.0);DependencyInjection\{Sitemap,Verify,History}Services::package()delegate there too. Same texts, same
service ids. A new CI job removes the three packages and boots the bundle with detection
(OptionalPackagesDetectionTest). - Requires
indexnowkit/core ^0.13,indexnowkit/console ^0.5, andindexnowkit/history ^0.4when installed
(conflictwith older).
Tests
- The kernels of the functional suite put a fingerprint of the bundle's sources in the container cache path: with
debug: falseSymfony never checks the compiled container for freshness, so a local edit of the DI extension was
tested against the previous container (audit 0.13 T10). - The in-memory Messenger transport of the
messenger*variants runs with?serialize=true, so the message and its
stamps are really encoded and decoded instead of being handed back as the same object (audit 0.13 T17). - A
#[IndexNow(resolver: ...)]id the container knows but cannot build, and one it does not know at all, are
asserted to carry the family'sConfigurationExceptiontexts, which now come from the core's
Url\ArrayResolverLocator(audit 0.13 A10).
0.14.0
Changed
- The optional packages wire themselves:
DependencyInjection\{Verify,History,Sitemap}Serviceskeep the service ids,
the configuration nodes and the definitions but take the predicate, the check line, the sample check factory, the PDO
of a DSN, the 403 counter and the status runner fromVerify\Adapter\VerifyServices,History\Adapter\HistoryServices
andSitemap\Adapter\SitemapServicesof the packages (verify 0.3, history 0.3, sitemap 0.7 —conflictwith older
ones).indexnowkit.check.verifyis built by the package fromindexnowkit.verify_config(same text). - Requires
indexnowkit/verify ^0.3,indexnowkit/history ^0.3,indexnowkit/sitemap ^0.7when installed.
0.13.0
Added
- Symfony 8 (
^6.4 || ^7.0 || ^8.0on every symfony/* requirement; the README said "6.4 | 7 | 8" since 0.11 while
composer.json capped at 7 — the two agree now). CI runs the bundle on Symfony 8 with PHP 8.4 (ci:install:symfony8).
Changed
- Wiring follows core 0.12.0:
AttributeUrlResolver::fromConfig()andObjectChangeHandlertake theParamExtractor
as their third argument (the serviceindexnowkit.param_extractor, unchanged). - Requires
indexnowkit/core ^0.12.
0.12.0
Changed
Messenger\SubmitUrlsHandlerre-queues only the rejected URLs of a partially accepted batch, as a new
SubmitUrlsMessagewith the same id and the engine'sRetry-Afteras aDelayStamp; the whole message is thrown back
to the transport only when every URL was rejected. Before, aRetry-Afterlonger thandebounce.per_urlre-sent the
accepted URLs too.Messenger\MessengerDispatchersends one message perbatch.max_urlsURLs: a bulk import of 500 000 rows was one
message a transport with a size limit (SQS) rejected, and every URL was lost with one log line.checkgetsverify.transport(an applicationhttp.clientwith verify) and theverify.dispatchline comes from
Verify\Check\DispatchCheck.indexnowkit.verifyconfiguration:time_budget.- Requires
indexnowkit/core ^0.11,indexnowkit/console ^0.4; tests againstverify ^0.2,history ^0.2,sitemap ^0.6,doctrine ^0.8.
0.11.0
Added
indexnowkit.param_extractor(aliasIndexNowKit\Attribute\ParamExtractor): howparamsandwhenare read off
entities — the core DSL plus every service implementingAttribute\SubjectReaderInterface, which is autoconfigured with
the tagindexnowkit.subject_reader(a reader for objects the DSL cannot see into: a CMS record behindget_field()).
The resolver, the change handler, the facade andindexnow:explainshare it.
Changed
- Requires
indexnowkit/core ^0.10.
0.10.0
Added
indexnowkit/verifywiring (spec 17 §6.1). With the package installed theverifynode is the full tree
(enabled,redirect,non_canonical,origin_error,delay,timeout,max_redirects,max_batch,
robots_cache_ttl,user_agent;DependencyInjection\VerifyServices); withverify.enabled: true
indexnowkit.submitterandindexnowkit.command_submitter_factoryare decorated byVerifyingSubmitter/
VerifyingSubmitterFactory, sodispatch: sync, the Messenger handler, the profiler recorder and every command
verify;Submitter::classkeeps pointing at the plain submitter;indexnowkit.command_submitter_factory.unverified
is the plain factory (for the--no-verifyflag ofindexnow:sitemap). New services:indexnowkit.verify_config,
indexnowkit.verify.transport(verify.timeout,verify.user_agent, yourhttp.client),indexnowkit.verify.robots.
checklines:verify.installed(verify: installed, disabled (verify.enabled: false)/verify: enabled (…)),
verify.dispatch(warning withdispatch: sync),verify.sample. Without the package theverifyblock is
accepted and ignored (checksays so) and--sampleis an error naming the install line.indexnow:check --sample=<url>/--sample-class=<FQCN>[:<id>](repeatable;Check\SampleOptions,
Check\VerifySampleCheck,Check\EntitySampleroverindexnowkit.entity_loaderwith Doctrine).indexnow:config --jsonprints theverifysection when the package is installed.indexnowkit/historywiring (spec 17 §6.2). With the package installed thehistorynode is the full tree
(store,limit,key_prefix,pdo.dsn,pdo.service,pdo.table,retention_days;
DependencyInjection\HistoryServices); withhistory.store: psr16orpdothe package's store is
indexnowkit.submission_store(aliasindexnowkit.history.store), so the submitter, the Messenger handler, the
commands and the verify decorator record into it — an application service under that id still replaces it.
psr16uses the debounce pool's PSR-16 view (orcache.appwithdebounce.store: memory|none);pdotakes the
Doctrine connection ofpdo.service(a connection name or a service id,getNativeConnection()) or a PDO built
frompdo.dsn— never both — and does not create the table (see the package'sdocs/migrations.md). New services:
indexnowkit.history_config,indexnowkit.history.pdo/indexnowkit.history.cache,indexnowkit.forbidden_counter
(Retry\ForbiddenCounter),indexnowkit.console.history,indexnowkit.console.status. Commands
indexnow:history(--host,--status,--url,--since,--limit,--json,--purge[=days]) and
indexnow:status(--jsonper the package'sstatus.schema.json; the Messenger transport and bus as the
adapter facts); without the packageCommand\HistoryNotInstalledCommand/StatusNotInstalledCommandprint the
install line and exit 1.checklines:history.installed(without the package),history.store,
history.records.config --jsongets thehistorysection. The profiler panel lists the last 20 recorded
submissions ("Recent submissions";IndexNowDataCollectortakes an appended?SubmissionStoreInterface $history).IndexNowKitBundle(?bool $sitemapInstalled = null, ?bool $verifyInstalled = null, ?bool $historyInstalled = null)
(appended), the same onIndexNowKitConfigurationandIndexNowKitLoader; parameterindexnowkit.debounce.key_prefix;
DependencyInjection\TransportFactory::create(..., array $extraHeaders = []).
Changed
- Requires
indexnowkit/core ^0.9,indexnowkit/console ^0.3and (dev/suggest)indexnowkit/sitemap ^0.5,
indexnowkit/doctrine ^0.7,indexnowkit/verify ^0.1,indexnowkit/history ^0.1.
0.9.0
Changed
- Requires
indexnowkit/core ^0.8,indexnowkit/console ^0.2and (dev/suggest)indexnowkit/sitemap ^0.4,indexnowkit/doctrine ^0.6. Core 0.8 strips tracking parameters by default (normalizer.strip_tracking_params) and makesEqualsinparamsan error (see the core changelog).
Added
- The
indexnow:checklines of the bundle carry stable codes (core 0.8,check --json):wiring.messenger,
wiring.doctrine, plus the core'sdebounce.storeandsitemap.installed. Listed in the core'sdocs/check-codes.md. indexnow:check --json(the report as JSON, schemadocs/check.schema.jsonofindexnowkit/console),--strict
(warnings fail the command: put it in the deploy pipeline) and a repeatable--host(console 0.2).indexnow:key:generate --forcekeeps the replaced key asINDEXNOW_PREVIOUS_KEYand refuses a second rotation while
it is set;--no-previousand--yesdecide (console 0.2).- The 403 escalation of
Clientcounts in the PSR-16 view of thedebounce.storepool (core 0.8): onecritical
line per streak for every worker of the application; withmemory/nonethe counter stays per process. - Service
indexnowkit.submission_store(aliasSubmission\SubmissionStoreInterface,NullSubmissionStoreby default):
the store the submitter and the command submitters record everyResultin (core 0.8); replace it with your own or
with theindexnowkit/historypackage. - Configuration block
normalizer(strip_tracking_params,tracking_params,trailing_slash,sort_query): the
canonical form of every URL (core 0.8).indexnowkit.url_normalizeris now built byUrl\UrlNormalizerFactory
from the configuration; tracking parameters are stripped by default. indexnow:explain --jsonand thewhenvalues in the text output (console 0.2).indexnow:config(--json): the effective configuration with masked keys plus this adapter's own keys (console 0.2).
0.8.0
Changed
- Requires core 0.7:
Console\SubmitterFactory/Console\SubmitterFactoryInterfaceare now
IndexNowKit\Adapter\SubmitterFactory/IndexNowKit\Adapter\SubmitterFactoryInterface,Console\ResultSummaryis
IndexNowKit\Submission\ResultSummary. Application code that names them (a decorator ofindexnowkit.command_submitter_factory) changes theuseline; nothing else. - The test suite requires
indexnowkit/testing ^0.1(require-dev): the conformance kits and the H01–H05 assertions
moved there from the core (Testing\Conformance\KeyFileAssertions,CheckOutputAssertions,ReadmeAssertions). - Requires
indexnowkit/console ^0.1: the runners and definitions the commands are built on moved there from the core
with their FQCN unchanged (IndexNowKit\Console\*); Composer installs it with this package, nothing to do. - The sitemap predicate is an
IndexNowKit\Adapter\OptionalPackage(DependencyInjection\SitemapServices::package());
the bundle'ssitemapInstalledconstructor argument is unchanged.IndexNowKitLoader::SITEMAP_MISSING,
SITEMAP_MISSING_BLOCK_IGNOREDandCommand\SitemapNotInstalledCommand::MESSAGEare gone (the texts come from the
package object;DependencyInjection\*is wiring, not API). Thecheckline for a configured but ignoredsitemap
block is a warning now (it was ok).
Documentation
- README: the quick-start entity is
tests/Readme/Post.phpverbatim (completeuselines, thecategoryrelation the
via:rule reads, casts/defaults that make it run);ReadmeQuickstartTestcompares the README block with the file
and runs the entity through the test application against the FakeTransport. - README: "Notes for AI assistants" (package, minimal complete snippet, verification, pitfalls across the adapters);
ReadmeAiNotesTestkeeps it consistent with the commands and configuration keys. - README "Operations": the production checklist first, then monitoring rules, deleted pages, what not to submit,
multi-domain and troubleshooting. docs/troubleshooting.md: "Staging submitted its URLs" and "Duplicates with
memoryand several workers". docs/multi-domain.md: www and apex, hreflang clusters throughlocales: 'all'/
locale_hosts/via:. - Russian translation: docs/troubleshooting.ru.md (linked from README.ru.md).
homepagein composer.json points at the docs site (https://indexnowkit.github.io/php/).
0.7.0
Wave 0a of docs/spec/17 with core 0.6.0. indexnow:check fails in a non-production kernel environment when a key
is configured and dry_run is not set (a staging copy with the production key submits real URLs). A staging or
preview environment that submits on purpose says dry_run: false in its configuration and gets a warning instead.
The Flex recipe's dry_run: true in dev and test is unaffected.
Changed
- Requires
indexnowkit/core ^0.6;indexnowkit/doctrine ^0.4andindexnowkit/sitemap ^0.2when installed. - The
dry_runnode of the configuration has no default any more: an unsetdry_runstays unset so the core can tell
it from an explicitfalse. Readingdry_runfrom the processed configuration array (not fromConfig) now needs
?? false.
Added
debounceline inindexnow:checkthrough the coreDebounceStoreCheckand the bundle'sCheck\CacheProbe:
the configured pool is read through the samePsr16Cachethe store uses and named (debounce: 600s per URL, shared through cache pool "cache.app" (RedisAdapter)); an unusable pool is an error,memorya per-process
warning,noneandper_url: 0ok lines. Parity with the Laravel and Yii2 adapters.internetarchiveandamazonaccepted inengines(core 0.6).
Documentation
- docs/bc.md: configuration keys, command names and options, the service ids of
extending.md, the
container parameters, public classes and the route. README: "Why this over X", "Notification, not indexing",
the issues link, the badges in the family order.
0.6.1
Changed
- Internal refactor, no API change:
DependencyInjection\IndexNowKitLoader::load()is a sequence of private methods
per block of services (config, http, pipeline, urls, dispatch, facade, key file, profiler, checks, console,
doctrine). Service ids, arguments, tags, aliases and their registration order are unchanged; a new
ContainerShapeTestrecords them per configuration variant and fails on any difference.