From 091946dcc5c50685b2fde89fcdccaf39b9a19179 Mon Sep 17 00:00:00 2001 From: Tony Wu Date: Mon, 18 May 2026 18:00:24 +0100 Subject: [PATCH 1/3] feat(docs): capabilities lints + auto-generated capabilities index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a structural lint suite for V3 catalog frontmatter and a new auto-generated capabilities index page at /v3/capabilities, both backed by a shared `isV3CatalogEntry` predicate so the lint scope and emitter inclusion logic can't drift. bin/emitters.mjs (new module): - `isV3CatalogEntry(doc)` — shared predicate (catalog path patterns + `exclude_from_v3_catalog` opt-out); used by both emitters and the new lint so they share a single source of truth. - `emitV3LibraryCatalog` — moved from build-agent-indexes.mjs; behaviour unchanged (byte-identical output for existing 39-entry manifest; emits new optional `category` field when present). - `emitCapabilitiesIndex(docs)` — new emitter. Reads frontmatter `category:` and renders one section per ALLOWED_CATEGORIES value (data / identity / communications / media / native / commerce / integration / automation / analytics / meta). Sorted bullet list per section. Byte-stable across runs (no timestamps). - `ALLOWED_CATEGORIES` + Set — exported enum (10 values). - `parseListFrontmatter`, `deriveV3Package` — moved here too; re-exported from build-agent-indexes.mjs for test back-compat. bin/build-agent-indexes.mjs: - `validateCapabilities(docs)` — new strict-mode lint. Scope: V3 catalog entries only. Six rules: * empty/absent `capabilities[]` * non-lowercase token * duplicate token within one entry * token >40 chars * WARN: token starts with `[` (bracket-mismatch parse footgun) * `category:` not in ALLOWED_CATEGORIES_SET Plus a WARN-level missing-category rule so the field can land in staged commits without breaking CI mid-rollout. Errors carry `{ relPath, field, message, hint, docUrl }`; the runner prints hint + see-also URL on each failure so contributors know how to fix. - main(): wires `validateCapabilities` after `validateFrontmatter` and emits the new capabilities.md page after the catalog manifest. Frontmatter backfill across all 39 catalog entries: - 14 installable docs (`API/fliplet-*.md`) gain a `category:` value. - 25 ambient core docs (`API/core/*.md`) likewise. - Distribution: data 4, identity 6, communications 5, media 3, native 1, commerce 2, integration 2, automation 3, analytics 1, meta 12. The `meta` bucket trails because framework-level APIs (App, Apps, Encode, Env, Registry, Studio, Widget, Navigate, Screens, Misc, Error, Locale) are genuinely framework-level rather than residual. Tests: 127 (was 98). 29 new cases cover isV3CatalogEntry (5), validateCapabilities (10), emitCapabilitiesIndex (7), and the ALLOWED_CATEGORIES enum shape (3). Verification: - `node bin/build-agent-indexes.mjs --strict` passes - `npm run test:unit` → 127/127 pass - Catalog manifest byte-identical to pre-refactor (modulo timestamp + new optional `category` field on each entry) - Generated v3/capabilities.md is byte-stable across runs Co-Authored-By: Claude Opus 4.7 (1M context) --- .../agent-skills/fliplet-docs-index/SKILL.md | 1 + docs/.well-known/agent-skills/index.json | 2 +- docs/.well-known/llms-full.txt | 56 +++ docs/.well-known/llms-v3-libraries.json | 115 +++++-- docs/.well-known/llms.txt | 1 + docs/API/core/ai.md | 1 + docs/API/core/analytics.md | 1 + docs/API/core/api.md | 1 + docs/API/core/app-actions-v3.md | 1 + docs/API/core/app.md | 1 + docs/API/core/apps.md | 1 + docs/API/core/biometrics.md | 1 + docs/API/core/cache.md | 1 + docs/API/core/encode.md | 1 + docs/API/core/environment.md | 1 + docs/API/core/error.md | 1 + docs/API/core/hooks.md | 1 + docs/API/core/localization.md | 1 + docs/API/core/misc.md | 1 + docs/API/core/navigate.md | 1 + docs/API/core/navigator.md | 1 + docs/API/core/notifications.md | 1 + docs/API/core/organizations.md | 1 + docs/API/core/profile.md | 1 + docs/API/core/registry.md | 1 + docs/API/core/screens.md | 1 + docs/API/core/storage.md | 1 + docs/API/core/studio.md | 1 + docs/API/core/user.md | 1 + docs/API/core/widget.md | 1 + docs/API/fliplet-app-submissions.md | 1 + docs/API/fliplet-audio.md | 1 + docs/API/fliplet-barcode.md | 1 + docs/API/fliplet-chat.md | 1 + docs/API/fliplet-communicate.md | 1 + docs/API/fliplet-datasources.md | 1 + docs/API/fliplet-encryption.md | 1 + docs/API/fliplet-media.md | 1 + docs/API/fliplet-notifications.md | 1 + docs/API/fliplet-payments.md | 1 + docs/API/fliplet-security.md | 1 + docs/API/fliplet-session.md | 1 + docs/API/fliplet-socket.md | 1 + docs/API/fliplet-tokens.md | 1 + .../__tests__/build-agent-indexes.test.mjs | 324 ++++++++++++++++++ docs/bin/build-agent-indexes.mjs | 288 ++++++++++------ docs/bin/emitters.mjs | 256 ++++++++++++++ docs/v3/capabilities.md | 83 +++++ 48 files changed, 1020 insertions(+), 145 deletions(-) create mode 100644 docs/bin/emitters.mjs create mode 100644 docs/v3/capabilities.md diff --git a/docs/.well-known/agent-skills/fliplet-docs-index/SKILL.md b/docs/.well-known/agent-skills/fliplet-docs-index/SKILL.md index 17210dc1..3d2fab88 100644 --- a/docs/.well-known/agent-skills/fliplet-docs-index/SKILL.md +++ b/docs/.well-known/agent-skills/fliplet-docs-index/SKILL.md @@ -43,6 +43,7 @@ These docs don't belong to a single capability cluster — they are general onbo - [Fliplet open source resources](https://developers.fliplet.com/open-source.html): Where to find Fliplet's open-source code, pre-built app solutions, screen templates, community code examples, and developer documentation. - [Fliplet CLI quickstart](https://developers.fliplet.com/Quickstart.html): Install Node.js and the Fliplet CLI so you can develop and test components, themes, and menus on your machine. - [Upcoming and recently launched features](https://developers.fliplet.com/Upcoming.html): Tracker of Fliplet features recently shipped or in beta, linking to their developer documentation. +- [V3 capabilities](https://developers.fliplet.com/v3/capabilities.html): Auto-generated index of every Fliplet JS API surface available to V3 apps, grouped by capability category. - [Fliplet VS Code extension](https://developers.fliplet.com/VS-Code-Extension-Setup-Usage.html): Install, authenticate, and use the Fliplet VS Code extension to develop Fliplet apps directly from your editor. ## Full site index diff --git a/docs/.well-known/agent-skills/index.json b/docs/.well-known/agent-skills/index.json index 0bd9029f..42caa483 100644 --- a/docs/.well-known/agent-skills/index.json +++ b/docs/.well-known/agent-skills/index.json @@ -143,7 +143,7 @@ "index", "fallback" ], - "sha256": "c75e174343fbf7a78152ac5621c64c296f7576538b4214be5c07147c470c7201" + "sha256": "c3a6063139ab0508ed14aaed58299e4f99fbc00ae1a5151b7197bbdcb21f23bb" } ] } diff --git a/docs/.well-known/llms-full.txt b/docs/.well-known/llms-full.txt index 6e501cf1..d5ed55dc 100644 --- a/docs/.well-known/llms-full.txt +++ b/docs/.well-known/llms-full.txt @@ -37516,6 +37516,62 @@ C:>nslookup -type=TXT amazonses.com | find "v=spf1" --- +# V3 capabilities +URL: https://developers.fliplet.com/v3/capabilities.html + + + + +# V3 capabilities + +Every Fliplet JS API available to V3 apps, grouped by capability category. Each entry links to its full API reference. Ambient namespaces (preloaded into every app via `fliplet-core`) are marked **preloaded**; everything else is installable via `add_dependencies`. + +## Uncategorized + +_These entries are missing a `category:` value in frontmatter. See `docs/CONTRIBUTING.md` for how to assign one._ + +- [``Fliplet.Pages` and `Fliplet.Page``](https://developers.fliplet.com/API/core/screens.html) **(preloaded)** — List app screens, get the current screen's public URL, and build shareable URLs for any screen by ID. +- [``Fliplet.Storage` and `Fliplet.App.Storage``](https://developers.fliplet.com/API/core/storage.html) **(preloaded)** — Persist JSON-serializable values to device or browser storage, scoped globally or to the current app. +- [`App Actions V3`](https://developers.fliplet.com/API/core/app-actions-v3.html) **(preloaded)** — Write and run JavaScript code directly on the server or client to perform automations, scheduled tasks and on-demand operations. +- [`Fliplet common functions`](https://developers.fliplet.com/API/core/misc.html) **(preloaded)** — Utility helpers on the global `Fliplet` object: `Fliplet.compile()` for templating and `Fliplet.guid()` for unique IDs. +- [`Fliplet.AI`](https://developers.fliplet.com/API/core/ai.html) **(preloaded)** — Build AI features with `Fliplet.AI` — chat, completions, streaming, image generation, transcription, and embeddings via OpenAI or Google Gemini proxies. +- [`Fliplet.Analytics`](https://developers.fliplet.com/API/core/analytics.html) **(preloaded)** — Enable, disable, and check analytics tracking, and record custom app events and page views from JavaScript. +- [`Fliplet.API.request()`](https://developers.fliplet.com/API/core/api.html) **(preloaded)** — Make authenticated HTTP requests to Fliplet APIs with automatic URL construction, caching, offline queueing, and error handling. +- [`Fliplet.App`](https://developers.fliplet.com/API/core/app.html) **(preloaded)** — Retrieve the current app's public slug, build shareable screen URLs, and access app-level settings from JavaScript. +- [`Fliplet.App.Submissions`](https://developers.fliplet.com/API/fliplet-app-submissions.html) — Read App Store and Google Play submission metadata for the current Fliplet app — version, status, build numbers — via the fliplet-app-submissions package. +- [`Fliplet.App.Tokens`](https://developers.fliplet.com/API/fliplet-tokens.html) — Read the list of API tokens that authorise external services and backend integrations to call Fliplet APIs on behalf of an app. +- [`Fliplet.Apps`](https://developers.fliplet.com/API/core/apps.html) **(preloaded)** — List the Fliplet apps the current user can access, and filter between legacy V1 and modern V2 apps. +- [`Fliplet.Barcode`](https://developers.fliplet.com/API/fliplet-barcode.html) — Generate QR codes and 1D/2D barcodes on screen, and scan them from the device camera, via the fliplet-barcode package. +- [`Fliplet.Cache`](https://developers.fliplet.com/API/core/cache.html) **(preloaded)** — Run async operations once and memoize their results, with optional expiry and background refresh. +- [`Fliplet.Chat`](https://developers.fliplet.com/API/fliplet-chat.html) — Build one-to-one, group, and public-channel chat features. Fliplet.Chat owns the conversations and messages data sources internally — supply only the contacts list (who can chat with whom). +- [`Fliplet.Communicate`](https://developers.fliplet.com/API/fliplet-communicate.html) — Send email, SMS, push notifications, and share URLs from a Fliplet app using a single Communicate namespace. +- [`Fliplet.DataSources`](https://developers.fliplet.com/API/fliplet-datasources.html) — Connect to, query, insert, update, and delete records in Fliplet Data Sources from inside an app. All methods are promise-based. +- [`Fliplet.DataSources.Encryption`](https://developers.fliplet.com/API/fliplet-encryption.html) — Automatically encrypt and decrypt selected Data Source columns on-device by registering a private key and column list. +- [`Fliplet.Encode`](https://developers.fliplet.com/API/core/encode.html) **(preloaded)** — Encode strings as base64 and double-encode URL query parameters safely for transport. +- [`Fliplet.Env`](https://developers.fliplet.com/API/core/environment.html) **(preloaded)** — Read environment variables such as `appId`, `appName`, `mode`, and `apiUrl` from the current runtime. +- [`Fliplet.Hooks`](https://developers.fliplet.com/API/core/hooks.html) **(preloaded)** — Register callbacks that run before or after key app events (e.g. form submit), with sync or async Promise handlers. +- [`Fliplet.Locale`](https://developers.fliplet.com/API/core/localization.html) **(preloaded)** — Translate strings and format dates and numbers in Fliplet components via Fliplet.Locale, the T() shorthand, and translation.json files using i18next. +- [`Fliplet.Media`](https://developers.fliplet.com/API/fliplet-media.html) — Browse folders, upload and manage files, and download media to devices via the Fliplet Media namespace. +- [`Fliplet.Media.Audio`](https://developers.fliplet.com/API/fliplet-audio.html) — Play, pause, stop, and seek audio files on device or from a URL in Fliplet apps via the Audio namespace. +- [`Fliplet.Navigate`](https://developers.fliplet.com/API/core/navigate.html) **(preloaded)** — Navigate between app screens, open external URLs, pass query parameters, and handle back, home, and modal navigation via Fliplet.Navigate. +- [`Fliplet.Navigator`](https://developers.fliplet.com/API/core/navigator.html) **(preloaded)** — Detect online/offline state, listen for connectivity changes, and wait for the device to be ready. +- [`Fliplet.Navigator.Notifications`](https://developers.fliplet.com/API/core/notifications.html) **(preloaded)** — Check notification support, request permission, and send local device notifications from JavaScript. +- [`Fliplet.Notifications`](https://developers.fliplet.com/API/fliplet-notifications.html) — Read, send, and schedule in-app and push notifications in Fliplet apps, with support for scopes, read receipts, and badge counts. +- [`Fliplet.Organizations`](https://developers.fliplet.com/API/core/organizations.html) **(preloaded)** — List the current user's organizations and fetch audit logs with filters for type, date range, app, and session. +- [`Fliplet.parseError()`](https://developers.fliplet.com/API/core/error.html) **(preloaded)** — Turn any error response or object into a human-readable message by scanning common error properties. +- [`Fliplet.Payments`](https://developers.fliplet.com/API/fliplet-payments.html) — Accept Stripe payments and checkout in Fliplet apps via Fliplet.Payments, with a products data source and webhook-driven order tracking. +- [`Fliplet.Profile`](https://developers.fliplet.com/API/core/profile.html) **(preloaded)** — Read and write namespaced user profile attributes (email, name, company, phone) and fetch the device UUID. +- [`Fliplet.Registry`](https://developers.fliplet.com/API/core/registry.html) **(preloaded)** — Store and retrieve runtime values and functions by key so components can share state and helpers. +- [`Fliplet.Security`](https://developers.fliplet.com/API/fliplet-security.html) — Persist a per-app structured object to encrypted device storage via the fliplet-security package — for app-local secrets, device tokens, and per-user preferences. Distinct from fliplet-encryption (Da… +- [`Fliplet.Session`](https://developers.fliplet.com/API/fliplet-session.html) — Read, write, and clear the current user session — including cached offline sessions — for authentication state in Fliplet apps. +- [`Fliplet.Socket`](https://developers.fliplet.com/API/fliplet-socket.html) — Real-time WebSocket connection to the Fliplet API with auto-authentication, server URL discovery, and dev/prod transport fallback via the fliplet-socket package. +- [`Fliplet.Studio`](https://developers.fliplet.com/API/core/studio.html) **(preloaded)** — Emit events to Fliplet Studio and listen for events from it when building widget interfaces. +- [`Fliplet.User`](https://developers.fliplet.com/API/core/user.html) **(preloaded)** — Get and set the current user's auth token, profile details, and preferences, and sign the user out. +- [`Fliplet.User.Biometrics`](https://developers.fliplet.com/API/core/biometrics.html) **(preloaded)** — Check biometric availability and verify users with Face ID, Touch ID, or fingerprint inside native Fliplet apps. +- [`Fliplet.Widget`](https://developers.fliplet.com/API/core/widget.html) **(preloaded)** — Access widget instance IDs, settings, and data, and coordinate save and ready events between widget and interface. + +--- + # Fliplet VS Code extension URL: https://developers.fliplet.com/VS-Code-Extension-Setup-Usage.html diff --git a/docs/.well-known/llms-v3-libraries.json b/docs/.well-known/llms-v3-libraries.json index 4b76ebe3..039522f8 100644 --- a/docs/.well-known/llms-v3-libraries.json +++ b/docs/.well-known/llms-v3-libraries.json @@ -1,6 +1,6 @@ { "version": 1, - "generatedAt": "2026-05-16T15:54:05.264Z", + "generatedAt": "2026-05-18T16:59:34.786Z", "libraries": [ { "package": "fliplet-app-submissions", @@ -19,7 +19,8 @@ "app status", "native build", "app review" - ] + ], + "category": "commerce" }, { "package": "fliplet-audio", @@ -38,7 +39,8 @@ "mp3", "streaming audio", "audio playback" - ] + ], + "category": "media" }, { "package": "fliplet-barcode", @@ -59,7 +61,8 @@ "upc", "1d barcode", "2d barcode" - ] + ], + "category": "media" }, { "package": "fliplet-chat", @@ -83,6 +86,7 @@ "typing indicator", "message history" ], + "category": "communications", "notes": "Owns the conversations and messages data sources internally — never propose `Conversations`, `Messages`, `Typing Status`, or similar data sources of your own. The only data source you design is the `contacts` list passed to `Fliplet.Chat.connect()` (who can chat with whom)." }, { @@ -106,7 +110,8 @@ "mailgun", "compose email", "mailto" - ] + ], + "category": "communications" }, { "package": "fliplet-datasources", @@ -132,7 +137,8 @@ "subscribe", "real-time records", "bulk operations" - ] + ], + "category": "data" }, { "package": "fliplet-encryption", @@ -152,6 +158,7 @@ "on-device encryption", "pgp" ], + "category": "data", "notes": "Installing this package transparently encrypts and decrypts the configured columns on every Fliplet.DataSources find/insert/update call — only install when you intend to encrypt, otherwise it will silently alter data-source operations." }, { @@ -175,7 +182,8 @@ "attachment", "browse files", "search files" - ] + ], + "category": "media" }, { "package": "fliplet-notifications", @@ -193,7 +201,8 @@ "read receipt", "notifications inbox", "broadcast notification" - ] + ], + "category": "communications" }, { "package": "fliplet-payments", @@ -219,7 +228,8 @@ "product", "cart", "donation" - ] + ], + "category": "commerce" }, { "package": "fliplet-security", @@ -237,7 +247,8 @@ "per-user storage", "app secret", "sensitive value storage" - ] + ], + "category": "identity" }, { "package": "fliplet-session", @@ -256,7 +267,8 @@ "passport", "sso session", "connected account" - ] + ], + "category": "identity" }, { "package": "fliplet-socket", @@ -278,7 +290,8 @@ "server push", "live data", "socket.io" - ] + ], + "category": "communications" }, { "package": "fliplet-tokens", @@ -297,7 +310,8 @@ "bearer token", "external service token", "app token" - ] + ], + "category": "integration" }, { "package": "fliplet-core", @@ -315,7 +329,8 @@ "share screen", "screen id", "public screen url" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -336,7 +351,8 @@ "namespaced storage", "json storage", "local storage" - ] + ], + "category": "data" }, { "package": "fliplet-core", @@ -357,7 +373,8 @@ "background job", "action trigger", "webhook handler" - ] + ], + "category": "automation" }, { "package": "fliplet-core", @@ -376,7 +393,8 @@ "unique id", "string templating", "generate id" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -401,7 +419,8 @@ "vision", "multimodal", "ai assistant" - ] + ], + "category": "automation" }, { "package": "fliplet-core", @@ -418,7 +437,8 @@ "app analytics", "system analytics", "event tracking" - ] + ], + "category": "analytics" }, { "package": "fliplet-core", @@ -435,7 +455,8 @@ "offline queue", "request cache", "fliplet api" - ] + ], + "category": "integration" }, { "package": "fliplet-core", @@ -455,7 +476,8 @@ "device orientation", "app metadata", "app config" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -471,7 +493,8 @@ "v2 apps", "available apps", "accessible apps" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -489,7 +512,8 @@ "background refresh", "deduplicate", "cached promise" - ] + ], + "category": "data" }, { "package": "fliplet-core", @@ -506,7 +530,8 @@ "decode", "base64 encode", "double encode" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -525,7 +550,8 @@ "current app", "viewer mode", "preview mode" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -543,7 +569,8 @@ "before save", "form submit hook", "async hook" - ] + ], + "category": "automation" }, { "package": "fliplet-core", @@ -563,7 +590,8 @@ "i18next", "multilingual", "internationalization" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -590,7 +618,8 @@ "navigate to screen", "confirm dialog", "prompt dialog" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -608,7 +637,8 @@ "network change", "online status", "offline detection" - ] + ], + "category": "native" }, { "package": "fliplet-core", @@ -624,7 +654,8 @@ "scheduled local notification", "native notification", "browser notification" - ] + ], + "category": "communications" }, { "package": "fliplet-core", @@ -642,7 +673,8 @@ "org list", "audit", "compliance log" - ] + ], + "category": "identity" }, { "package": "fliplet-core", @@ -658,7 +690,8 @@ "human-readable error", "error handling", "error response" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -678,7 +711,8 @@ "user attribute", "profile attribute", "namespaced profile" - ] + ], + "category": "identity" }, { "package": "fliplet-core", @@ -695,7 +729,8 @@ "global helpers", "function registry", "runtime key-value" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -712,7 +747,8 @@ "listen to studio events", "message studio", "studio bridge" - ] + ], + "category": "meta" }, { "package": "fliplet-core", @@ -732,7 +768,8 @@ "user profile", "login", "authentication" - ] + ], + "category": "identity" }, { "package": "fliplet-core", @@ -750,7 +787,8 @@ "native auth", "device authentication", "biometric verify" - ] + ], + "category": "identity" }, { "package": "fliplet-core", @@ -769,7 +807,8 @@ "widget interface", "namespaced widget", "component instance" - ] + ], + "category": "meta" } ] } diff --git a/docs/.well-known/llms.txt b/docs/.well-known/llms.txt index a316b36f..93afa0b2 100644 --- a/docs/.well-known/llms.txt +++ b/docs/.well-known/llms.txt @@ -226,4 +226,5 @@ - [UI guidelines for component settings (interface)](https://developers.fliplet.com/UI-guidelines-interface.html): Recommended Bootstrap-based styles for buttons, forms, and typography in a Fliplet component's Studio settings interface. - [Upcoming and recently launched features](https://developers.fliplet.com/Upcoming.html): Tracker of Fliplet features recently shipped or in beta, linking to their developer documentation. - [Fliplet URLs and IP addresses](https://developers.fliplet.com/URLs-and-IP-Addresses.html): Domains and ports that Fliplet Studio, web apps, native apps, and the Data Integration Service need reachable through a corporate firewall. +- [V3 capabilities](https://developers.fliplet.com/v3/capabilities.html): Auto-generated index of every Fliplet JS API surface available to V3 apps, grouped by capability category. - [Fliplet VS Code extension](https://developers.fliplet.com/VS-Code-Extension-Setup-Usage.html): Install, authenticate, and use the Fliplet VS Code extension to develop Fliplet apps directly from your editor. diff --git a/docs/API/core/ai.md b/docs/API/core/ai.md index 9ee8d395..3673f6ca 100644 --- a/docs/API/core/ai.md +++ b/docs/API/core/ai.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core] v3_relevant: true deprecated: false +category: automation capabilities: [ai, llm, openai, gemini, gpt, chat completion, image generation, dall-e, transcription, whisper, embeddings, streaming completion, vision, multimodal, ai assistant] --- # `Fliplet.AI` diff --git a/docs/API/core/analytics.md b/docs/API/core/analytics.md index dcae1b9e..861adc9b 100644 --- a/docs/API/core/analytics.md +++ b/docs/API/core/analytics.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, analytics] v3_relevant: true deprecated: false +category: analytics capabilities: [analytics, tracking, page view, custom event, app analytics, system analytics, event tracking] --- # `Fliplet.Analytics` diff --git a/docs/API/core/api.md b/docs/API/core/api.md index 748b541f..bdb7ab03 100644 --- a/docs/API/core/api.md +++ b/docs/API/core/api.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core] v3_relevant: true deprecated: false +category: integration capabilities: [api request, http request, fetch, authenticated request, offline queue, request cache, fliplet api] --- # `Fliplet.API.request()` diff --git a/docs/API/core/app-actions-v3.md b/docs/API/core/app-actions-v3.md index 92f70a1c..40ba0058 100644 --- a/docs/API/core/app-actions-v3.md +++ b/docs/API/core/app-actions-v3.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, app, actions] v3_relevant: true deprecated: false +category: automation capabilities: [app action, server function, cloud function, automation, scheduled task, cron, on-demand task, server-side javascript, background job, action trigger, webhook handler] --- diff --git a/docs/API/core/app.md b/docs/API/core/app.md index 516d1c5b..cd4b784e 100644 --- a/docs/API/core/app.md +++ b/docs/API/core/app.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, app] v3_relevant: true deprecated: false +category: meta capabilities: [app slug, public url, app settings, app logs, screen url, share url, preview mode, device orientation, app metadata, app config] --- # `Fliplet.App` diff --git a/docs/API/core/apps.md b/docs/API/core/apps.md index 0bb261e6..68837083 100644 --- a/docs/API/core/apps.md +++ b/docs/API/core/apps.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, apps] v3_relevant: true deprecated: false +category: meta capabilities: [app list, list apps, v1 apps, v2 apps, available apps, accessible apps] --- # `Fliplet.Apps` diff --git a/docs/API/core/biometrics.md b/docs/API/core/biometrics.md index f92798bc..4fab831f 100644 --- a/docs/API/core/biometrics.md +++ b/docs/API/core/biometrics.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, biometrics] v3_relevant: true deprecated: false +category: identity capabilities: [biometrics, face id, touch id, fingerprint, biometric authentication, native auth, device authentication, biometric verify] --- # `Fliplet.User.Biometrics` diff --git a/docs/API/core/cache.md b/docs/API/core/cache.md index d250b560..73f5bf75 100644 --- a/docs/API/core/cache.md +++ b/docs/API/core/cache.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, cache] v3_relevant: true deprecated: false +category: data capabilities: [cache, memoize, async cache, ttl, expiry, background refresh, deduplicate, cached promise] --- # `Fliplet.Cache` diff --git a/docs/API/core/encode.md b/docs/API/core/encode.md index 65b1beff..93418a70 100644 --- a/docs/API/core/encode.md +++ b/docs/API/core/encode.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, encode] v3_relevant: true deprecated: false +category: meta capabilities: [base64, encode, url encode, query parameter encode, decode, base64 encode, double encode] --- # `Fliplet.Encode` diff --git a/docs/API/core/environment.md b/docs/API/core/environment.md index 5bf5c8b2..2747af4f 100644 --- a/docs/API/core/environment.md +++ b/docs/API/core/environment.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, environment] v3_relevant: true deprecated: false +category: meta capabilities: [environment, env vars, app id, api url, runtime mode, dependencies, current app, viewer mode, preview mode] --- # `Fliplet.Env` diff --git a/docs/API/core/error.md b/docs/API/core/error.md index 26ebf670..ed3020c3 100644 --- a/docs/API/core/error.md +++ b/docs/API/core/error.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, error] v3_relevant: true deprecated: false +category: meta capabilities: [error, parse error, error message, human-readable error, error handling, error response] --- # `Fliplet.parseError()` diff --git a/docs/API/core/hooks.md b/docs/API/core/hooks.md index a6cd1ab0..6e75ec58 100644 --- a/docs/API/core/hooks.md +++ b/docs/API/core/hooks.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, hooks] v3_relevant: true deprecated: false +category: automation capabilities: [hook, before hook, after hook, lifecycle, event callback, before save, form submit hook, async hook] --- # `Fliplet.Hooks` diff --git a/docs/API/core/localization.md b/docs/API/core/localization.md index ecc7c4f4..4044f8ed 100644 --- a/docs/API/core/localization.md +++ b/docs/API/core/localization.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, localization] v3_relevant: true deprecated: false +category: meta capabilities: [localization, i18n, translation, translate string, locale, date format, number format, i18next, multilingual, internationalization] --- diff --git a/docs/API/core/misc.md b/docs/API/core/misc.md index 751ad51c..7fbe6ab6 100644 --- a/docs/API/core/misc.md +++ b/docs/API/core/misc.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, misc] v3_relevant: true deprecated: false +category: meta capabilities: [compile, handlebars, template, mustache, guid, uuid, unique id, string templating, generate id] --- # Fliplet common functions diff --git a/docs/API/core/navigate.md b/docs/API/core/navigate.md index 79cadb81..96ed4c8d 100644 --- a/docs/API/core/navigate.md +++ b/docs/API/core/navigate.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, navigate] v3_relevant: true deprecated: false +category: meta capabilities: [navigation, navigate, link, open screen, open url, external url, query parameter, back, home, exit app, popup, gallery, play video, log out, navigate to screen, confirm dialog, prompt dialog] --- diff --git a/docs/API/core/navigator.md b/docs/API/core/navigator.md index 7282588c..58897235 100644 --- a/docs/API/core/navigator.md +++ b/docs/API/core/navigator.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, navigator] v3_relevant: true deprecated: false +category: native capabilities: [online, offline, connectivity, network state, device ready, network change, online status, offline detection] --- # `Fliplet.Navigator` diff --git a/docs/API/core/notifications.md b/docs/API/core/notifications.md index e78a0f8f..315c3df5 100644 --- a/docs/API/core/notifications.md +++ b/docs/API/core/notifications.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, notifications] v3_relevant: true deprecated: false +category: communications capabilities: [local notification, device notification, notification permission, scheduled local notification, native notification, browser notification] --- # `Fliplet.Navigator.Notifications` diff --git a/docs/API/core/organizations.md b/docs/API/core/organizations.md index f3b4f99b..ddf495b1 100644 --- a/docs/API/core/organizations.md +++ b/docs/API/core/organizations.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, organizations] v3_relevant: true deprecated: false +category: identity capabilities: [organization, org, audit log, org settings, policies, org list, audit, compliance log] --- # `Fliplet.Organizations` diff --git a/docs/API/core/profile.md b/docs/API/core/profile.md index e6cdd4df..f6feec50 100644 --- a/docs/API/core/profile.md +++ b/docs/API/core/profile.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, profile] v3_relevant: true deprecated: false +category: identity capabilities: [profile, user profile, email, name, company, phone, device uuid, user attribute, profile attribute, namespaced profile] --- # `Fliplet.Profile` diff --git a/docs/API/core/registry.md b/docs/API/core/registry.md index 8e8a5ffc..8fec0eb7 100644 --- a/docs/API/core/registry.md +++ b/docs/API/core/registry.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, registry] v3_relevant: true deprecated: false +category: meta capabilities: [registry, runtime registry, component shared state, runtime helpers, global helpers, function registry, runtime key-value] --- # `Fliplet.Registry` diff --git a/docs/API/core/screens.md b/docs/API/core/screens.md index 2dc38599..30a8ffe4 100644 --- a/docs/API/core/screens.md +++ b/docs/API/core/screens.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, screens] v3_relevant: true deprecated: false +category: meta capabilities: [screen, page, list screens, current screen, screen url, share screen, screen id, public screen url] --- # `Fliplet.Pages` and `Fliplet.Page` diff --git a/docs/API/core/storage.md b/docs/API/core/storage.md index a719caf0..c3ef9d5a 100644 --- a/docs/API/core/storage.md +++ b/docs/API/core/storage.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, storage] v3_relevant: true deprecated: false +category: data capabilities: [storage, persistence, key-value, app storage, device storage, browser storage, preferences, settings, namespaced storage, json storage, local storage] --- # `Fliplet.Storage` and `Fliplet.App.Storage` diff --git a/docs/API/core/studio.md b/docs/API/core/studio.md index 0041ce5d..b9bedc60 100644 --- a/docs/API/core/studio.md +++ b/docs/API/core/studio.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, studio] v3_relevant: true deprecated: false +category: meta capabilities: [studio events, widget interface, studio communication, send event to studio, listen to studio events, message studio, studio bridge] --- # `Fliplet.Studio` diff --git a/docs/API/core/user.md b/docs/API/core/user.md index fc736e5b..9702355f 100644 --- a/docs/API/core/user.md +++ b/docs/API/core/user.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, user] v3_relevant: true deprecated: false +category: identity capabilities: [user, current user, auth token, signin, sign out, log out, user attributes, user profile, login, authentication] --- # `Fliplet.User` diff --git a/docs/API/core/widget.md b/docs/API/core/widget.md index 846a1b6b..cc2f8884 100644 --- a/docs/API/core/widget.md +++ b/docs/API/core/widget.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, core, widget] v3_relevant: true deprecated: false +category: meta capabilities: [widget, widget instance, widget settings, widget data, save event, ready event, widget interface, namespaced widget, component instance] --- # `Fliplet.Widget` diff --git a/docs/API/fliplet-app-submissions.md b/docs/API/fliplet-app-submissions.md index 91175fe3..504aae6d 100644 --- a/docs/API/fliplet-app-submissions.md +++ b/docs/API/fliplet-app-submissions.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, app-store, submissions, publishing] v3_relevant: true deprecated: false +category: commerce capabilities: [app store, google play, submission, app version, build number, store metadata, app status, native build, app review] --- # `Fliplet.App.Submissions` diff --git a/docs/API/fliplet-audio.md b/docs/API/fliplet-audio.md index 840c1c87..13878292 100644 --- a/docs/API/fliplet-audio.md +++ b/docs/API/fliplet-audio.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, audio] v3_relevant: true deprecated: false +category: media capabilities: [audio, sound, play audio, pause audio, music, podcast, mp3, streaming audio, audio playback] --- # `Fliplet.Media.Audio` diff --git a/docs/API/fliplet-barcode.md b/docs/API/fliplet-barcode.md index aaa6bbb1..a85e3a0f 100644 --- a/docs/API/fliplet-barcode.md +++ b/docs/API/fliplet-barcode.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, barcode] v3_relevant: true deprecated: false +category: media capabilities: [barcode, qr code, qrcode, scan, scanner, camera scan, generate barcode, ean, upc, 1d barcode, 2d barcode] --- # `Fliplet.Barcode` diff --git a/docs/API/fliplet-chat.md b/docs/API/fliplet-chat.md index 7f59e8f8..992a922b 100644 --- a/docs/API/fliplet-chat.md +++ b/docs/API/fliplet-chat.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, chat, messaging, realtime, conversations] v3_relevant: true deprecated: false +category: communications capabilities: [chat, conversation, group chat, public channel, direct message, dm, im, messaging, real-time chat, contacts, chat room, typing indicator, message history] notes: "Owns the conversations and messages data sources internally — never propose `Conversations`, `Messages`, `Typing Status`, or similar data sources of your own. The only data source you design is the `contacts` list passed to `Fliplet.Chat.connect()` (who can chat with whom)." --- diff --git a/docs/API/fliplet-communicate.md b/docs/API/fliplet-communicate.md index 779efc39..f97983f3 100644 --- a/docs/API/fliplet-communicate.md +++ b/docs/API/fliplet-communicate.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, communicate] v3_relevant: true deprecated: false +category: communications capabilities: [email, send email, sms, send sms, batch email, batch sms, share url, share link, sendgrid, twilio, mailgun, compose email, mailto] --- # `Fliplet.Communicate` diff --git a/docs/API/fliplet-datasources.md b/docs/API/fliplet-datasources.md index f6a649d5..2d83c6de 100644 --- a/docs/API/fliplet-datasources.md +++ b/docs/API/fliplet-datasources.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, datasources] v3_relevant: true deprecated: false +category: data capabilities: [data source, datasource, query, insert, update, delete, crud, records, table, database, pagination, sort, filter, subscribe, real-time records, bulk operations] --- # `Fliplet.DataSources` diff --git a/docs/API/fliplet-encryption.md b/docs/API/fliplet-encryption.md index b4dec1fb..c857b30a 100644 --- a/docs/API/fliplet-encryption.md +++ b/docs/API/fliplet-encryption.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, encryption] v3_relevant: true deprecated: false +category: data capabilities: [encrypt, encryption, decrypt, column encryption, private key, data source column, secure column, on-device encryption, pgp] notes: "Installing this package transparently encrypts and decrypts the configured columns on every Fliplet.DataSources find/insert/update call — only install when you intend to encrypt, otherwise it will silently alter data-source operations." --- diff --git a/docs/API/fliplet-media.md b/docs/API/fliplet-media.md index 50763bbd..7c58ad0c 100644 --- a/docs/API/fliplet-media.md +++ b/docs/API/fliplet-media.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, media] v3_relevant: true deprecated: false +category: media capabilities: [file, folder, upload, download, media, image, picture, photo, file storage, file manager, attachment, browse files, search files] --- # `Fliplet.Media` diff --git a/docs/API/fliplet-notifications.md b/docs/API/fliplet-notifications.md index c4a2d78e..1df29a5f 100644 --- a/docs/API/fliplet-notifications.md +++ b/docs/API/fliplet-notifications.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, notifications] v3_relevant: true deprecated: false +category: communications capabilities: [notification, push notification, in-app notification, scheduled notification, badge count, read receipt, notifications inbox, broadcast notification] --- # `Fliplet.Notifications` diff --git a/docs/API/fliplet-payments.md b/docs/API/fliplet-payments.md index 678c3f74..d3074a93 100644 --- a/docs/API/fliplet-payments.md +++ b/docs/API/fliplet-payments.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, payments] v3_relevant: true deprecated: false +category: commerce capabilities: [payments, stripe, checkout, subscription, recurring billing, billing, refund, webhook, price id, customer portal, payment intent, ecommerce, order, product, cart, donation] --- diff --git a/docs/API/fliplet-security.md b/docs/API/fliplet-security.md index e2213dbf..11a94802 100644 --- a/docs/API/fliplet-security.md +++ b/docs/API/fliplet-security.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, security, encryption, storage] v3_relevant: true deprecated: false +category: identity capabilities: [encrypted device storage, secure storage, device token, secret, credential storage, per-user storage, app secret, sensitive value storage] --- # `Fliplet.Security` diff --git a/docs/API/fliplet-session.md b/docs/API/fliplet-session.md index 86fd72f6..41f3a2cf 100644 --- a/docs/API/fliplet-session.md +++ b/docs/API/fliplet-session.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, session] v3_relevant: true deprecated: false +category: identity capabilities: [session, auth session, login state, current user session, offline session, signin state, passport, sso session, connected account] --- # `Fliplet.Session` diff --git a/docs/API/fliplet-socket.md b/docs/API/fliplet-socket.md index 0581c400..89b0a0d8 100644 --- a/docs/API/fliplet-socket.md +++ b/docs/API/fliplet-socket.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, socket, websocket, realtime, events] v3_relevant: true deprecated: false +category: communications capabilities: [websocket, socket, real-time, realtime, live updates, presence, broadcast, room, event stream, server push, live data, socket.io] --- # `Fliplet.Socket` diff --git a/docs/API/fliplet-tokens.md b/docs/API/fliplet-tokens.md index 21c48b62..e97fdb8b 100644 --- a/docs/API/fliplet-tokens.md +++ b/docs/API/fliplet-tokens.md @@ -5,6 +5,7 @@ type: api-reference tags: [js-api, tokens, api-keys, integrations] v3_relevant: true deprecated: false +category: integration capabilities: [api token, access token, backend integration, server-to-server, machine-to-machine, jwt, bearer token, external service token, app token] --- diff --git a/docs/bin/__tests__/build-agent-indexes.test.mjs b/docs/bin/__tests__/build-agent-indexes.test.mjs index 63ca4d3b..e2e69ee0 100644 --- a/docs/bin/__tests__/build-agent-indexes.test.mjs +++ b/docs/bin/__tests__/build-agent-indexes.test.mjs @@ -19,10 +19,15 @@ import { emitSkillMd, emitMcpServerCard, emitV3LibraryCatalog, + emitCapabilitiesIndex, deriveV3Package, parseListFrontmatter, + isV3CatalogEntry, + ALLOWED_CATEGORIES, + ALLOWED_CATEGORIES_SET, assignToCluster, validateFrontmatter, + validateCapabilities, ALLOWED_TYPES, CLUSTERS, collectDocs, @@ -831,4 +836,323 @@ describe('emitV3LibraryCatalog', () => { ['fliplet-a', 'fliplet-b'], ); }); + + it('emits category when present in frontmatter', () => { + const docs = [ + makeDoc('API/fliplet-payments.md', { category: 'commerce' }), + ]; + const catalog = emitV3LibraryCatalog(docs); + assert.equal(catalog.libraries[0].category, 'commerce'); + }); + + it('omits category when frontmatter is empty', () => { + const docs = [makeDoc('API/fliplet-payments.md', {})]; + const catalog = emitV3LibraryCatalog(docs); + assert.equal(catalog.libraries[0].category, undefined); + }); +}); + +describe('isV3CatalogEntry', () => { + function doc(relPath, fm = {}) { + return { relPath, fm }; + } + + it('returns true for installable fliplet-* docs', () => { + assert.equal(isV3CatalogEntry(doc('API/fliplet-barcode.md')), true); + assert.equal(isV3CatalogEntry(doc('API/fliplet-payments.md')), true); + }); + + it('returns true for ambient core/* docs', () => { + assert.equal(isV3CatalogEntry(doc('API/core/storage.md')), true); + assert.equal(isV3CatalogEntry(doc('API/core/ai.md')), true); + }); + + it('returns false for paths outside the catalog', () => { + assert.equal(isV3CatalogEntry(doc('REST-API/Apps.md')), false); + assert.equal(isV3CatalogEntry(doc('Building-themes.md')), false); + assert.equal(isV3CatalogEntry(doc('API/components/forms.md')), false); + assert.equal(isV3CatalogEntry(doc('API/datasources/queries.md')), false); + }); + + it('returns false when frontmatter has exclude_from_v3_catalog: true', () => { + assert.equal( + isV3CatalogEntry(doc('API/fliplet-ui.md', { exclude_from_v3_catalog: 'true' })), + false, + ); + assert.equal( + isV3CatalogEntry(doc('API/core/modal.md', { exclude_from_v3_catalog: 'true' })), + false, + ); + }); + + it('honours the exclude flag only as the literal string "true"', () => { + assert.equal( + isV3CatalogEntry(doc('API/fliplet-a.md', { exclude_from_v3_catalog: 'false' })), + true, + ); + assert.equal( + isV3CatalogEntry(doc('API/fliplet-a.md', { exclude_from_v3_catalog: '' })), + true, + ); + }); +}); + +describe('validateCapabilities', () => { + function entry(relPath, fm = {}) { + return { relPath, fm }; + } + + it('returns no errors for a well-formed catalog entry', () => { + const docs = [ + entry('API/fliplet-payments.md', { + capabilities: '[stripe, checkout, subscription]', + category: 'commerce', + }), + ]; + assert.deepEqual(validateCapabilities(docs), []); + }); + + it('skips docs outside the V3 catalog (no false positives)', () => { + const docs = [ + entry('REST-API/Apps.md', {}), + entry('Building-themes.md', {}), + entry('API/components/forms.md', {}), + entry('API/fliplet-x.md', { exclude_from_v3_catalog: 'true' }), + ]; + assert.deepEqual(validateCapabilities(docs), []); + }); + + it('flags missing capabilities[] on a catalog entry', () => { + const docs = [entry('API/fliplet-payments.md', { category: 'commerce' })]; + const errors = validateCapabilities(docs); + const capError = errors.find((e) => e.field === 'capabilities'); + assert.ok(capError); + assert.match(capError.message, /empty or missing/); + assert.ok(capError.hint); + assert.ok(capError.docUrl); + }); + + it('flags empty capabilities[] (e.g. `[]`)', () => { + const docs = [entry('API/fliplet-payments.md', { capabilities: '[]', category: 'commerce' })]; + const errors = validateCapabilities(docs); + assert.ok(errors.find((e) => e.field === 'capabilities')); + }); + + it('flags non-lowercase tokens', () => { + const docs = [ + entry('API/fliplet-payments.md', { + capabilities: '[Stripe, checkout]', + category: 'commerce', + }), + ]; + const errors = validateCapabilities(docs); + const e = errors.find((x) => x.message.includes('Stripe')); + assert.ok(e); + assert.match(e.message, /uppercase/); + }); + + it('flags tokens >40 chars', () => { + const long = 'a-very-very-very-very-very-very-very-long-token'; + const docs = [ + entry('API/fliplet-payments.md', { + capabilities: `[${long}]`, + category: 'commerce', + }), + ]; + const errors = validateCapabilities(docs); + assert.ok(errors.find((e) => e.message.includes('>40 chars'))); + }); + + it('flags duplicate tokens within one entry', () => { + const docs = [ + entry('API/fliplet-payments.md', { + capabilities: '[stripe, checkout, stripe]', + category: 'commerce', + }), + ]; + const errors = validateCapabilities(docs); + assert.ok(errors.find((e) => e.message.includes('duplicate'))); + }); + + it('warns when a token starts with `[` (bracket-mismatch footgun)', () => { + // `capabilities: [stripe, checkout` (missing `]`) parses as + // `['[stripe', 'checkout']` — the leading `[` token signals this. + const docs = [ + entry('API/fliplet-payments.md', { + capabilities: '[stripe, checkout', + category: 'commerce', + }), + ]; + const errors = validateCapabilities(docs); + const warn = errors.find((e) => e.message.includes('bracket-mismatch')); + assert.ok(warn); + assert.equal(warn.severity, 'warn'); + }); + + it('warns when category is missing on a catalog entry', () => { + const docs = [ + entry('API/fliplet-payments.md', { + capabilities: '[stripe, checkout]', + }), + ]; + const errors = validateCapabilities(docs); + const cat = errors.find((e) => e.field === 'category'); + assert.ok(cat); + assert.equal(cat.severity, 'warn'); + assert.match(cat.message, /missing/); + }); + + it('errors when category value is not in the allowed enum', () => { + const docs = [ + entry('API/fliplet-payments.md', { + capabilities: '[stripe]', + category: 'identitiy', // typo + }), + ]; + const errors = validateCapabilities(docs); + const cat = errors.find((e) => e.field === 'category'); + assert.ok(cat); + assert.equal(cat.severity, undefined); // hard error + assert.match(cat.message, /not in the allowed set/); + }); + + it('every error carries hint and docUrl', () => { + const docs = [ + entry('API/fliplet-payments.md', { + capabilities: '[Stripe, stripe, stripe]', + }), + ]; + const errors = validateCapabilities(docs); + assert.ok(errors.length > 0); + for (const e of errors) { + assert.ok(e.hint, `error on field ${e.field} missing hint`); + assert.ok(e.docUrl, `error on field ${e.field} missing docUrl`); + } + }); +}); + +describe('emitCapabilitiesIndex', () => { + function doc(relPath, title, description, fm = {}) { + return { + relPath, + url: `https://developers.fliplet.com/${relPath.replace(/\.md$/, '.html')}`, + title, + description, + fm, + }; + } + + it('skips docs outside the V3 catalog', () => { + const docs = [ + doc('Building-themes.md', 'Themes', 'Theme guide'), + doc('REST-API/Apps.md', 'Apps', 'REST'), + ]; + const out = emitCapabilitiesIndex(docs); + assert.match(out, /No content/i.test(out) || !/Building-themes/.test(out) ? /.*/ : /unreachable/); + assert.ok(!out.includes('Themes — Theme guide')); + }); + + it('groups entries by category in ALLOWED_CATEGORIES order', () => { + const docs = [ + doc('API/fliplet-payments.md', 'Fliplet.Payments', 'Stripe', { category: 'commerce', capabilities: '[stripe]' }), + doc('API/fliplet-datasources.md', 'Fliplet.DataSources', 'CRUD', { category: 'data', capabilities: '[crud]' }), + doc('API/core/user.md', 'Fliplet.User', 'Auth', { category: 'identity', capabilities: '[auth]' }), + ]; + const out = emitCapabilitiesIndex(docs); + const dataIdx = out.indexOf('## Data'); + const identityIdx = out.indexOf('## Identity'); + const commerceIdx = out.indexOf('## Commerce'); + assert.ok(dataIdx > 0); + assert.ok(identityIdx > dataIdx, 'Identity section after Data'); + assert.ok(commerceIdx > identityIdx, 'Commerce after Identity'); + }); + + it('puts uncategorised entries under an Uncategorized heading', () => { + const docs = [ + doc('API/fliplet-x.md', 'Fliplet.X', 'No category here', {}), + ]; + const out = emitCapabilitiesIndex(docs); + assert.match(out, /## Uncategorized/); + assert.match(out, /Fliplet\.X/); + }); + + it('marks ambient entries as preloaded', () => { + const docs = [ + doc('API/core/storage.md', 'Fliplet.Storage', 'Persist', { category: 'data', capabilities: '[storage]' }), + doc('API/fliplet-datasources.md', 'Fliplet.DataSources', 'Query', { category: 'data', capabilities: '[crud]' }), + ]; + const out = emitCapabilitiesIndex(docs); + assert.match(out, /Fliplet\.Storage[^—]*\*\*\(preloaded\)\*\*/); + // Installable should NOT have the preloaded tag + const dsLine = out.split('\n').find((l) => l.includes('Fliplet.DataSources')); + assert.ok(!dsLine.includes('preloaded')); + }); + + it('contains required frontmatter so validateFrontmatter passes on the generated file', () => { + const out = emitCapabilitiesIndex([]); + assert.match(out, /^---\n/); + assert.match(out, /title:/); + assert.match(out, /description:/); + assert.match(out, /type: reference/); + assert.match(out, /tags: \[v3, capabilities, js-api\]/); + }); + + it('produces byte-identical output across two runs (no timestamp drift)', () => { + const docs = [ + doc('API/fliplet-payments.md', 'Fliplet.Payments', 'Stripe', { category: 'commerce', capabilities: '[stripe]' }), + doc('API/core/user.md', 'Fliplet.User', 'Auth', { category: 'identity', capabilities: '[auth]' }), + ]; + const a = emitCapabilitiesIndex(docs); + const b = emitCapabilitiesIndex(docs); + assert.equal(a, b); + }); + + it('sorts entries within a category alphabetically by namespace', () => { + const docs = [ + doc('API/fliplet-payments.md', 'Fliplet.Payments', 'd', { category: 'commerce', capabilities: '[a]' }), + doc('API/fliplet-app-submissions.md', 'Fliplet.App.Submissions', 'd', { category: 'commerce', capabilities: '[a]' }), + ]; + const out = emitCapabilitiesIndex(docs); + const submissionsIdx = out.indexOf('Fliplet.App.Submissions'); + const paymentsIdx = out.indexOf('Fliplet.Payments'); + assert.ok(submissionsIdx > 0 && paymentsIdx > 0); + assert.ok(submissionsIdx < paymentsIdx, 'App.Submissions sorts before Payments'); + }); + + it('treats unknown category values as uncategorised', () => { + const docs = [ + doc('API/fliplet-x.md', 'Fliplet.X', 'd', { category: 'bogus', capabilities: '[a]' }), + ]; + const out = emitCapabilitiesIndex(docs); + assert.match(out, /## Uncategorized/); + }); +}); + +describe('ALLOWED_CATEGORIES', () => { + it('has exactly 10 values', () => { + assert.equal(ALLOWED_CATEGORIES.length, 10); + }); + + it('matches the documented enum order', () => { + assert.deepEqual(ALLOWED_CATEGORIES, [ + 'data', + 'identity', + 'communications', + 'media', + 'native', + 'commerce', + 'integration', + 'automation', + 'analytics', + 'meta', + ]); + }); + + it('exposes a Set for fast lookup', () => { + assert.ok(ALLOWED_CATEGORIES_SET instanceof Set); + assert.equal(ALLOWED_CATEGORIES_SET.size, ALLOWED_CATEGORIES.length); + for (const c of ALLOWED_CATEGORIES) { + assert.ok(ALLOWED_CATEGORIES_SET.has(c)); + } + }); }); diff --git a/docs/bin/build-agent-indexes.mjs b/docs/bin/build-agent-indexes.mjs index 16bd894b..3fa46809 100644 --- a/docs/bin/build-agent-indexes.mjs +++ b/docs/bin/build-agent-indexes.mjs @@ -27,6 +27,28 @@ import { createHash } from 'node:crypto'; import { fileURLToPath } from 'node:url'; import { dirname, join, relative, resolve, sep } from 'node:path'; import { shouldExclude } from './exclusions.mjs'; +import { + ALLOWED_CATEGORIES, + ALLOWED_CATEGORIES_SET, + deriveV3Package, + emitCapabilitiesIndex, + emitV3LibraryCatalog, + isV3CatalogEntry, + parseListFrontmatter, +} from './emitters.mjs'; + +// Re-export from emitters.mjs to preserve the import surface used by tests +// (bin/__tests__/build-agent-indexes.test.mjs). New code should import +// directly from emitters.mjs. +export { + ALLOWED_CATEGORIES, + ALLOWED_CATEGORIES_SET, + deriveV3Package, + emitCapabilitiesIndex, + emitV3LibraryCatalog, + isV3CatalogEntry, + parseListFrontmatter, +}; const here = dirname(fileURLToPath(import.meta.url)); const docsRoot = resolve(here, '..'); @@ -459,112 +481,11 @@ export function emitSkillMd(cluster, docsInCluster) { ); } -// V3 library catalog manifest. Emitted at /.well-known/llms-v3-libraries.json -// and consumed by Studio's `searchLibraries.js` tool to drive V3 builder -// library discovery, replacing the legacy /v1/widgets/assets fetch. -// -// Inclusion rules: -// - Installable packages: docs whose `relPath` matches `API/fliplet-*.md`. -// Emitted with `preloaded: false`. Package name defaults to the URL slug -// (`API/fliplet-barcode.md` → `fliplet-barcode`) and can be overridden -// via `package:` frontmatter. -// - Ambient (preloaded) namespaces: docs whose `relPath` matches -// `API/core/*.md`. Emitted with `preloaded: true` and `package: -// "fliplet-core"` since these APIs ship inside fliplet-core, which is -// bundled into every app and never needs `add_dependencies`. -// -// Either kind is skipped when `exclude_from_v3_catalog: true` is set in -// frontmatter. The catalog also surfaces two optional curation fields read -// from doc frontmatter: -// - `capabilities:` — bracketed list of keywords used by the consumer -// (Studio's `searchLibraries.js` and the V3 builder system prompt) to -// anchor user-described capabilities ("stripe", "checkout", "image -// generation") to the canonical Fliplet API. Always emitted as an -// array; empty when frontmatter omits it. -// - `notes:` — short curation note for side-effects or do-not-use caveats -// (e.g. fliplet-encryption modifies Fliplet.DataSources). Only emitted -// when present. -const V3_INSTALLABLE_PATH_RE = /^API\/fliplet-[^/]+\.md$/; -const V3_AMBIENT_PATH_RE = /^API\/core\/[^/]+\.md$/; - -export function deriveV3Package(relPath) { - const match = relPath.match(/^API\/(fliplet-[^/]+)\.md$/); - return match ? match[1] : null; -} - -// Parse a YAML-style flow list (`[a, b, c]`) or a bare comma-separated -// string into a clean array of trimmed strings. Returns [] for empty, -// missing, or `[]` inputs. The minimal frontmatter parser upstream keeps -// the raw value as a literal string, so this is where the list shape -// becomes an array. -export function parseListFrontmatter(raw) { - if (raw == null) return []; - const s = String(raw).trim(); - if (s === '' || s === '[]') return []; - const body = s.startsWith('[') && s.endsWith(']') ? s.slice(1, -1) : s; - return body - .split(',') - .map((t) => t.trim()) - .map((t) => { - if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) { - return t.slice(1, -1); - } - return t; - }) - .filter((t) => t.length > 0); -} - -export function emitV3LibraryCatalog(docs) { - const libraries = []; - for (const doc of docs) { - const isInstallable = V3_INSTALLABLE_PATH_RE.test(doc.relPath); - const isAmbient = V3_AMBIENT_PATH_RE.test(doc.relPath); - if (!isInstallable && !isAmbient) continue; - const fm = doc.fm || {}; - if (fm.exclude_from_v3_catalog === 'true') continue; - - let pkg; - if (isInstallable) { - pkg = (fm.package && fm.package.trim()) || deriveV3Package(doc.relPath); - if (!pkg) continue; - } else { - // Ambient namespaces all ship inside fliplet-core (preloaded into - // every app). Studio consumers key off `preloaded` to decide whether - // `add_dependencies` is required, not off `package`. - pkg = 'fliplet-core'; - } - - const entry = { - package: pkg, - namespace: doc.title, - title: doc.title, - description: doc.description || '', - docUrl: doc.url, - preloaded: isAmbient, - capabilities: parseListFrontmatter(fm.capabilities), - }; - - if (fm.notes && fm.notes.trim() !== '') { - entry.notes = fm.notes.trim(); - } - - libraries.push(entry); - } - // Stable sort: installable first (preloaded=false), then ambient, alpha by - // package then namespace as a tiebreaker. Studio's renderer groups by - // `preloaded`; this order makes the JSON pleasant to read in diffs too. - libraries.sort((a, b) => { - if (a.preloaded !== b.preloaded) return a.preloaded ? 1 : -1; - const pkgCmp = (a.package || '').localeCompare(b.package || ''); - if (pkgCmp !== 0) return pkgCmp; - return (a.namespace || '').localeCompare(b.namespace || ''); - }); - return { - version: 1, - generatedAt: new Date().toISOString(), - libraries, - }; -} +// V3 library catalog (emitV3LibraryCatalog) and capabilities index page +// (emitCapabilitiesIndex) emitters live in ./emitters.mjs. They share an +// `isV3CatalogEntry(doc)` predicate so neither drifts from the other. +// Re-exports above keep `bin/__tests__/build-agent-indexes.test.mjs` +// working without a test-side import change. // MCP Server Card per SEP-1649 // (https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127). @@ -698,6 +619,123 @@ export function validateFrontmatter(docs) { return errors; } +// Strict-mode capability-field validator. Returns an array of error objects +// (`{ relPath, field, message, hint, docUrl }`) — empty array means clean. +// +// Scope: only docs that pass `isV3CatalogEntry(doc)`. This is intentionally +// different from `validateFrontmatter` (which runs on every doc): the lints +// here enforce the catalog's invariants, and docs outside the catalog +// (guides, REST API, etc.) don't have `capabilities:` or `category:` at all. +// +// Two rule families: +// +// `capabilities:` (already-curated field — these lints catch authoring +// slips after the field was added): +// - empty/absent (must have at least one keyword on a catalog entry) +// - non-lowercase token (e.g. `Stripe` should be `stripe`) +// - duplicate token within one entry +// - token >40 chars (probably a run-on or comma left out) +// - WARN if a token starts with `[` — strong signal of bracket-mismatch +// in the YAML flow list (e.g. `capabilities: [stripe, checkout` +// without the closing `]`). `parseListFrontmatter` parses this +// silently with `[stripe` as the first token. +// +// `category:` (new field — enforces the enum): +// - empty/absent +// - value not in `ALLOWED_CATEGORIES_SET` +// +// All errors carry a `hint` (one-liner fix) and a `docUrl` pointing to the +// CONTRIBUTING checklist. The strict-mode runner in main() includes them +// in the printed error message. +const CONTRIBUTING_URL = `${BASE_URL}/CONTRIBUTING`; + +export function validateCapabilities(docs) { + const errors = []; + for (const doc of docs) { + if (!isV3CatalogEntry(doc)) continue; + const fm = doc.fm || {}; + + // capabilities[] + const capsRaw = fm.capabilities; + const caps = parseListFrontmatter(capsRaw); + if (capsRaw == null || capsRaw.trim() === '' || capsRaw.trim() === '[]' || caps.length === 0) { + errors.push({ + relPath: doc.relPath, + field: 'capabilities', + message: '`capabilities:` is empty or missing on a V3 catalog entry', + hint: 'Add 6–12 lowercase keywords describing what this API does (e.g. `[stripe, checkout, subscription]`).', + docUrl: CONTRIBUTING_URL, + }); + } else { + const seen = new Set(); + for (const token of caps) { + if (token.startsWith('[')) { + errors.push({ + relPath: doc.relPath, + field: 'capabilities', + message: `\`capabilities:\` token \`${token}\` starts with \`[\` — likely a bracket-mismatch in YAML`, + hint: 'Check that the flow list is wrapped correctly, e.g. `capabilities: [a, b, c]` (note the closing `]`).', + docUrl: CONTRIBUTING_URL, + severity: 'warn', + }); + } + if (token !== token.toLowerCase()) { + errors.push({ + relPath: doc.relPath, + field: 'capabilities', + message: `\`capabilities:\` token \`${token}\` contains uppercase characters`, + hint: 'Capability keywords must be lowercase (e.g. `stripe`, not `Stripe`).', + docUrl: CONTRIBUTING_URL, + }); + } + if (token.length > 40) { + errors.push({ + relPath: doc.relPath, + field: 'capabilities', + message: `\`capabilities:\` token is >40 chars: \`${token}\``, + hint: 'Keywords should be short. Check for a missing comma.', + docUrl: CONTRIBUTING_URL, + }); + } + if (seen.has(token)) { + errors.push({ + relPath: doc.relPath, + field: 'capabilities', + message: `\`capabilities:\` duplicate token \`${token}\``, + hint: 'Remove the duplicate.', + docUrl: CONTRIBUTING_URL, + }); + } + seen.add(token); + } + } + + // category (enforced once D3.1 backfill completes — until then, the + // empty/missing rule is a soft warning so CI doesn't fail before the + // category-backfill commit lands). + const cat = fm.category && fm.category.trim(); + if (!cat) { + errors.push({ + relPath: doc.relPath, + field: 'category', + message: '`category:` is missing on a V3 catalog entry', + hint: `Pick one of: ${ALLOWED_CATEGORIES.join(', ')}.`, + docUrl: CONTRIBUTING_URL, + severity: 'warn', + }); + } else if (!ALLOWED_CATEGORIES_SET.has(cat)) { + errors.push({ + relPath: doc.relPath, + field: 'category', + message: `\`category: ${cat}\` is not in the allowed set`, + hint: `Allowed values: ${ALLOWED_CATEGORIES.join(', ')}.`, + docUrl: CONTRIBUTING_URL, + }); + } + } + return errors; +} + function main() { const strict = process.argv.includes('--strict'); const docs = collectDocs(docsRoot); @@ -721,6 +759,35 @@ function main() { } } + // Capability lints run after frontmatter validation. Scope: V3 catalog + // entries only (see isV3CatalogEntry). Each error carries a `hint` and + // a `docUrl` to the CONTRIBUTING checklist so authors know exactly how + // to fix. + const capErrors = validateCapabilities(docs); + const capHardErrors = capErrors.filter((e) => e.severity !== 'warn'); + const capWarns = capErrors.filter((e) => e.severity === 'warn'); + if (capWarns.length > 0) { + for (const e of capWarns) { + console.error(`[warn] ${e.relPath}: ${e.message}`); + if (e.hint) console.error(` hint: ${e.hint}`); + if (e.docUrl) console.error(` see: ${e.docUrl}`); + } + } + if (capHardErrors.length > 0) { + const tag = strict ? '[error]' : '[warn]'; + for (const e of capHardErrors) { + console.error(`${tag} ${e.relPath}: ${e.message}`); + if (e.hint) console.error(` hint: ${e.hint}`); + if (e.docUrl) console.error(` see: ${e.docUrl}`); + } + if (strict) { + console.error( + `\n${capHardErrors.length} capability error${capHardErrors.length === 1 ? '' : 's'} — failing build (--strict).`, + ); + process.exit(1); + } + } + mkdirSync(agentSkillsDir, { recursive: true }); mkdirSync(mcpDir, { recursive: true }); @@ -766,6 +833,14 @@ function main() { JSON.stringify(v3Catalog, null, 2) + '\n', ); + // Capabilities index page. Written to docs/v3/capabilities.md so Jekyll + // renders it like any other doc. Byte-stable (no timestamps) so two runs + // against identical input produce byte-identical output. + const v3Dir = join(docsRoot, 'v3'); + mkdirSync(v3Dir, { recursive: true }); + const capabilitiesPage = emitCapabilitiesIndex(docs); + writeFileSync(join(v3Dir, 'capabilities.md'), capabilitiesPage); + console.log('Generated:'); console.log(` .well-known/llms.txt (${llmsTxt.length} bytes, ${docs.length} entries)`); console.log(` .well-known/llms-full.txt (${llmsFull.length} bytes)`); @@ -776,6 +851,7 @@ function main() { } console.log(` .well-known/mcp/server-card.json (${MCP_ENDPOINT})`); console.log(` .well-known/llms-v3-libraries.json (${v3Catalog.libraries.length} V3 librar${v3Catalog.libraries.length === 1 ? 'y' : 'ies'})`); + console.log(` v3/capabilities.md (${capabilitiesPage.length} bytes)`); } // Run main() only when invoked as a script, not when imported by tests. diff --git a/docs/bin/emitters.mjs b/docs/bin/emitters.mjs new file mode 100644 index 00000000..2067b62d --- /dev/null +++ b/docs/bin/emitters.mjs @@ -0,0 +1,256 @@ +// Emitters and shared catalog predicates for the V3 library catalog and the +// auto-generated capabilities index page. +// +// Lives outside `build-agent-indexes.mjs` (the build orchestrator) to keep +// each file navigable and to give the two emitters that share inclusion +// logic — `emitV3LibraryCatalog` and `emitCapabilitiesIndex` — a single +// `isV3CatalogEntry(doc)` source of truth. Both call it; nothing else +// decides what counts as a catalog entry. +// +// Stdlib only — no npm deps. Imported by build-agent-indexes.mjs. + +// V3 catalog membership is determined by two path patterns plus the +// `exclude_from_v3_catalog: true` frontmatter opt-out. Keep these regexes +// private to this module — the predicate `isV3CatalogEntry` is the public +// contract. +const V3_INSTALLABLE_PATH_RE = /^API\/fliplet-[^/]+\.md$/; +const V3_AMBIENT_PATH_RE = /^API\/core\/[^/]+\.md$/; + +// Allowed values for the `category:` frontmatter field. Documented in +// docs/CLAUDE.md as the canonical schema. Each catalog entry picks exactly +// one primary category; the auto-generated capabilities page groups entries +// by this value. +// +// Order matters: the capabilities page renders sections in this order, so +// `data` and `identity` lead and the more orthogonal buckets (`automation`, +// `analytics`, `meta`) trail. +export const ALLOWED_CATEGORIES = [ + 'data', + 'identity', + 'communications', + 'media', + 'native', + 'commerce', + 'integration', + 'automation', + 'analytics', + 'meta', +]; + +export const ALLOWED_CATEGORIES_SET = new Set(ALLOWED_CATEGORIES); + +// Shared predicate. Both `emitV3LibraryCatalog` and `emitCapabilitiesIndex` +// must use this — drift between them is a real bug (page would show entries +// the agent doesn't know about, or vice versa). +// +// A doc is a V3 catalog entry when: +// - its path matches `API/fliplet-*.md` (installable) OR +// `API/core/*.md` (ambient, preloaded via fliplet-core), AND +// - its frontmatter does NOT set `exclude_from_v3_catalog: true`. +// +// Note: this is DIFFERENT from `shouldExclude(path)` in exclusions.mjs. +// `shouldExclude` skips a path from indexing entirely (redirect stubs, +// `_site/`, etc.); `isV3CatalogEntry` decides catalog membership for docs +// that ARE indexed. Conflating them mis-fires lints across all docs. +export function isV3CatalogEntry(doc) { + const isInstallable = V3_INSTALLABLE_PATH_RE.test(doc.relPath); + const isAmbient = V3_AMBIENT_PATH_RE.test(doc.relPath); + if (!isInstallable && !isAmbient) return false; + const fm = doc.fm || {}; + if (fm.exclude_from_v3_catalog === 'true') return false; + return true; +} + +export function deriveV3Package(relPath) { + const match = relPath.match(/^API\/(fliplet-[^/]+)\.md$/); + return match ? match[1] : null; +} + +// Parse a YAML-style flow list (`[a, b, c]`) or a bare comma-separated +// string into a clean array of trimmed strings. Returns [] for empty, +// missing, or `[]` inputs. The minimal frontmatter parser upstream keeps +// the raw value as a literal string, so this is where the list shape +// becomes an array. +export function parseListFrontmatter(raw) { + if (raw == null) return []; + const s = String(raw).trim(); + if (s === '' || s === '[]') return []; + const body = s.startsWith('[') && s.endsWith(']') ? s.slice(1, -1) : s; + return body + .split(',') + .map((t) => t.trim()) + .map((t) => { + if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) { + return t.slice(1, -1); + } + return t; + }) + .filter((t) => t.length > 0); +} + +// V3 library catalog manifest. Emitted at /.well-known/llms-v3-libraries.json +// and consumed by Studio's `searchLibraries.js` tool and the V3 builder +// system prompt to drive library discovery. +// +// Inclusion rules: see `isV3CatalogEntry`. The catalog also surfaces three +// optional curation fields read from doc frontmatter: +// - `capabilities:` — bracketed list of keywords used to anchor user- +// described capabilities ("stripe", "checkout", "image generation") to +// the canonical Fliplet API. Always emitted as an array; empty when +// frontmatter omits it. +// - `category:` — single string from `ALLOWED_CATEGORIES`. Drives the +// capabilities index page grouping. Emitted as `category` when present. +// - `notes:` — short curation note for side-effects or do-not-use caveats +// (e.g. fliplet-encryption modifies Fliplet.DataSources). Only emitted +// when present. +export function emitV3LibraryCatalog(docs) { + const libraries = []; + for (const doc of docs) { + if (!isV3CatalogEntry(doc)) continue; + const isAmbient = V3_AMBIENT_PATH_RE.test(doc.relPath); + const fm = doc.fm || {}; + + let pkg; + if (!isAmbient) { + pkg = (fm.package && fm.package.trim()) || deriveV3Package(doc.relPath); + if (!pkg) continue; + } else { + pkg = 'fliplet-core'; + } + + const entry = { + package: pkg, + namespace: doc.title, + title: doc.title, + description: doc.description || '', + docUrl: doc.url, + preloaded: isAmbient, + capabilities: parseListFrontmatter(fm.capabilities), + }; + + if (fm.category && fm.category.trim() !== '') { + entry.category = fm.category.trim(); + } + if (fm.notes && fm.notes.trim() !== '') { + entry.notes = fm.notes.trim(); + } + + libraries.push(entry); + } + // Stable sort: installable first (preloaded=false), then ambient, alpha by + // package then namespace as a tiebreaker. + libraries.sort((a, b) => { + if (a.preloaded !== b.preloaded) return a.preloaded ? 1 : -1; + const pkgCmp = (a.package || '').localeCompare(b.package || ''); + if (pkgCmp !== 0) return pkgCmp; + return (a.namespace || '').localeCompare(b.namespace || ''); + }); + return { + version: 1, + generatedAt: new Date().toISOString(), + libraries, + }; +} + +// Capabilities index page (`docs/v3/capabilities.md`). Auto-generated from +// the same catalog set as `emitV3LibraryCatalog`. Renders one section per +// `ALLOWED_CATEGORIES` value, with entries sorted by namespace. +// +// Output is a complete Markdown file with frontmatter — Jekyll renders it +// at developers.fliplet.com/v3/capabilities like any other doc. Frontmatter +// is required so `validateFrontmatter` passes on the generated file. +// +// Byte-stable: no timestamps in the output. Two runs against identical +// input produce byte-identical output. +export function emitCapabilitiesIndex(docs) { + const entries = []; + const uncategorized = []; + + for (const doc of docs) { + if (!isV3CatalogEntry(doc)) continue; + const fm = doc.fm || {}; + const category = fm.category && fm.category.trim(); + const isAmbient = V3_AMBIENT_PATH_RE.test(doc.relPath); + const item = { + namespace: doc.title, + description: doc.description || '', + url: doc.url, + preloaded: isAmbient, + }; + if (category && ALLOWED_CATEGORIES_SET.has(category)) { + entries.push({ category, ...item }); + } else { + uncategorized.push(item); + } + } + + // Group by category, preserving ALLOWED_CATEGORIES order for stable output. + const byCategory = new Map(ALLOWED_CATEGORIES.map((c) => [c, []])); + for (const e of entries) byCategory.get(e.category).push(e); + for (const c of ALLOWED_CATEGORIES) { + byCategory.get(c).sort((a, b) => a.namespace.localeCompare(b.namespace)); + } + uncategorized.sort((a, b) => a.namespace.localeCompare(b.namespace)); + + const lines = []; + lines.push('---'); + lines.push('title: "V3 capabilities"'); + lines.push( + 'description: "Auto-generated index of every Fliplet JS API surface available to V3 apps, grouped by capability category."', + ); + lines.push('type: reference'); + lines.push('tags: [v3, capabilities, js-api]'); + lines.push('v3_relevant: true'); + lines.push('---'); + lines.push(''); + lines.push(''); + lines.push(''); + lines.push(''); + lines.push('# V3 capabilities'); + lines.push(''); + lines.push( + 'Every Fliplet JS API available to V3 apps, grouped by capability category. Each entry links to its full API reference. Ambient namespaces (preloaded into every app via `fliplet-core`) are marked **preloaded**; everything else is installable via `add_dependencies`.', + ); + lines.push(''); + + const HEADERS = { + data: 'Data', + identity: 'Identity', + communications: 'Communications', + media: 'Media', + native: 'Native', + commerce: 'Commerce', + integration: 'Integration', + automation: 'Automation', + analytics: 'Analytics', + meta: 'Meta', + }; + + for (const cat of ALLOWED_CATEGORIES) { + const items = byCategory.get(cat); + if (items.length === 0) continue; + lines.push(`## ${HEADERS[cat] || cat}`); + lines.push(''); + for (const item of items) { + const tag = item.preloaded ? ' **(preloaded)**' : ''; + lines.push(`- [\`${item.namespace}\`](${item.url})${tag} — ${item.description}`); + } + lines.push(''); + } + + if (uncategorized.length > 0) { + lines.push('## Uncategorized'); + lines.push(''); + lines.push( + '_These entries are missing a `category:` value in frontmatter. See `docs/CONTRIBUTING.md` for how to assign one._', + ); + lines.push(''); + for (const item of uncategorized) { + const tag = item.preloaded ? ' **(preloaded)**' : ''; + lines.push(`- [\`${item.namespace}\`](${item.url})${tag} — ${item.description}`); + } + lines.push(''); + } + + return lines.join('\n'); +} diff --git a/docs/v3/capabilities.md b/docs/v3/capabilities.md new file mode 100644 index 00000000..7abcc5cf --- /dev/null +++ b/docs/v3/capabilities.md @@ -0,0 +1,83 @@ +--- +title: "V3 capabilities" +description: "Auto-generated index of every Fliplet JS API surface available to V3 apps, grouped by capability category." +type: reference +tags: [v3, capabilities, js-api] +v3_relevant: true +--- + + + + +# V3 capabilities + +Every Fliplet JS API available to V3 apps, grouped by capability category. Each entry links to its full API reference. Ambient namespaces (preloaded into every app via `fliplet-core`) are marked **preloaded**; everything else is installable via `add_dependencies`. + +## Data + +- [``Fliplet.Storage` and `Fliplet.App.Storage``](https://developers.fliplet.com/API/core/storage.html) **(preloaded)** — Persist JSON-serializable values to device or browser storage, scoped globally or to the current app. +- [`Fliplet.Cache`](https://developers.fliplet.com/API/core/cache.html) **(preloaded)** — Run async operations once and memoize their results, with optional expiry and background refresh. +- [`Fliplet.DataSources`](https://developers.fliplet.com/API/fliplet-datasources.html) — Connect to, query, insert, update, and delete records in Fliplet Data Sources from inside an app. All methods are promise-based. +- [`Fliplet.DataSources.Encryption`](https://developers.fliplet.com/API/fliplet-encryption.html) — Automatically encrypt and decrypt selected Data Source columns on-device by registering a private key and column list. + +## Identity + +- [`Fliplet.Organizations`](https://developers.fliplet.com/API/core/organizations.html) **(preloaded)** — List the current user's organizations and fetch audit logs with filters for type, date range, app, and session. +- [`Fliplet.Profile`](https://developers.fliplet.com/API/core/profile.html) **(preloaded)** — Read and write namespaced user profile attributes (email, name, company, phone) and fetch the device UUID. +- [`Fliplet.Security`](https://developers.fliplet.com/API/fliplet-security.html) — Persist a per-app structured object to encrypted device storage via the fliplet-security package — for app-local secrets, device tokens, and per-user preferences. Distinct from fliplet-encryption (Da… +- [`Fliplet.Session`](https://developers.fliplet.com/API/fliplet-session.html) — Read, write, and clear the current user session — including cached offline sessions — for authentication state in Fliplet apps. +- [`Fliplet.User`](https://developers.fliplet.com/API/core/user.html) **(preloaded)** — Get and set the current user's auth token, profile details, and preferences, and sign the user out. +- [`Fliplet.User.Biometrics`](https://developers.fliplet.com/API/core/biometrics.html) **(preloaded)** — Check biometric availability and verify users with Face ID, Touch ID, or fingerprint inside native Fliplet apps. + +## Communications + +- [`Fliplet.Chat`](https://developers.fliplet.com/API/fliplet-chat.html) — Build one-to-one, group, and public-channel chat features. Fliplet.Chat owns the conversations and messages data sources internally — supply only the contacts list (who can chat with whom). +- [`Fliplet.Communicate`](https://developers.fliplet.com/API/fliplet-communicate.html) — Send email, SMS, push notifications, and share URLs from a Fliplet app using a single Communicate namespace. +- [`Fliplet.Navigator.Notifications`](https://developers.fliplet.com/API/core/notifications.html) **(preloaded)** — Check notification support, request permission, and send local device notifications from JavaScript. +- [`Fliplet.Notifications`](https://developers.fliplet.com/API/fliplet-notifications.html) — Read, send, and schedule in-app and push notifications in Fliplet apps, with support for scopes, read receipts, and badge counts. +- [`Fliplet.Socket`](https://developers.fliplet.com/API/fliplet-socket.html) — Real-time WebSocket connection to the Fliplet API with auto-authentication, server URL discovery, and dev/prod transport fallback via the fliplet-socket package. + +## Media + +- [`Fliplet.Barcode`](https://developers.fliplet.com/API/fliplet-barcode.html) — Generate QR codes and 1D/2D barcodes on screen, and scan them from the device camera, via the fliplet-barcode package. +- [`Fliplet.Media`](https://developers.fliplet.com/API/fliplet-media.html) — Browse folders, upload and manage files, and download media to devices via the Fliplet Media namespace. +- [`Fliplet.Media.Audio`](https://developers.fliplet.com/API/fliplet-audio.html) — Play, pause, stop, and seek audio files on device or from a URL in Fliplet apps via the Audio namespace. + +## Native + +- [`Fliplet.Navigator`](https://developers.fliplet.com/API/core/navigator.html) **(preloaded)** — Detect online/offline state, listen for connectivity changes, and wait for the device to be ready. + +## Commerce + +- [`Fliplet.App.Submissions`](https://developers.fliplet.com/API/fliplet-app-submissions.html) — Read App Store and Google Play submission metadata for the current Fliplet app — version, status, build numbers — via the fliplet-app-submissions package. +- [`Fliplet.Payments`](https://developers.fliplet.com/API/fliplet-payments.html) — Accept Stripe payments and checkout in Fliplet apps via Fliplet.Payments, with a products data source and webhook-driven order tracking. + +## Integration + +- [`Fliplet.API.request()`](https://developers.fliplet.com/API/core/api.html) **(preloaded)** — Make authenticated HTTP requests to Fliplet APIs with automatic URL construction, caching, offline queueing, and error handling. +- [`Fliplet.App.Tokens`](https://developers.fliplet.com/API/fliplet-tokens.html) — Read the list of API tokens that authorise external services and backend integrations to call Fliplet APIs on behalf of an app. + +## Automation + +- [`App Actions V3`](https://developers.fliplet.com/API/core/app-actions-v3.html) **(preloaded)** — Write and run JavaScript code directly on the server or client to perform automations, scheduled tasks and on-demand operations. +- [`Fliplet.AI`](https://developers.fliplet.com/API/core/ai.html) **(preloaded)** — Build AI features with `Fliplet.AI` — chat, completions, streaming, image generation, transcription, and embeddings via OpenAI or Google Gemini proxies. +- [`Fliplet.Hooks`](https://developers.fliplet.com/API/core/hooks.html) **(preloaded)** — Register callbacks that run before or after key app events (e.g. form submit), with sync or async Promise handlers. + +## Analytics + +- [`Fliplet.Analytics`](https://developers.fliplet.com/API/core/analytics.html) **(preloaded)** — Enable, disable, and check analytics tracking, and record custom app events and page views from JavaScript. + +## Meta + +- [``Fliplet.Pages` and `Fliplet.Page``](https://developers.fliplet.com/API/core/screens.html) **(preloaded)** — List app screens, get the current screen's public URL, and build shareable URLs for any screen by ID. +- [`Fliplet common functions`](https://developers.fliplet.com/API/core/misc.html) **(preloaded)** — Utility helpers on the global `Fliplet` object: `Fliplet.compile()` for templating and `Fliplet.guid()` for unique IDs. +- [`Fliplet.App`](https://developers.fliplet.com/API/core/app.html) **(preloaded)** — Retrieve the current app's public slug, build shareable screen URLs, and access app-level settings from JavaScript. +- [`Fliplet.Apps`](https://developers.fliplet.com/API/core/apps.html) **(preloaded)** — List the Fliplet apps the current user can access, and filter between legacy V1 and modern V2 apps. +- [`Fliplet.Encode`](https://developers.fliplet.com/API/core/encode.html) **(preloaded)** — Encode strings as base64 and double-encode URL query parameters safely for transport. +- [`Fliplet.Env`](https://developers.fliplet.com/API/core/environment.html) **(preloaded)** — Read environment variables such as `appId`, `appName`, `mode`, and `apiUrl` from the current runtime. +- [`Fliplet.Locale`](https://developers.fliplet.com/API/core/localization.html) **(preloaded)** — Translate strings and format dates and numbers in Fliplet components via Fliplet.Locale, the T() shorthand, and translation.json files using i18next. +- [`Fliplet.Navigate`](https://developers.fliplet.com/API/core/navigate.html) **(preloaded)** — Navigate between app screens, open external URLs, pass query parameters, and handle back, home, and modal navigation via Fliplet.Navigate. +- [`Fliplet.parseError()`](https://developers.fliplet.com/API/core/error.html) **(preloaded)** — Turn any error response or object into a human-readable message by scanning common error properties. +- [`Fliplet.Registry`](https://developers.fliplet.com/API/core/registry.html) **(preloaded)** — Store and retrieve runtime values and functions by key so components can share state and helpers. +- [`Fliplet.Studio`](https://developers.fliplet.com/API/core/studio.html) **(preloaded)** — Emit events to Fliplet Studio and listen for events from it when building widget interfaces. +- [`Fliplet.Widget`](https://developers.fliplet.com/API/core/widget.html) **(preloaded)** — Access widget instance IDs, settings, and data, and coordinate save and ready events between widget and interface. From f35dfd0868e7f9620234f6ee75277d3e70a43d5a Mon Sep 17 00:00:00 2001 From: Tony Wu Date: Mon, 18 May 2026 18:05:46 +0100 Subject: [PATCH 2/3] docs: add CONTRIBUTING.md + document category schema in CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the contributor checklist that lint errors link to so a new package PR has a single page to follow instead of scattered tribal knowledge. `docs/CONTRIBUTING.md` (new): - 10-item "Adding a new package doc" checklist covering template, the full frontmatter schema (incl. the new `category:` enum), capability tagging guidance with worked examples, when to use `exclude_from_v3_catalog`, signature verification against api repo source, the `--strict` local check, and PR + CF Pages preview. - "Updating an existing doc" cautions about renaming titles and reordering capabilities[] (both ripple through the V3 builder's prompt and SHA-pinned downstream artifacts). - File-location map so contributors know which directory a new doc belongs in. `docs/CLAUDE.md`: - "Optional fields for V3 library catalog" section gains `category:` with the full enum, a cross-cutting-API guidance note, and a pointer to CONTRIBUTING.md. - Build pipeline diagram now shows the v3/capabilities.md output and notes the validateCapabilities lints. - "What NOT to add" §5 ("No second taxonomy") gets a documented exception for the auto-generated capabilities page: re-derived from catalog on every build, can't drift, serves a distinct audience. `docs/bin/build-agent-indexes.mjs`: - Lint `docUrl` for capability errors now points at developers.fliplet.com/CONTRIBUTING.html (matching the `.html` convention in urlForPath). Verification: - npm run test:unit → 127/127 pass - node bin/build-agent-indexes.mjs --strict → exit 0 - Three injected violations (empty capabilities, bad category value, uppercase token) all caught by --strict with hint + docUrl printed Co-Authored-By: Claude Opus 4.7 (1M context) --- .../agent-skills/fliplet-docs-index/SKILL.md | 1 + docs/.well-known/agent-skills/index.json | 2 +- docs/.well-known/llms-full.txt | 187 +++++++++++++++--- docs/.well-known/llms-v3-libraries.json | 2 +- docs/.well-known/llms.txt | 1 + docs/CLAUDE.md | 27 ++- docs/CONTRIBUTING.md | 109 ++++++++++ docs/bin/build-agent-indexes.mjs | 2 +- 8 files changed, 298 insertions(+), 33 deletions(-) create mode 100644 docs/CONTRIBUTING.md diff --git a/docs/.well-known/agent-skills/fliplet-docs-index/SKILL.md b/docs/.well-known/agent-skills/fliplet-docs-index/SKILL.md index 3d2fab88..cc171f5e 100644 --- a/docs/.well-known/agent-skills/fliplet-docs-index/SKILL.md +++ b/docs/.well-known/agent-skills/fliplet-docs-index/SKILL.md @@ -34,6 +34,7 @@ These docs don't belong to a single capability cluster — they are general onbo - [Best practice and advices when building components](https://developers.fliplet.com/Best-practises.html): Gotchas for Fliplet components: instance data, multi-drop handling, Handlebars escaping for Vue/Angular curly braces, and required dependencies. - [Changelog](https://developers.fliplet.com/Changelog.html): Changelog notes giving a summary of recent significant changes to the documentation. - [Fliplet coding and documentation standards](https://developers.fliplet.com/coding-standards.html): Coding and documentation standards used across Fliplet APIs, components, and examples, so both humans and AI tools produce consistent Fliplet code. +- [Contributing to developer documentation](https://developers.fliplet.com/CONTRIBUTING.html): How to author docs in fliplet-cli/docs — frontmatter schema, capability tagging, the V3 catalog, and the CI checks that run on every PR. - [Sending events between components](https://developers.fliplet.com/Event-emitter.html): Components interfaces can send events to Fliplet Studio using a event emitter bus provided with the `fliplet-core` dependency. - [Fliplet app execution flow](https://developers.fliplet.com/Execution-flow.html): The rendering and hook lifecycle Fliplet apps go through before a screen is shown to the user, and where to safely run custom code within it. - [Introduction to the Fliplet developer platform](https://developers.fliplet.com/Introduction.html): Overview of the Fliplet developer stack (JavaScript, SASS, Handlebars) and the kinds of apps, components, themes, and menus you can build on it. diff --git a/docs/.well-known/agent-skills/index.json b/docs/.well-known/agent-skills/index.json index 42caa483..d9b6a5e5 100644 --- a/docs/.well-known/agent-skills/index.json +++ b/docs/.well-known/agent-skills/index.json @@ -143,7 +143,7 @@ "index", "fallback" ], - "sha256": "c3a6063139ab0508ed14aaed58299e4f99fbc00ae1a5151b7197bbdcb21f23bb" + "sha256": "7ead6a898b1148692aff42e53a19107c9f2888f75b61e6746f6ab324d4d0b0c1" } ] } diff --git a/docs/.well-known/llms-full.txt b/docs/.well-known/llms-full.txt index d5ed55dc..30ee8949 100644 --- a/docs/.well-known/llms-full.txt +++ b/docs/.well-known/llms-full.txt @@ -28958,6 +28958,112 @@ if (isTemplate) { --- +# Contributing to developer documentation +URL: https://developers.fliplet.com/CONTRIBUTING.html + +# Contributing to developer documentation + +This is the contributor checklist for adding or updating Fliplet developer documentation. Lint errors in the build pipeline link back to this page, so what's here is what CI is checking for. + +The reference reading underneath this checklist is `docs/CLAUDE.md` — the canonical schema for frontmatter, the build pipeline, and the rules for what NOT to add. This page is the human-facing walkthrough. + +## Adding a new package doc + +When you add a new `fliplet-*` package, follow this 10-step checklist: + +1. **Start from the template.** Copy `_templates/doc-template.md` (or `_templates/js-api.md` for a JavaScript API reference) to `docs/API/fliplet-.md`. Filename must match the npm package name, prefixed with `fliplet-`. + +2. **Set the required frontmatter.** Every doc needs: + - `title:` matching the H1 (minus enclosing backticks) + - `description:` 1–2 sentences, ≤160 chars, standalone + - `type:` one of `api-reference` / `guide` / `how-to` / `concept` / `tutorial` / `reference` / `integration` + - `tags:` first tag is the canonical area (`js-api`, `rest-api`, etc.), then 1–5 specifics, lowercase dash-separated + - `v3_relevant: true` (default; set `false` only for clearly V1-only content) + - `deprecated: false` (default) + +3. **Add `capabilities:` — 6–12 lowercase keywords.** Describe what this API does in user-facing terms ("stripe", "barcode scan", "send email"), including named third-party services where relevant. The V3 AI builder uses these to anchor user-described capabilities to your API without a `search_libraries` round-trip. Examples: + ```yaml + capabilities: [stripe, checkout, subscription, recurring billing, refund, webhook, customer portal, payment intent, ecommerce] + capabilities: [barcode scan, qr code, ean, upc, code 128, code 39, camera scanner] + ``` + +4. **Add `category:` — pick exactly one.** Allowed values (see `docs/v3/capabilities` for what's in each): + - `data` — persistence, query, real-time, encryption, offline storage + - `identity` — auth, sessions, biometrics, profile, orgs, tokens + - `communications` — email / SMS / push, chat, websockets + - `media` — upload, transform, audio, scanning, barcode + - `native` — native-only APIs (Cordova bridge) + - `commerce` — payments, subscriptions, app store / play store metadata + - `integration` — REST API, OAuth, webhooks, app actions, hooks + - `automation` — AI, app actions runtime, tasks, scheduling + - `analytics` — analytics, error tracking, navigation, metrics + - `meta` — registry, widget, common functions, framework-level helpers + + Pick the dominant facet. A cross-cutting API like `Fliplet.Notifications` (communications + native) picks `communications` because that's how end-users describe what it does. + +5. **Set `exclude_from_v3_catalog: true` ONLY if the package shouldn't appear in the V3 builder's anchored prompt.** Cases where exclusion is correct: + - The package is a UI primitive replaced by the V3 design system (`fliplet-ui-*`, `fliplet-table`, `fliplet-modal`) + - The package is deprecated, V1-only, or a redirect stub + - The doc is meta (overview pages, framework docs) + + Most installable docs SHOULD be in the catalog. Add a one-line `notes:` field too if the exclusion needs context. + +6. **Write the intro paragraph between H1 and the first H2.** The `llms.txt` extractor and the agent-skills/SKILL.md generators both depend on prose between the title and the first subheading. Don't jump straight from `# Title` into `## Subheading`. + +7. **Document each public method with a runnable code example.** Code examples must work — the V3 AI builder follows the docs literally. Verify signatures against `~/Sites/fliplet/api/public/assets//` source before publishing. + +8. **Verify the doc against source.** For JS APIs, cross-check every method name, parameter list, and return shape against the package source. If a method exists in source but isn't documented, decide whether it's public-API-worthy (document) or internal (omit). Don't document methods that don't exist. + +9. **Run `--strict` locally.** From `docs/`: + ```bash + node bin/build-agent-indexes.mjs --strict + ``` + Fix any errors before opening a PR. The lint will catch: + - Empty/non-lowercase/duplicate `capabilities[]` tokens + - Tokens >40 chars (likely a missing comma) + - Tokens that start with `[` (bracket-mismatch in your YAML flow list) + - Missing `category:` or values outside the allowed enum + - Standard frontmatter violations from `validateFrontmatter` + +10. **Open the PR.** CF Pages will build a branch preview. Visit the preview URL to confirm: + - Your doc renders with the right layout + - It appears under the correct section on `/v3/capabilities` (auto-generated index) + - The `.well-known/llms-v3-libraries.json` diff in the PR shows your new entry with the right `category`, `capabilities`, and `preloaded` flag + +## Updating an existing doc + +The same rules apply with two adjustments: +- Don't change `title:` casually — the V3 AI builder embeds the namespace title in its system prompt; renaming silently shifts what the agent recognises. +- Don't reorder `capabilities[]` — the field is hashed downstream; reordering = diff churn without semantic change. + +## Where does each thing live? + +- **`docs/API/fliplet-*.md`** — installable packages (catalog: `preloaded: false`) +- **`docs/API/core/*.md`** — ambient namespaces preloaded via `fliplet-core` (catalog: `preloaded: true`) +- **`docs/API/components/*.md`** — components framework (not in V3 catalog) +- **`docs/API/helpers/*.md`** — helpers framework (not in V3 catalog) +- **`docs/REST-API/*.md`** — REST endpoints (not in V3 catalog) +- **`docs/v3/*.md`** — V3-specific generated pages (e.g. `capabilities.md` — do not hand-edit) + +## What gets generated, what doesn't + +`bin/build-agent-indexes.mjs` runs on every CF Pages deploy and regenerates these on every push: + +- `.well-known/llms.txt` — per-page index +- `.well-known/llms-full.txt` — concatenated content +- `.well-known/llms-v3-libraries.json` — the V3 library catalog +- `.well-known/agent-skills/*` — cluster-shaped skill registry +- `v3/capabilities.md` — the auto-generated capabilities index + +You can edit any of these manually but the next build will overwrite. The single source of truth is your doc's frontmatter + body. + +## See also + +- [`docs/CLAUDE.md`](https://github.com/Fliplet/fliplet-cli/blob/master/docs/CLAUDE.md) — full schema, build pipeline, "what NOT to add" +- [`docs/v3/capabilities`](v3/capabilities) — the live capabilities index (auto-generated from `category:` frontmatter) + +--- + # Custom Headers URL: https://developers.fliplet.com/Custom-Headers.html @@ -37526,48 +37632,73 @@ URL: https://developers.fliplet.com/v3/capabilities.html Every Fliplet JS API available to V3 apps, grouped by capability category. Each entry links to its full API reference. Ambient namespaces (preloaded into every app via `fliplet-core`) are marked **preloaded**; everything else is installable via `add_dependencies`. -## Uncategorized - -_These entries are missing a `category:` value in frontmatter. See `docs/CONTRIBUTING.md` for how to assign one._ +## Data -- [``Fliplet.Pages` and `Fliplet.Page``](https://developers.fliplet.com/API/core/screens.html) **(preloaded)** — List app screens, get the current screen's public URL, and build shareable URLs for any screen by ID. - [``Fliplet.Storage` and `Fliplet.App.Storage``](https://developers.fliplet.com/API/core/storage.html) **(preloaded)** — Persist JSON-serializable values to device or browser storage, scoped globally or to the current app. +- [`Fliplet.Cache`](https://developers.fliplet.com/API/core/cache.html) **(preloaded)** — Run async operations once and memoize their results, with optional expiry and background refresh. +- [`Fliplet.DataSources`](https://developers.fliplet.com/API/fliplet-datasources.html) — Connect to, query, insert, update, and delete records in Fliplet Data Sources from inside an app. All methods are promise-based. +- [`Fliplet.DataSources.Encryption`](https://developers.fliplet.com/API/fliplet-encryption.html) — Automatically encrypt and decrypt selected Data Source columns on-device by registering a private key and column list. + +## Identity + +- [`Fliplet.Organizations`](https://developers.fliplet.com/API/core/organizations.html) **(preloaded)** — List the current user's organizations and fetch audit logs with filters for type, date range, app, and session. +- [`Fliplet.Profile`](https://developers.fliplet.com/API/core/profile.html) **(preloaded)** — Read and write namespaced user profile attributes (email, name, company, phone) and fetch the device UUID. +- [`Fliplet.Security`](https://developers.fliplet.com/API/fliplet-security.html) — Persist a per-app structured object to encrypted device storage via the fliplet-security package — for app-local secrets, device tokens, and per-user preferences. Distinct from fliplet-encryption (Da… +- [`Fliplet.Session`](https://developers.fliplet.com/API/fliplet-session.html) — Read, write, and clear the current user session — including cached offline sessions — for authentication state in Fliplet apps. +- [`Fliplet.User`](https://developers.fliplet.com/API/core/user.html) **(preloaded)** — Get and set the current user's auth token, profile details, and preferences, and sign the user out. +- [`Fliplet.User.Biometrics`](https://developers.fliplet.com/API/core/biometrics.html) **(preloaded)** — Check biometric availability and verify users with Face ID, Touch ID, or fingerprint inside native Fliplet apps. + +## Communications + +- [`Fliplet.Chat`](https://developers.fliplet.com/API/fliplet-chat.html) — Build one-to-one, group, and public-channel chat features. Fliplet.Chat owns the conversations and messages data sources internally — supply only the contacts list (who can chat with whom). +- [`Fliplet.Communicate`](https://developers.fliplet.com/API/fliplet-communicate.html) — Send email, SMS, push notifications, and share URLs from a Fliplet app using a single Communicate namespace. +- [`Fliplet.Navigator.Notifications`](https://developers.fliplet.com/API/core/notifications.html) **(preloaded)** — Check notification support, request permission, and send local device notifications from JavaScript. +- [`Fliplet.Notifications`](https://developers.fliplet.com/API/fliplet-notifications.html) — Read, send, and schedule in-app and push notifications in Fliplet apps, with support for scopes, read receipts, and badge counts. +- [`Fliplet.Socket`](https://developers.fliplet.com/API/fliplet-socket.html) — Real-time WebSocket connection to the Fliplet API with auto-authentication, server URL discovery, and dev/prod transport fallback via the fliplet-socket package. + +## Media + +- [`Fliplet.Barcode`](https://developers.fliplet.com/API/fliplet-barcode.html) — Generate QR codes and 1D/2D barcodes on screen, and scan them from the device camera, via the fliplet-barcode package. +- [`Fliplet.Media`](https://developers.fliplet.com/API/fliplet-media.html) — Browse folders, upload and manage files, and download media to devices via the Fliplet Media namespace. +- [`Fliplet.Media.Audio`](https://developers.fliplet.com/API/fliplet-audio.html) — Play, pause, stop, and seek audio files on device or from a URL in Fliplet apps via the Audio namespace. + +## Native + +- [`Fliplet.Navigator`](https://developers.fliplet.com/API/core/navigator.html) **(preloaded)** — Detect online/offline state, listen for connectivity changes, and wait for the device to be ready. + +## Commerce + +- [`Fliplet.App.Submissions`](https://developers.fliplet.com/API/fliplet-app-submissions.html) — Read App Store and Google Play submission metadata for the current Fliplet app — version, status, build numbers — via the fliplet-app-submissions package. +- [`Fliplet.Payments`](https://developers.fliplet.com/API/fliplet-payments.html) — Accept Stripe payments and checkout in Fliplet apps via Fliplet.Payments, with a products data source and webhook-driven order tracking. + +## Integration + +- [`Fliplet.API.request()`](https://developers.fliplet.com/API/core/api.html) **(preloaded)** — Make authenticated HTTP requests to Fliplet APIs with automatic URL construction, caching, offline queueing, and error handling. +- [`Fliplet.App.Tokens`](https://developers.fliplet.com/API/fliplet-tokens.html) — Read the list of API tokens that authorise external services and backend integrations to call Fliplet APIs on behalf of an app. + +## Automation + - [`App Actions V3`](https://developers.fliplet.com/API/core/app-actions-v3.html) **(preloaded)** — Write and run JavaScript code directly on the server or client to perform automations, scheduled tasks and on-demand operations. -- [`Fliplet common functions`](https://developers.fliplet.com/API/core/misc.html) **(preloaded)** — Utility helpers on the global `Fliplet` object: `Fliplet.compile()` for templating and `Fliplet.guid()` for unique IDs. - [`Fliplet.AI`](https://developers.fliplet.com/API/core/ai.html) **(preloaded)** — Build AI features with `Fliplet.AI` — chat, completions, streaming, image generation, transcription, and embeddings via OpenAI or Google Gemini proxies. +- [`Fliplet.Hooks`](https://developers.fliplet.com/API/core/hooks.html) **(preloaded)** — Register callbacks that run before or after key app events (e.g. form submit), with sync or async Promise handlers. + +## Analytics + - [`Fliplet.Analytics`](https://developers.fliplet.com/API/core/analytics.html) **(preloaded)** — Enable, disable, and check analytics tracking, and record custom app events and page views from JavaScript. -- [`Fliplet.API.request()`](https://developers.fliplet.com/API/core/api.html) **(preloaded)** — Make authenticated HTTP requests to Fliplet APIs with automatic URL construction, caching, offline queueing, and error handling. + +## Meta + +- [``Fliplet.Pages` and `Fliplet.Page``](https://developers.fliplet.com/API/core/screens.html) **(preloaded)** — List app screens, get the current screen's public URL, and build shareable URLs for any screen by ID. +- [`Fliplet common functions`](https://developers.fliplet.com/API/core/misc.html) **(preloaded)** — Utility helpers on the global `Fliplet` object: `Fliplet.compile()` for templating and `Fliplet.guid()` for unique IDs. - [`Fliplet.App`](https://developers.fliplet.com/API/core/app.html) **(preloaded)** — Retrieve the current app's public slug, build shareable screen URLs, and access app-level settings from JavaScript. -- [`Fliplet.App.Submissions`](https://developers.fliplet.com/API/fliplet-app-submissions.html) — Read App Store and Google Play submission metadata for the current Fliplet app — version, status, build numbers — via the fliplet-app-submissions package. -- [`Fliplet.App.Tokens`](https://developers.fliplet.com/API/fliplet-tokens.html) — Read the list of API tokens that authorise external services and backend integrations to call Fliplet APIs on behalf of an app. - [`Fliplet.Apps`](https://developers.fliplet.com/API/core/apps.html) **(preloaded)** — List the Fliplet apps the current user can access, and filter between legacy V1 and modern V2 apps. -- [`Fliplet.Barcode`](https://developers.fliplet.com/API/fliplet-barcode.html) — Generate QR codes and 1D/2D barcodes on screen, and scan them from the device camera, via the fliplet-barcode package. -- [`Fliplet.Cache`](https://developers.fliplet.com/API/core/cache.html) **(preloaded)** — Run async operations once and memoize their results, with optional expiry and background refresh. -- [`Fliplet.Chat`](https://developers.fliplet.com/API/fliplet-chat.html) — Build one-to-one, group, and public-channel chat features. Fliplet.Chat owns the conversations and messages data sources internally — supply only the contacts list (who can chat with whom). -- [`Fliplet.Communicate`](https://developers.fliplet.com/API/fliplet-communicate.html) — Send email, SMS, push notifications, and share URLs from a Fliplet app using a single Communicate namespace. -- [`Fliplet.DataSources`](https://developers.fliplet.com/API/fliplet-datasources.html) — Connect to, query, insert, update, and delete records in Fliplet Data Sources from inside an app. All methods are promise-based. -- [`Fliplet.DataSources.Encryption`](https://developers.fliplet.com/API/fliplet-encryption.html) — Automatically encrypt and decrypt selected Data Source columns on-device by registering a private key and column list. - [`Fliplet.Encode`](https://developers.fliplet.com/API/core/encode.html) **(preloaded)** — Encode strings as base64 and double-encode URL query parameters safely for transport. - [`Fliplet.Env`](https://developers.fliplet.com/API/core/environment.html) **(preloaded)** — Read environment variables such as `appId`, `appName`, `mode`, and `apiUrl` from the current runtime. -- [`Fliplet.Hooks`](https://developers.fliplet.com/API/core/hooks.html) **(preloaded)** — Register callbacks that run before or after key app events (e.g. form submit), with sync or async Promise handlers. - [`Fliplet.Locale`](https://developers.fliplet.com/API/core/localization.html) **(preloaded)** — Translate strings and format dates and numbers in Fliplet components via Fliplet.Locale, the T() shorthand, and translation.json files using i18next. -- [`Fliplet.Media`](https://developers.fliplet.com/API/fliplet-media.html) — Browse folders, upload and manage files, and download media to devices via the Fliplet Media namespace. -- [`Fliplet.Media.Audio`](https://developers.fliplet.com/API/fliplet-audio.html) — Play, pause, stop, and seek audio files on device or from a URL in Fliplet apps via the Audio namespace. - [`Fliplet.Navigate`](https://developers.fliplet.com/API/core/navigate.html) **(preloaded)** — Navigate between app screens, open external URLs, pass query parameters, and handle back, home, and modal navigation via Fliplet.Navigate. -- [`Fliplet.Navigator`](https://developers.fliplet.com/API/core/navigator.html) **(preloaded)** — Detect online/offline state, listen for connectivity changes, and wait for the device to be ready. -- [`Fliplet.Navigator.Notifications`](https://developers.fliplet.com/API/core/notifications.html) **(preloaded)** — Check notification support, request permission, and send local device notifications from JavaScript. -- [`Fliplet.Notifications`](https://developers.fliplet.com/API/fliplet-notifications.html) — Read, send, and schedule in-app and push notifications in Fliplet apps, with support for scopes, read receipts, and badge counts. -- [`Fliplet.Organizations`](https://developers.fliplet.com/API/core/organizations.html) **(preloaded)** — List the current user's organizations and fetch audit logs with filters for type, date range, app, and session. - [`Fliplet.parseError()`](https://developers.fliplet.com/API/core/error.html) **(preloaded)** — Turn any error response or object into a human-readable message by scanning common error properties. -- [`Fliplet.Payments`](https://developers.fliplet.com/API/fliplet-payments.html) — Accept Stripe payments and checkout in Fliplet apps via Fliplet.Payments, with a products data source and webhook-driven order tracking. -- [`Fliplet.Profile`](https://developers.fliplet.com/API/core/profile.html) **(preloaded)** — Read and write namespaced user profile attributes (email, name, company, phone) and fetch the device UUID. - [`Fliplet.Registry`](https://developers.fliplet.com/API/core/registry.html) **(preloaded)** — Store and retrieve runtime values and functions by key so components can share state and helpers. -- [`Fliplet.Security`](https://developers.fliplet.com/API/fliplet-security.html) — Persist a per-app structured object to encrypted device storage via the fliplet-security package — for app-local secrets, device tokens, and per-user preferences. Distinct from fliplet-encryption (Da… -- [`Fliplet.Session`](https://developers.fliplet.com/API/fliplet-session.html) — Read, write, and clear the current user session — including cached offline sessions — for authentication state in Fliplet apps. -- [`Fliplet.Socket`](https://developers.fliplet.com/API/fliplet-socket.html) — Real-time WebSocket connection to the Fliplet API with auto-authentication, server URL discovery, and dev/prod transport fallback via the fliplet-socket package. - [`Fliplet.Studio`](https://developers.fliplet.com/API/core/studio.html) **(preloaded)** — Emit events to Fliplet Studio and listen for events from it when building widget interfaces. -- [`Fliplet.User`](https://developers.fliplet.com/API/core/user.html) **(preloaded)** — Get and set the current user's auth token, profile details, and preferences, and sign the user out. -- [`Fliplet.User.Biometrics`](https://developers.fliplet.com/API/core/biometrics.html) **(preloaded)** — Check biometric availability and verify users with Face ID, Touch ID, or fingerprint inside native Fliplet apps. - [`Fliplet.Widget`](https://developers.fliplet.com/API/core/widget.html) **(preloaded)** — Access widget instance IDs, settings, and data, and coordinate save and ready events between widget and interface. --- diff --git a/docs/.well-known/llms-v3-libraries.json b/docs/.well-known/llms-v3-libraries.json index 039522f8..a9375da4 100644 --- a/docs/.well-known/llms-v3-libraries.json +++ b/docs/.well-known/llms-v3-libraries.json @@ -1,6 +1,6 @@ { "version": 1, - "generatedAt": "2026-05-18T16:59:34.786Z", + "generatedAt": "2026-05-18T17:05:16.435Z", "libraries": [ { "package": "fliplet-app-submissions", diff --git a/docs/.well-known/llms.txt b/docs/.well-known/llms.txt index 93afa0b2..439246dd 100644 --- a/docs/.well-known/llms.txt +++ b/docs/.well-known/llms.txt @@ -192,6 +192,7 @@ - [Fliplet coding and documentation standards](https://developers.fliplet.com/coding-standards.html): Coding and documentation standards used across Fliplet APIs, components, and examples, so both humans and AI tools produce consistent Fliplet code. - [Component events](https://developers.fliplet.com/Component-events.html): Listen for component lifecycle events (adding, added, removed, moved, render) emitted while users edit a Fliplet screen, via Fliplet.Hooks.on('componentEvent'). - [Context targeting](https://developers.fliplet.com/Context-targeting.html): Target devices in Fliplet apps via Modernizr classes and JS flags for iOS, Android, Windows, web, native, mobile/tablet/desktop, notch, and Studio edit mode. +- [Contributing to developer documentation](https://developers.fliplet.com/CONTRIBUTING.html): How to author docs in fliplet-cli/docs — frontmatter schema, capability tagging, the V3 catalog, and the CI checks that run on every PR. - [Custom Headers](https://developers.fliplet.com/Custom-Headers.html): Configure custom HTTP response headers (CSP, HSTS, CORS, custom security headers) for a Fliplet app via Fliplet.App.Settings and the Developer Options panel. - [Custom HTML templates for Fliplet components](https://developers.fliplet.com/Custom-template-for-components.html): How to override a component's default template with custom HTML and Handlebars in the new container-based drag-and-drop system. - [Fliplet infrastructure data flow](https://developers.fliplet.com/Data-flow.html): Architecture diagram showing how data flows between Fliplet Studio, Fliplet servers, app clients, and connected data sources. diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md index f0a67c31..5cf17e08 100644 --- a/docs/CLAUDE.md +++ b/docs/CLAUDE.md @@ -52,12 +52,13 @@ index still emits them; it is up to the consumer to prefer non-deprecated. ### Optional fields for V3 library catalog The V3 library catalog (`/.well-known/llms-v3-libraries.json`, consumed by -Studio's V3 AI builder) reads two extra optional fields from `API/fliplet-*.md` +Studio's V3 AI builder) reads three extra optional fields from `API/fliplet-*.md` (installable packages) and `API/core/*.md` (ambient namespaces preloaded into every app): ```yaml capabilities: [stripe, checkout, subscription, refund, billing, webhook] +category: commerce notes: "Installing this package transparently encrypts/decrypts columns in Fliplet.DataSources operations — install only when you intend to encrypt." exclude_from_v3_catalog: true # opt the doc out of the catalog ``` @@ -69,6 +70,16 @@ recognize when a user-described capability maps to an existing Fliplet API without a `search_libraries` round-trip. Aim for 6-12 keywords, including named third-party services where applicable. +**`category`** — single string from the enumerated set +`{ data, identity, communications, media, native, commerce, integration, +automation, analytics, meta }`. Drives the section grouping on the +auto-generated `/v3/capabilities` index page. Pick the dominant facet — +cross-cutting APIs (e.g. `Fliplet.Notifications` = communications + +native) pick the one that matches how end-users describe what the API +does. Required on non-excluded catalog entries; lint warns when absent, +errors when value is outside the allowed set. See `docs/CONTRIBUTING.md` +for guidance on which value to pick. + **`notes`** — short curation note for side-effects, do-not-use caveats, or gotchas the agent needs to know up-front. Used sparingly — most docs need none. @@ -109,8 +120,14 @@ docs/**/*.md │ llms.txt, llms-full.txt, │ agent-skills/index.json, │ agent-skills//SKILL.md (12 capability clusters), - │ mcp/server-card.json + │ mcp/server-card.json, + │ llms-v3-libraries.json (V3 builder catalog) │ } + │ docs/v3/capabilities.md (auto-generated index page) + │ + │ Also runs validateFrontmatter + validateCapabilities in --strict + │ mode (CI). Capability lints enforce: non-empty/lowercase/unique/ + │ ≤40-char `capabilities[]`; `category:` value ∈ enumerated set. │ ├── bundle exec jekyll build │ ↓ @@ -232,6 +249,12 @@ Counters drift toward more layers when fewer would do: - **No second taxonomy for the same docs.** We already publish per-page (`llms.txt`) and clustered (`agent-skills/`) views; a third classification needs a distinct audience that neither serves. + - **Exception**: `docs/v3/capabilities.md` is auto-generated from + frontmatter `category:` and serves a distinct audience (PMs / partner + developers / external evaluators asking "what can apps do?"). It is + not hand-maintained prose and re-derives from the catalog on every + build, so it cannot drift. Audit any future "we need a third + taxonomy" proposal against the same generated-from-frontmatter bar. ## Repository conventions diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 00000000..2e928315 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,109 @@ +--- +title: "Contributing to developer documentation" +description: "How to author docs in fliplet-cli/docs — frontmatter schema, capability tagging, the V3 catalog, and the CI checks that run on every PR." +type: guide +tags: [contributing, authoring, meta] +v3_relevant: true +deprecated: false +--- + +# Contributing to developer documentation + +This is the contributor checklist for adding or updating Fliplet developer documentation. Lint errors in the build pipeline link back to this page, so what's here is what CI is checking for. + +The reference reading underneath this checklist is `docs/CLAUDE.md` — the canonical schema for frontmatter, the build pipeline, and the rules for what NOT to add. This page is the human-facing walkthrough. + +## Adding a new package doc + +When you add a new `fliplet-*` package, follow this 10-step checklist: + +1. **Start from the template.** Copy `_templates/doc-template.md` (or `_templates/js-api.md` for a JavaScript API reference) to `docs/API/fliplet-.md`. Filename must match the npm package name, prefixed with `fliplet-`. + +2. **Set the required frontmatter.** Every doc needs: + - `title:` matching the H1 (minus enclosing backticks) + - `description:` 1–2 sentences, ≤160 chars, standalone + - `type:` one of `api-reference` / `guide` / `how-to` / `concept` / `tutorial` / `reference` / `integration` + - `tags:` first tag is the canonical area (`js-api`, `rest-api`, etc.), then 1–5 specifics, lowercase dash-separated + - `v3_relevant: true` (default; set `false` only for clearly V1-only content) + - `deprecated: false` (default) + +3. **Add `capabilities:` — 6–12 lowercase keywords.** Describe what this API does in user-facing terms ("stripe", "barcode scan", "send email"), including named third-party services where relevant. The V3 AI builder uses these to anchor user-described capabilities to your API without a `search_libraries` round-trip. Examples: + ```yaml + capabilities: [stripe, checkout, subscription, recurring billing, refund, webhook, customer portal, payment intent, ecommerce] + capabilities: [barcode scan, qr code, ean, upc, code 128, code 39, camera scanner] + ``` + +4. **Add `category:` — pick exactly one.** Allowed values (see `docs/v3/capabilities` for what's in each): + - `data` — persistence, query, real-time, encryption, offline storage + - `identity` — auth, sessions, biometrics, profile, orgs, tokens + - `communications` — email / SMS / push, chat, websockets + - `media` — upload, transform, audio, scanning, barcode + - `native` — native-only APIs (Cordova bridge) + - `commerce` — payments, subscriptions, app store / play store metadata + - `integration` — REST API, OAuth, webhooks, app actions, hooks + - `automation` — AI, app actions runtime, tasks, scheduling + - `analytics` — analytics, error tracking, navigation, metrics + - `meta` — registry, widget, common functions, framework-level helpers + + Pick the dominant facet. A cross-cutting API like `Fliplet.Notifications` (communications + native) picks `communications` because that's how end-users describe what it does. + +5. **Set `exclude_from_v3_catalog: true` ONLY if the package shouldn't appear in the V3 builder's anchored prompt.** Cases where exclusion is correct: + - The package is a UI primitive replaced by the V3 design system (`fliplet-ui-*`, `fliplet-table`, `fliplet-modal`) + - The package is deprecated, V1-only, or a redirect stub + - The doc is meta (overview pages, framework docs) + + Most installable docs SHOULD be in the catalog. Add a one-line `notes:` field too if the exclusion needs context. + +6. **Write the intro paragraph between H1 and the first H2.** The `llms.txt` extractor and the agent-skills/SKILL.md generators both depend on prose between the title and the first subheading. Don't jump straight from `# Title` into `## Subheading`. + +7. **Document each public method with a runnable code example.** Code examples must work — the V3 AI builder follows the docs literally. Verify signatures against `~/Sites/fliplet/api/public/assets//` source before publishing. + +8. **Verify the doc against source.** For JS APIs, cross-check every method name, parameter list, and return shape against the package source. If a method exists in source but isn't documented, decide whether it's public-API-worthy (document) or internal (omit). Don't document methods that don't exist. + +9. **Run `--strict` locally.** From `docs/`: + ```bash + node bin/build-agent-indexes.mjs --strict + ``` + Fix any errors before opening a PR. The lint will catch: + - Empty/non-lowercase/duplicate `capabilities[]` tokens + - Tokens >40 chars (likely a missing comma) + - Tokens that start with `[` (bracket-mismatch in your YAML flow list) + - Missing `category:` or values outside the allowed enum + - Standard frontmatter violations from `validateFrontmatter` + +10. **Open the PR.** CF Pages will build a branch preview. Visit the preview URL to confirm: + - Your doc renders with the right layout + - It appears under the correct section on `/v3/capabilities` (auto-generated index) + - The `.well-known/llms-v3-libraries.json` diff in the PR shows your new entry with the right `category`, `capabilities`, and `preloaded` flag + +## Updating an existing doc + +The same rules apply with two adjustments: +- Don't change `title:` casually — the V3 AI builder embeds the namespace title in its system prompt; renaming silently shifts what the agent recognises. +- Don't reorder `capabilities[]` — the field is hashed downstream; reordering = diff churn without semantic change. + +## Where does each thing live? + +- **`docs/API/fliplet-*.md`** — installable packages (catalog: `preloaded: false`) +- **`docs/API/core/*.md`** — ambient namespaces preloaded via `fliplet-core` (catalog: `preloaded: true`) +- **`docs/API/components/*.md`** — components framework (not in V3 catalog) +- **`docs/API/helpers/*.md`** — helpers framework (not in V3 catalog) +- **`docs/REST-API/*.md`** — REST endpoints (not in V3 catalog) +- **`docs/v3/*.md`** — V3-specific generated pages (e.g. `capabilities.md` — do not hand-edit) + +## What gets generated, what doesn't + +`bin/build-agent-indexes.mjs` runs on every CF Pages deploy and regenerates these on every push: + +- `.well-known/llms.txt` — per-page index +- `.well-known/llms-full.txt` — concatenated content +- `.well-known/llms-v3-libraries.json` — the V3 library catalog +- `.well-known/agent-skills/*` — cluster-shaped skill registry +- `v3/capabilities.md` — the auto-generated capabilities index + +You can edit any of these manually but the next build will overwrite. The single source of truth is your doc's frontmatter + body. + +## See also + +- [`docs/CLAUDE.md`](https://github.com/Fliplet/fliplet-cli/blob/master/docs/CLAUDE.md) — full schema, build pipeline, "what NOT to add" +- [`docs/v3/capabilities`](v3/capabilities) — the live capabilities index (auto-generated from `category:` frontmatter) diff --git a/docs/bin/build-agent-indexes.mjs b/docs/bin/build-agent-indexes.mjs index 3fa46809..8bba1a36 100644 --- a/docs/bin/build-agent-indexes.mjs +++ b/docs/bin/build-agent-indexes.mjs @@ -647,7 +647,7 @@ export function validateFrontmatter(docs) { // All errors carry a `hint` (one-liner fix) and a `docUrl` pointing to the // CONTRIBUTING checklist. The strict-mode runner in main() includes them // in the printed error message. -const CONTRIBUTING_URL = `${BASE_URL}/CONTRIBUTING`; +const CONTRIBUTING_URL = `${BASE_URL}/CONTRIBUTING.html`; export function validateCapabilities(docs) { const errors = []; From 6a8e479a43a890a6c4e7dd868c2456c386de752d Mon Sep 17 00:00:00 2001 From: Tony Wu Date: Sat, 6 Jun 2026 23:08:54 +0100 Subject: [PATCH 3/3] =?UTF-8?q?docs(v3):=20split=20meta=20+=20add=20observ?= =?UTF-8?q?ability=20=E2=80=94=2010=20=E2=86=92=2013=20categories?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `meta` bucket was trending toward catch-all status (12 entries already, projected 16-18 after upcoming doc work). Splits into three sized-for-purpose categories and adds `observability` to give logs + error tracking a home that's distinct from `analytics` (event tracking). ALLOWED_CATEGORIES (10 → 13): - ADD: `observability` — logs, error capture, audit trails (app health). Distinct from `analytics` which is user behaviour. - ADD: `framework` — runtime, registry, environment, widget, locale, dynamic loading (framework-level glue). - ADD: `navigation` — screen navigation, URL routing, screen listing. - KEEP: `meta` — residual catch-all only (App, Apps, Encode, parseError, common functions). 5 entries post-split. Relabels 7 existing docs out of `meta`: - `core/widget.md`, `core/localization.md`, `core/environment.md`, `core/registry.md`, `core/studio.md` → `framework` - `core/navigate.md`, `core/screens.md` → `navigation` Distribution after split (39 entries total): data 4 · identity 6 · communications 5 · media 3 · native 1 · commerce 2 · integration 2 · automation 3 · analytics 1 · observability 0 · framework 5 · navigation 2 · meta 5 `observability` ships empty — the emitter skips categories with 0 entries, so the rendered page shows 12 sections currently. Future docs (fliplet-error-tracking, App.Logs, Organizations.Logs) populate it. Updates: - bin/emitters.mjs: ALLOWED_CATEGORIES enum, HEADERS map - bin/__tests__/build-agent-indexes.test.mjs: enum length + order assertions updated for 13 values - docs/CLAUDE.md: documents the 13-value enum + the "if meta exceeds 6-8 entries, split rather than absorb" rule - docs/CONTRIBUTING.md: per-category guidance for new docs (incl. the analytics/observability distinction) Verification: - node bin/build-agent-indexes.mjs --strict → exit 0 - npm run test:unit → 127/127 pass - v3/capabilities.md regenerates with 12 sections in correct order (Framework between Analytics and Meta, Navigation following) Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/.well-known/llms-full.txt | 12 +++++++---- docs/.well-known/llms-v3-libraries.json | 16 +++++++-------- docs/API/core/environment.md | 2 +- docs/API/core/localization.md | 2 +- docs/API/core/navigate.md | 2 +- docs/API/core/registry.md | 2 +- docs/API/core/screens.md | 2 +- docs/API/core/studio.md | 2 +- docs/API/core/widget.md | 2 +- docs/CLAUDE.md | 19 +++++++++++------- docs/CONTRIBUTING.md | 11 ++++++---- .../__tests__/build-agent-indexes.test.mjs | 7 +++++-- docs/bin/emitters.mjs | 18 ++++++++++++++--- docs/v3/capabilities.md | 20 ++++++++++++------- 14 files changed, 75 insertions(+), 42 deletions(-) diff --git a/docs/.well-known/llms-full.txt b/docs/.well-known/llms-full.txt index 30ee8949..14b126bc 100644 --- a/docs/.well-known/llms-full.txt +++ b/docs/.well-known/llms-full.txt @@ -28994,10 +28994,13 @@ When you add a new `fliplet-*` package, follow this 10-step checklist: - `media` — upload, transform, audio, scanning, barcode - `native` — native-only APIs (Cordova bridge) - `commerce` — payments, subscriptions, app store / play store metadata - - `integration` — REST API, OAuth, webhooks, app actions, hooks - - `automation` — AI, app actions runtime, tasks, scheduling - - `analytics` — analytics, error tracking, navigation, metrics - - `meta` — registry, widget, common functions, framework-level helpers + - `integration` — REST API, OAuth, webhooks + - `automation` — AI, app actions runtime, hooks, scheduling + - `analytics` — event tracking, custom metrics, page views (user behaviour) + - `observability` — logs, error capture, audit trails (app health — distinct from `analytics`) + - `framework` — runtime, registry, environment, widget, locale, dynamic loading (framework-level glue) + - `navigation` — screen navigation, URL routing, screen listing + - `meta` — residual catch-all (app metadata, encoding helpers, error parsing, common functions). Keep small — if `meta` exceeds 6-8 entries, propose a split rather than letting it absorb new entries Pick the dominant facet. A cross-cutting API like `Fliplet.Notifications` (communications + native) picks `communications` because that's how end-users describe what it does. @@ -32885,6 +32888,7 @@ Release notes for the Fliplet iOS and Android native frameworks — rebuild your

Android

Current release: 6.4.4

Target API level: 36

+

Minimum supported SDK: 29 (Android 10)

diff --git a/docs/.well-known/llms-v3-libraries.json b/docs/.well-known/llms-v3-libraries.json index a9375da4..033e8d01 100644 --- a/docs/.well-known/llms-v3-libraries.json +++ b/docs/.well-known/llms-v3-libraries.json @@ -1,6 +1,6 @@ { "version": 1, - "generatedAt": "2026-05-18T17:05:16.435Z", + "generatedAt": "2026-06-06T22:08:26.937Z", "libraries": [ { "package": "fliplet-app-submissions", @@ -330,7 +330,7 @@ "screen id", "public screen url" ], - "category": "meta" + "category": "navigation" }, { "package": "fliplet-core", @@ -551,7 +551,7 @@ "viewer mode", "preview mode" ], - "category": "meta" + "category": "framework" }, { "package": "fliplet-core", @@ -591,7 +591,7 @@ "multilingual", "internationalization" ], - "category": "meta" + "category": "framework" }, { "package": "fliplet-core", @@ -619,7 +619,7 @@ "confirm dialog", "prompt dialog" ], - "category": "meta" + "category": "navigation" }, { "package": "fliplet-core", @@ -730,7 +730,7 @@ "function registry", "runtime key-value" ], - "category": "meta" + "category": "framework" }, { "package": "fliplet-core", @@ -748,7 +748,7 @@ "message studio", "studio bridge" ], - "category": "meta" + "category": "framework" }, { "package": "fliplet-core", @@ -808,7 +808,7 @@ "namespaced widget", "component instance" ], - "category": "meta" + "category": "framework" } ] } diff --git a/docs/API/core/environment.md b/docs/API/core/environment.md index 2747af4f..07858c81 100644 --- a/docs/API/core/environment.md +++ b/docs/API/core/environment.md @@ -5,7 +5,7 @@ type: api-reference tags: [js-api, core, environment] v3_relevant: true deprecated: false -category: meta +category: framework capabilities: [environment, env vars, app id, api url, runtime mode, dependencies, current app, viewer mode, preview mode] --- # `Fliplet.Env` diff --git a/docs/API/core/localization.md b/docs/API/core/localization.md index 4044f8ed..23e9567c 100644 --- a/docs/API/core/localization.md +++ b/docs/API/core/localization.md @@ -5,7 +5,7 @@ type: api-reference tags: [js-api, core, localization] v3_relevant: true deprecated: false -category: meta +category: framework capabilities: [localization, i18n, translation, translate string, locale, date format, number format, i18next, multilingual, internationalization] --- diff --git a/docs/API/core/navigate.md b/docs/API/core/navigate.md index 96ed4c8d..e36cff6f 100644 --- a/docs/API/core/navigate.md +++ b/docs/API/core/navigate.md @@ -5,7 +5,7 @@ type: api-reference tags: [js-api, core, navigate] v3_relevant: true deprecated: false -category: meta +category: navigation capabilities: [navigation, navigate, link, open screen, open url, external url, query parameter, back, home, exit app, popup, gallery, play video, log out, navigate to screen, confirm dialog, prompt dialog] --- diff --git a/docs/API/core/registry.md b/docs/API/core/registry.md index 8fec0eb7..1d448c47 100644 --- a/docs/API/core/registry.md +++ b/docs/API/core/registry.md @@ -5,7 +5,7 @@ type: api-reference tags: [js-api, core, registry] v3_relevant: true deprecated: false -category: meta +category: framework capabilities: [registry, runtime registry, component shared state, runtime helpers, global helpers, function registry, runtime key-value] --- # `Fliplet.Registry` diff --git a/docs/API/core/screens.md b/docs/API/core/screens.md index 30a8ffe4..a5476a89 100644 --- a/docs/API/core/screens.md +++ b/docs/API/core/screens.md @@ -5,7 +5,7 @@ type: api-reference tags: [js-api, core, screens] v3_relevant: true deprecated: false -category: meta +category: navigation capabilities: [screen, page, list screens, current screen, screen url, share screen, screen id, public screen url] --- # `Fliplet.Pages` and `Fliplet.Page` diff --git a/docs/API/core/studio.md b/docs/API/core/studio.md index b9bedc60..e621a4d5 100644 --- a/docs/API/core/studio.md +++ b/docs/API/core/studio.md @@ -5,7 +5,7 @@ type: api-reference tags: [js-api, core, studio] v3_relevant: true deprecated: false -category: meta +category: framework capabilities: [studio events, widget interface, studio communication, send event to studio, listen to studio events, message studio, studio bridge] --- # `Fliplet.Studio` diff --git a/docs/API/core/widget.md b/docs/API/core/widget.md index cc2f8884..75fa61b5 100644 --- a/docs/API/core/widget.md +++ b/docs/API/core/widget.md @@ -5,7 +5,7 @@ type: api-reference tags: [js-api, core, widget] v3_relevant: true deprecated: false -category: meta +category: framework capabilities: [widget, widget instance, widget settings, widget data, save event, ready event, widget interface, namespaced widget, component instance] --- # `Fliplet.Widget` diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md index 5cf17e08..1a15630b 100644 --- a/docs/CLAUDE.md +++ b/docs/CLAUDE.md @@ -72,13 +72,18 @@ named third-party services where applicable. **`category`** — single string from the enumerated set `{ data, identity, communications, media, native, commerce, integration, -automation, analytics, meta }`. Drives the section grouping on the -auto-generated `/v3/capabilities` index page. Pick the dominant facet — -cross-cutting APIs (e.g. `Fliplet.Notifications` = communications + -native) pick the one that matches how end-users describe what the API -does. Required on non-excluded catalog entries; lint warns when absent, -errors when value is outside the allowed set. See `docs/CONTRIBUTING.md` -for guidance on which value to pick. +automation, analytics, observability, framework, navigation, meta }`. +Drives the section grouping on the auto-generated `/v3/capabilities` +index page. Pick the dominant facet — cross-cutting APIs (e.g. +`Fliplet.Notifications` = communications + native) pick the one that +matches how end-users describe what the API does. Required on +non-excluded catalog entries; lint warns when absent, errors when value +is outside the allowed set. See `docs/CONTRIBUTING.md` for guidance on +which value to pick. + +`meta` is the residual bucket — keep it small. If `meta` exceeds 6-8 +entries, split it further (the framework + navigation split happened +when the earlier "platform" residual hit 12+ entries). **`notes`** — short curation note for side-effects, do-not-use caveats, or gotchas the agent needs to know up-front. Used sparingly — most docs need diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 2e928315..1c51dba6 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -40,10 +40,13 @@ When you add a new `fliplet-*` package, follow this 10-step checklist: - `media` — upload, transform, audio, scanning, barcode - `native` — native-only APIs (Cordova bridge) - `commerce` — payments, subscriptions, app store / play store metadata - - `integration` — REST API, OAuth, webhooks, app actions, hooks - - `automation` — AI, app actions runtime, tasks, scheduling - - `analytics` — analytics, error tracking, navigation, metrics - - `meta` — registry, widget, common functions, framework-level helpers + - `integration` — REST API, OAuth, webhooks + - `automation` — AI, app actions runtime, hooks, scheduling + - `analytics` — event tracking, custom metrics, page views (user behaviour) + - `observability` — logs, error capture, audit trails (app health — distinct from `analytics`) + - `framework` — runtime, registry, environment, widget, locale, dynamic loading (framework-level glue) + - `navigation` — screen navigation, URL routing, screen listing + - `meta` — residual catch-all (app metadata, encoding helpers, error parsing, common functions). Keep small — if `meta` exceeds 6-8 entries, propose a split rather than letting it absorb new entries Pick the dominant facet. A cross-cutting API like `Fliplet.Notifications` (communications + native) picks `communications` because that's how end-users describe what it does. diff --git a/docs/bin/__tests__/build-agent-indexes.test.mjs b/docs/bin/__tests__/build-agent-indexes.test.mjs index e2e69ee0..07490045 100644 --- a/docs/bin/__tests__/build-agent-indexes.test.mjs +++ b/docs/bin/__tests__/build-agent-indexes.test.mjs @@ -1129,8 +1129,8 @@ describe('emitCapabilitiesIndex', () => { }); describe('ALLOWED_CATEGORIES', () => { - it('has exactly 10 values', () => { - assert.equal(ALLOWED_CATEGORIES.length, 10); + it('has exactly 13 values', () => { + assert.equal(ALLOWED_CATEGORIES.length, 13); }); it('matches the documented enum order', () => { @@ -1144,6 +1144,9 @@ describe('ALLOWED_CATEGORIES', () => { 'integration', 'automation', 'analytics', + 'observability', + 'framework', + 'navigation', 'meta', ]); }); diff --git a/docs/bin/emitters.mjs b/docs/bin/emitters.mjs index 2067b62d..2fddd162 100644 --- a/docs/bin/emitters.mjs +++ b/docs/bin/emitters.mjs @@ -21,9 +21,15 @@ const V3_AMBIENT_PATH_RE = /^API\/core\/[^/]+\.md$/; // one primary category; the auto-generated capabilities page groups entries // by this value. // -// Order matters: the capabilities page renders sections in this order, so -// `data` and `identity` lead and the more orthogonal buckets (`automation`, -// `analytics`, `meta`) trail. +// Order matters: the capabilities page renders sections in this order. Most +// commonly-reached-for categories lead (`data`, `identity`); navigation + +// framework follow; orthogonal/service categories (`automation`, +// `analytics`, `observability`, `meta`) trail. +// +// `meta` is the residual bucket — kept deliberately small. If `meta` grows +// past 6-8 entries again, split it further rather than letting it absorb +// the new entries (the same anti-pattern that motivated the framework + +// navigation split when the earlier "platform" residual hit 12+ entries). export const ALLOWED_CATEGORIES = [ 'data', 'identity', @@ -34,6 +40,9 @@ export const ALLOWED_CATEGORIES = [ 'integration', 'automation', 'analytics', + 'observability', + 'framework', + 'navigation', 'meta', ]; @@ -223,6 +232,9 @@ export function emitCapabilitiesIndex(docs) { integration: 'Integration', automation: 'Automation', analytics: 'Analytics', + observability: 'Observability', + framework: 'Framework', + navigation: 'Navigation', meta: 'Meta', }; diff --git a/docs/v3/capabilities.md b/docs/v3/capabilities.md index 7abcc5cf..ce093d44 100644 --- a/docs/v3/capabilities.md +++ b/docs/v3/capabilities.md @@ -67,17 +67,23 @@ Every Fliplet JS API available to V3 apps, grouped by capability category. Each - [`Fliplet.Analytics`](https://developers.fliplet.com/API/core/analytics.html) **(preloaded)** — Enable, disable, and check analytics tracking, and record custom app events and page views from JavaScript. -## Meta +## Framework + +- [`Fliplet.Env`](https://developers.fliplet.com/API/core/environment.html) **(preloaded)** — Read environment variables such as `appId`, `appName`, `mode`, and `apiUrl` from the current runtime. +- [`Fliplet.Locale`](https://developers.fliplet.com/API/core/localization.html) **(preloaded)** — Translate strings and format dates and numbers in Fliplet components via Fliplet.Locale, the T() shorthand, and translation.json files using i18next. +- [`Fliplet.Registry`](https://developers.fliplet.com/API/core/registry.html) **(preloaded)** — Store and retrieve runtime values and functions by key so components can share state and helpers. +- [`Fliplet.Studio`](https://developers.fliplet.com/API/core/studio.html) **(preloaded)** — Emit events to Fliplet Studio and listen for events from it when building widget interfaces. +- [`Fliplet.Widget`](https://developers.fliplet.com/API/core/widget.html) **(preloaded)** — Access widget instance IDs, settings, and data, and coordinate save and ready events between widget and interface. + +## Navigation - [``Fliplet.Pages` and `Fliplet.Page``](https://developers.fliplet.com/API/core/screens.html) **(preloaded)** — List app screens, get the current screen's public URL, and build shareable URLs for any screen by ID. +- [`Fliplet.Navigate`](https://developers.fliplet.com/API/core/navigate.html) **(preloaded)** — Navigate between app screens, open external URLs, pass query parameters, and handle back, home, and modal navigation via Fliplet.Navigate. + +## Meta + - [`Fliplet common functions`](https://developers.fliplet.com/API/core/misc.html) **(preloaded)** — Utility helpers on the global `Fliplet` object: `Fliplet.compile()` for templating and `Fliplet.guid()` for unique IDs. - [`Fliplet.App`](https://developers.fliplet.com/API/core/app.html) **(preloaded)** — Retrieve the current app's public slug, build shareable screen URLs, and access app-level settings from JavaScript. - [`Fliplet.Apps`](https://developers.fliplet.com/API/core/apps.html) **(preloaded)** — List the Fliplet apps the current user can access, and filter between legacy V1 and modern V2 apps. - [`Fliplet.Encode`](https://developers.fliplet.com/API/core/encode.html) **(preloaded)** — Encode strings as base64 and double-encode URL query parameters safely for transport. -- [`Fliplet.Env`](https://developers.fliplet.com/API/core/environment.html) **(preloaded)** — Read environment variables such as `appId`, `appName`, `mode`, and `apiUrl` from the current runtime. -- [`Fliplet.Locale`](https://developers.fliplet.com/API/core/localization.html) **(preloaded)** — Translate strings and format dates and numbers in Fliplet components via Fliplet.Locale, the T() shorthand, and translation.json files using i18next. -- [`Fliplet.Navigate`](https://developers.fliplet.com/API/core/navigate.html) **(preloaded)** — Navigate between app screens, open external URLs, pass query parameters, and handle back, home, and modal navigation via Fliplet.Navigate. - [`Fliplet.parseError()`](https://developers.fliplet.com/API/core/error.html) **(preloaded)** — Turn any error response or object into a human-readable message by scanning common error properties. -- [`Fliplet.Registry`](https://developers.fliplet.com/API/core/registry.html) **(preloaded)** — Store and retrieve runtime values and functions by key so components can share state and helpers. -- [`Fliplet.Studio`](https://developers.fliplet.com/API/core/studio.html) **(preloaded)** — Emit events to Fliplet Studio and listen for events from it when building widget interfaces. -- [`Fliplet.Widget`](https://developers.fliplet.com/API/core/widget.html) **(preloaded)** — Access widget instance IDs, settings, and data, and coordinate save and ready events between widget and interface.