NAME

Developer::Dashboard::PageStore - page persistence and token transport

SYNOPSIS

my $store = Developer::Dashboard::PageStore->new(paths => $paths);
my $page  = $store->load_saved_page('welcome');

DESCRIPTION

This module persists saved page instruction documents and handles transient encoded page transport. Its nav-fragment loader can return unchanged literal HTML without constructing a page object, while dynamic or structured nav files still use the canonical parser and renderer. The bounded in-memory cache uses high-resolution file identity and timestamps; it does not cache dynamic Template Toolkit output and each cache lookup checks that the file is still a regular file under a configured dashboards layer.

METHODS

new, page_file, save_page, load_saved_page, load_nav_fragment, load_transient_page, encode_page, editable_url, render_url, source_url, list_saved_pages, migrate_legacy_json_pages

Manage saved and transient pages.

PURPOSE

This module persists and lists saved dashboard pages under the runtime dashboards tree. It turns page IDs into concrete bookmark files, writes edited pages back to disk, and provides the saved-page inventory used by the browser and CLI page commands.

Canonical single-segment ASCII ids use a narrow validation fast path that avoids general prefix normalization and path splitting. Prefixed, nested, Unicode, whitespace-bearing, and reference ids still follow the full normalization and validation path; traversal checks and secure path containment remain in force for every file operation.

WHY IT EXISTS

It exists because saved bookmark storage needs one owner for file layout, ID validation, overwrite behavior, and page listing. That keeps the editor, CLI page helpers, and seeded-page bootstrap all talking to the same store semantics.

WHEN TO USE

Use this file when changing saved page file layout, bookmark ID handling, list ordering, or any feature that loads or saves pages under dashboards/.

HOW TO USE

Construct it with the active paths object, then use the page load/save/list methods instead of reading the dashboards directory directly. Let this module enforce the saved-page storage contract.

The web application uses load_nav_fragment for discovered nav/*.tt files. It supplies the scanned root so the store can avoid searching every layer, while the store still validates the root, checks the current file identity, and uses the secure no-follow open when content is not cached. A literal HTML fragment is returned as a body string; fragments with Template Toolkit directives and structured bookmark files are returned as page documents for normal request-time rendering.

WHAT USES IT

It is used by CLI page commands, web edit/source/render routes, seed bootstrap flows, and tests that verify saved bookmark persistence.

EXAMPLES

Example 1:

perl -Ilib -MDeveloper::Dashboard::PageStore -e 1

Do a direct compile-and-load check against the module from a source checkout.

Example 2:

prove -lv t/07-core-units.t t/21-refactor-coverage.t

Run the focused regression tests that most directly exercise this module's behavior.

Example 3:

HARNESS_PERL_SWITCHES=-MDevel::Cover prove -lr t

Recheck the module under the repository coverage gate rather than relying on a load-only probe.

Example 4:

prove -lr t

Put any module-level change back through the entire repository suite before release.

Example 5:

my $fragment = $store->load_nav_fragment('nav/status.tt', root => $dashboard_root);

Use this for a discovered layered nav file. A literal fragment returns { kind => 'literal', body => ... }; a dynamic or structured file returns { kind => 'page', page => $document }, and a file removed between inventory and load returns undef.