VERSION:
    File: PACKAGE-NOTES.txt
    Package archive: s3-cloudfront-indexer-html-package-v91.zip
    Top folder: s3-cloudfront-indexer-html-package-v91
    Package version: v91
    Build name: PACKAGE-NOTES.txt

CHANGE NOTE:
    Moves PUBLIC_DEBUG_DETAIL_LEVEL to the first lines of the viewer source.

What changed:

    The very top of lambda-edge-directory-browser/index.mjs now starts with:

        // EDIT THIS FIRST: public debug detail level. Allowed: "off", "safe", "verbose".
        const PUBLIC_DEBUG_DETAIL_LEVEL = "safe";

Why:

    You should not have to search through the file to change the debug detail
    level.

For your own sites, change:

        const PUBLIC_DEBUG_DETAIL_LEVEL = "safe";

to:

        const PUBLIC_DEBUG_DETAIL_LEVEL = "verbose";

Allowed values:

    "off"
    "safe"
    "verbose"

Kept from v87/v86:

    Safe public debug by default.
    Verbose operator debug by opt-in constant.
    ?debug=1 diagnostics.
    JSON attempt / accepted / fallback reporting.

What to deploy:

    Replace only:
        lambda-edge-directory-browser/index.mjs

    Then:
        Deploy
        Publish a numbered Lambda@Edge version
        Update CloudFront behavior associations
        Wait for CloudFront deployment

What not to change:

    Keep updater v67.
    Keep updater reserved concurrency at 1.

================================================================================

Deployment:
    Replace the s3-directory-index-updater Lambda code with:
        s3-directory-index-updater/index.mjs

Then set:
    Configuration → General configuration → Edit
    Timeout: 30 seconds
    Memory: 512 MB

================================================================================

Deployment:
    Replace the s3-directory-index-updater Lambda code with:
        s3-directory-index-updater/index.mjs

Manual test event:

{
  "Records": [
    {
      "s3": {
        "bucket": {
          "name": "www.8k.art"
        },
        "object": {
          "key": "beta/s3-cloudfront-indexer/index-updater-test.txt"
        }
      }
    }
  ]
}

Expected:
    beta/s3-cloudfront-indexer/.directory-index.json
    beta/.directory-index.json

================================================================================

Deployment:
    Replace the s3-directory-index-updater Lambda code with:
        s3-directory-index-updater/index.mjs

Then test again with:
        beta/index-updater-test.txt

Expected:
        beta/.directory-index.json

================================================================================

SUPER-FAST MODEL:

    Write-time work beats click-time work.

    S3 upload/delete event
        -> s3-directory-index-updater Lambda
        -> updates .directory-index.json in affected folders
        -> viewer Lambda reads one tiny JSON file
        -> folder dates + file dates + sizes render fast

FILES ADDED:

    s3-directory-index-updater/index.mjs
    policies/s3-directory-index-updater-policy-example.json

VIEWER FALLBACK:

    If .directory-index.json does not exist, the directory browser still falls
    back to live ListObjectsV2 so beginners can deploy without the updater first.

PRODUCTION TARGETS:

    8k.art
    8k.press
    define.com

================================================================================

Performance behavior:

    DIRECTORY_HTML_CACHE_SECONDS = 900
    DIRECTORY_HTML_SHARED_CACHE_SECONDS = 3600
    DIRECTORY_HTML_STALE_WHILE_REVALIDATE_SECONDS = 86400
    PREFETCH_FOLDER_PAGES_AFTER_RENDER = true
    MAX_FOLDER_PAGES_TO_PREFETCH = 12

What this improves:

    When a user opens /beta/, the browser can prefetch folder pages like
    /beta/_images/ in the background. When the user clicks, the next page is
    often already warm in browser/CloudFront cache.

Folder timestamps:

    Still use S3 folder marker metadata.
    Still non-blocking after first page render.
    No recursive scan.
    No direct-child scan.
    No folder size calculation.

================================================================================

CloudFront Function header file:

    cloudfront-function-headers/allow-all-cors-and-inline-text.js

Purpose:

    Optional companion function.
    Use it if you want source-code files to display inline instead of downloading.
    It is not required for directory listings themselves.

Removed:

    cloudfront-function-headers/allow-all-cors-and-inline-text.original.js

Reason:

    The backup/original file was confusing and could be deployed by mistake.

================================================================================

Important file updated:

    cloudfront-function-headers/allow-all-cors-and-inline-text.js

Purpose:

    This is the CloudFront Function response-header file. It controls whether
    source-code files display inline in the browser instead of downloading.

================================================================================

Performance behavior:

    1. Main directory page:
       ListObjectsV2 only, returns fast.

    2. Folder timestamp metadata:
       Loaded after the page displays using:
       ?directory-meta=folder-timestamps

    3. Folder timestamps:
       Still use only S3 folder marker metadata.
       No recursive scan.
       No direct-child scan.
       No folder size calculation.

This gives the best user experience:
    instant page display + folder timestamps shortly afterward.

================================================================================

Performance behavior:

    /beta
        redirects immediately to /beta/

    /beta/_images
        checks the S3 folder marker beta/_images/
        redirects if the marker exists

    /beta/README
        checks beta/README/
        does not redirect if that folder marker is missing

Caches:

    DIRECTORY_HTML_CACHE_SECONDS = 120
    LAMBDA_MEMORY_CACHE_SECONDS = 30
    FOLDER_MARKER_MEMORY_CACHE_SECONDS = 300

Folder timestamps remain enabled and use only S3 folder marker metadata.

No recursive scan is performed.
No direct-child scan is performed.
No folder size is calculated.

================================================================================

Speed fix:

    /beta/_images

now redirects immediately to:

    /beta/_images/

without first asking S3 whether the folder exists.

Folder timestamps remain enabled and use only S3 folder marker metadata.

No recursive scan is performed.
No direct-child scan is performed.
No folder size is calculated.
No artificial folder timestamp request limit is exposed.

================================================================================

Folder timestamp behavior:

    SHOW_FOLDER_LAST_MODIFIED = true

Meaning:

    Folder Last modified = LastModified from the S3 marker object, for example:

        beta/_docs/am/
        beta/_daily-builds/2026-05-18/

No recursive scan is performed.
No direct-child scan is performed.
No folder size is calculated.
No artificial "6 at a time" setting is exposed.

================================================================================

Plain-English folder timestamp setting:

    SHOW_FOLDER_LAST_MODIFIED = 6

Meaning:

    Lambda may ask S3 for up to 6 folder marker timestamps at the same time.

Beginner guidance:

    6 is a good default.
    Use 2 or 3 if pages feel slow.
    Use 6 or 8 if pages have many folders and still feel fast.

================================================================================

Folder timestamp behavior:

    SHOW_FOLDER_LAST_MODIFIED = true
    SHOW_FOLDER_LAST_MODIFIED = 6

Meaning:

    Folder Last modified = LastModified from the S3 marker object, for example:

        beta/_daily-builds/
        beta/s3-cloudfront-indexer/

No recursive scan is performed.
No direct-child scan is performed.
No folder size is calculated.

If no marker object exists, the folder timestamp is left blank.

================================================================================

Fast folder timestamp defaults:

    SHOW_FOLDER_LAST_MODIFIED = true
    FOLDER_LAST_MODIFIED_MODE = "marker"
    FOLDER_LAST_MODIFIED_RECURSIVE = false
    MAX_FOLDER_LAST_MODIFIED_KEYS = 1000
    SHOW_FOLDER_LAST_MODIFIED = 6

Why this is better:

    S3 CommonPrefixes do not include LastModified values, but many S3 folders
    have marker objects whose keys end in "/". HeadObject on that marker object
    is much cheaper than recursively listing all descendants.

Fallback options:

    FOLDER_LAST_MODIFIED_MODE = "direct"
        calculate newest direct child file timestamp

    FOLDER_LAST_MODIFIED_MODE = "recursive"
        calculate newest nested descendant timestamp; slower

================================================================================

Fast default:

    SHOW_FOLDER_LAST_MODIFIED = false

Reason:

    S3 folders are prefixes, not real directories. Calculating folder timestamps
    requires extra S3 list calls. On folders with many child folders, that can
    make navigation feel slow.

Optional experiment:

    SHOW_FOLDER_LAST_MODIFIED = true

If enabled:

    FOLDER_LAST_MODIFIED_RECURSIVE = false
        faster, only direct child files count

    FOLDER_LAST_MODIFIED_RECURSIVE = true
        slower, nested descendants count

================================================================================

Fast folder timestamp defaults:

    SHOW_FOLDER_LAST_MODIFIED = true
    FOLDER_LAST_MODIFIED_RECURSIVE = false
    MAX_FOLDER_LAST_MODIFIED_KEYS = 1000
    SHOW_FOLDER_LAST_MODIFIED = 3

Meaning:

    Folder Last modified = newest direct child file timestamp.

To scan all nested descendants instead, set:

    FOLDER_LAST_MODIFIED_RECURSIVE = true

================================================================================

Folder timestamp configuration is controlled in index.mjs / 8k-art-directory-browser.txt by:

    SHOW_FOLDER_LAST_MODIFIED
    FOLDER_LAST_MODIFIED_RECURSIVE
    MAX_FOLDER_LAST_MODIFIED_KEYS
    SHOW_FOLDER_LAST_MODIFIED

Default:

    SHOW_FOLDER_LAST_MODIFIED = true
    FOLDER_LAST_MODIFIED_RECURSIVE = true
    MAX_FOLDER_LAST_MODIFIED_KEYS = 5000
    SHOW_FOLDER_LAST_MODIFIED = 4

Meaning:

    Folder Last modified = newest file timestamp inside that S3 prefix.

================================================================================

Time zone configuration is controlled in index.mjs / 8k-art-directory-browser.txt by:

    DIRECTORY_LISTING_TIME_ZONE
    DIRECTORY_LISTING_LOCALE
    DIRECTORY_LISTING_TIME_ZONE_LABEL

Default:

    America/Los_Angeles

Example display:

    2026-05-18 03:24:12 PM PDT

================================================================================

Canonical configuration is now controlled in index.mjs / 8k-art-directory-browser.txt by:

    ENABLE_CANONICAL_URL_RULES
    CANONICAL_HOST_RULES
    STRIP_LEADING_WWW_FOR_UNKNOWN_HOSTS

ZIP filename and top folder intentionally match:

    s3-cloudfront-indexer-html-package-v91.zip
    s3-cloudfront-indexer-html-package-v91/

================================================================================

PACKAGE VERSION SUMMARY

Package file:
    s3-cloudfront-indexer-html-package-v91

Version:
    v10.2

Release date:
    2026-05-18

Rule used:
    Every text/code/html/json file in this package now carries its own version
    marker. The Build name inside each file matches that file's exact file name.

Files updated:
    8k-art-directory-browser.txt
    DEPLOYMENT-CHECKLIST.html
    LICENSE.txt
    PACKAGE-NOTES.txt
    QUICKSTART-FOR-BEGINNERS.html
    README.html
    TROUBLESHOOTING.html
    cloudfront-function-headers/allow-all-cors-and-inline-text.js
    lambda-edge-directory-browser/index.mjs
    public-landing-page-example.html
    policies/lambda-edge-trust-policy.json
    policies/s3-list-prefix-policy-example.json

================================================================================

S3 CloudFront Indexer HTML Package v10.1

Release date: 2026-05-18
Build name: nested-slash-html-v10.1

This package replaces the former Markdown documentation files with HTML files.

Version marker:
  The Lambda source now has a source-code-only version/date comment at the very
  top of the file. It is not visible in generated directory listings.

Important Lambda@Edge fix:
  Slashless nested folder URLs such as:
      https://8k.art/beta/s3-cloudfront-indexer
  redirect to:
      https://8k.art/beta/s3-cloudfront-indexer/

This keeps public links working without requiring visitors to type the trailing slash.

Previous package notes:
S3 CloudFront Indexer HTML Package v10

This package replaces the former Markdown documentation files with HTML files.

Converted files:
  README.md -> README.html
  QUICKSTART-FOR-BEGINNERS.md -> QUICKSTART-FOR-BEGINNERS.html
  DEPLOYMENT-CHECKLIST.md -> DEPLOYMENT-CHECKLIST.html
  TROUBLESHOOTING.md -> TROUBLESHOOTING.html

Important Lambda@Edge fix:
  Slashless nested folder URLs such as:
      https://8k.art/beta/s3-cloudfront-indexer
  now redirect to:
      https://8k.art/beta/s3-cloudfront-indexer/

This keeps public links working without requiring visitors to type the trailing slash.



v90 CHANGE NOTE
----------------
The S3 directory index updater now treats ObjectRemoved events as non-forcing updates.
Normal deleted files do not regenerate .directory-index.json files. Only deleted explicit
folder-marker objects, such as some/path/, update containing parent listings. This avoids
recreating stale index JSON files during S3 Browser folder rename operations.


v91 CHANGE NOTE
----------------
Corrects the delete handling rule after v90 overcorrected normal file deletion.

ObjectRemoved for a normal file now rebuilds the containing folder and parent
folders so deleted files disappear from .directory-index.json. If the containing
folder is now empty and has no explicit S3 folder-marker object, the updater
deletes that folder's .directory-index.json instead of writing an empty index
that would resurrect a stale renamed-away folder.

ObjectRemoved for an explicit folder marker deletes that folder's own
.directory-index.json if present, then updates only the containing parent
folders.
