diff --git a/docs/connected-apps.mdx b/docs/connected-apps.mdx new file mode 100644 index 00000000..0a4e653c --- /dev/null +++ b/docs/connected-apps.mdx @@ -0,0 +1,1061 @@ +--- +title: "Connected Apps" +description: "Partner and developer guide for Quran Foundation Connected Apps discovery, listing review, visibility, user consent, and responsible integration." +sidebar_label: "Connected Apps" +displayed_sidebar: "APIsSidebar" +--- + +import Link from '@docusaurus/Link'; + +# Connected Apps + +

+ Policy version: 1.0 Last updated: 2026-06-30{' '} + Effective date: 2026-06-30 +

+ +
+
+

Partner and developer guide

+

Prepare your Quran app for review, connection, and discovery.

+

+ Connected Apps is the path for developers and app owners who want their + product to appear on Quran.com/apps, + use Quran Foundation APIs, or request selected visibility across Quran + Foundation surfaces. This guide explains what to prepare, how review works, + what users must be able to understand, and what a listing or label does + and does not mean. +

+
+ + Request access + + + Review listing checklist + +
+
+ Directory listing + Partner review + OAuth scopes + User consent + Ongoing changes +
+
+ +
+ Start here: request API access before building against + protected APIs. When your product is ready for discovery, submit a complete + listing package with ownership, support, privacy, content, and platform + details. Developer Console self-service may simplify this workflow over + time, but access, scopes, listing approval, labels, and featured placement + remain reviewed decisions. +
+
+ +## Why Build On Quran Foundation + +Connected Apps is a way to build on trusted Quran Foundation infrastructure +while giving users a clearer path between Quran.com and participating products. + +
+
+

Trusted infrastructure

+

+ Build faster on comprehensive APIs and scholarly verified Quran data, + without maintaining fragile source pipelines on your own. +

+
+
+

Connected ecosystem

+

+ Connected Apps is more than an API program. It helps users move between + Quran.com and participating apps without starting over. +

+
+
+

Account continuity

+

+ With OAuth2 and approved User APIs, bookmarks, progress, goals, notes, and + preferences can follow the user where continuity is appropriate. +

+
+
+

Discoverability

+

+ Qualified apps can be listed on Quran.com/apps within a trusted directory + without treating discovery as paid placement. +

+
+
+

Direct support

+

+ Get guidance from Quran Foundation and a mission-aligned network of + builders during access, OAuth, listing, and review decisions. +

+
+
+ +## Partner Terms And Compliance + +Listed apps must comply with the Connected Apps requirements on this page and +all applicable laws. Where a partner or its users access Quran.com services +directly, the [Quran.com Terms & Conditions](https://quran.com/terms-and-conditions) +apply to that use. + +Apps using Quran Foundation APIs, OAuth, or user-related data must comply with +the [Quran Foundation Developer Terms](/legal/developer-terms/). + +Commercial use of Quranic content, such as hosting or redistributing licensed +recitations, translations, or tafsir, may require a separate written content +license beyond standard API access. Partner-specific or content-licensing terms +will be published here where applicable. + +## Who This Guide Is For + +Use this guide if you are building, operating, or representing an app that +connects to Quran Foundation content, authentication, user features, or public +discovery surfaces. + +
+
+
01
+

App builders

+

+ You want to use Quran Foundation APIs, SDKs, or OAuth2 to build a Quran + reading, listening, study, memorization, reflection, or community product. +

+
+
+
02
+

App owners

+

+ You want your independent app to be discoverable through Quran.com/apps + with clear ownership, support, privacy, and platform information. +

+
+
+
03
+

Partner teams

+

+ You want a stronger relationship such as OAuth account continuity, a + reviewed label, or selected editorial visibility. +

+
+
+ +## How Connected Apps Works + +Connected Apps has four public-facing parts. Treat them as separate review +steps, not as one automatic approval. + +
+
+

Build

+

Developer access and API use

+

+ Start with Request Access. Use the{' '} + Developer Journey to choose APIs + and plan OAuth clients, redirect URIs, and user-data scopes before + production review. +

+
+
+

Submit

+

Listing package

+

+ A listing package gives reviewers enough information to understand the + product, verify ownership and support routes, check content and data use, + and decide whether the app is ready for Quran.com/apps. +

+
+
+

Review

+

Eligibility checks

+

+ Quran Foundation reviews the app in context: usefulness, content handling, + data and consent, product quality, support readiness, commercial model, + AI features, and alignment with user trust. +

+
+
+

Discover

+

Directory and selected visibility

+

+ Approved apps may appear in the Connected Apps directory. Labels, + connected-account flows, and featured placements are additional decisions + with their own requirements. +

+
+
+ +## Eligibility Gates + +Some checks are contextual and weighed in review. These four are not. They are +pass/fail, and they are the baseline protections for users, Quran Foundation, +and the integrity of Quranic content. No app may be listed, receive a reviewed +label, become Connected, or be Featured until all four gates are met. If an app +later falls out of compliance, the same gates govern restriction or removal. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GateMinimum requirementExamples of evidenceIf not met
Content integrity and updatesQuran Foundation-provided Quranic content must be accessed through approved Quran Foundation endpoints or a written license. External Quranic, scholarly, or supporting content must have verifiable rights, accurate attribution, and any category-specific approval required by Quran Foundation. All content must remain current where corrections, removals, restrictions, or source updates apply.API usage, release notes, update cadence, in-app attribution, and license or rights records.Unlisted or delisted until corrected.
Security and privacy baselineA publicly available privacy notice, a reasonable security posture, no harmful or deceptive data practices, and a security or incident contact.Privacy link, security contact, data minimization, and incident-response route.Unlisted or delisted.
API and platform complianceRespects API terms, usage rules, branding rules, and licensing or attribution terms.Accepted partner terms, compliance acknowledgement, and monitored usage.Unlisted or delisted.
Maintenance and responsivenessA named technical contact who can respond to breaking changes within agreed timelines.Support route, issue responsiveness, and maintenance commitment.Unlisted or delisted.
+
+ +:::note +Eligibility is judged on its own terms. A strong marketing presence, large user +base, or popularity does not offset a failed gate. +::: + +## Review Process And Timelines + +Review is a sequence of decisions, not a single approval. Knowing the stages +helps you submit a package that moves quickly. + +1. **Submit**: send a complete listing package, and request API access first if + you need protected APIs. +2. **Completeness check**: reviewers confirm ownership, support routes, content + handling, privacy information, and required listing fields. Incomplete or + unclear packages are returned and slow the process. +3. **Contextual review**: the app is assessed against eligibility gates and the + review criteria on this page. +4. **Decision**: the outcome may be listing approval, a request for changes, or, + where relevant, a label or connected-access decision with its own + requirements. +5. **Live**: approved apps appear in the directory. Labels and featuring are + separate, additional decisions. + +Quran Foundation aims to acknowledge submissions within 1 to 2 business days +and return an initial review within 5 business days of receiving a complete +package. Complex content, OAuth, AI, data, or commercial cases may take longer. +For status, contact [developers@quran.com](mailto:developers@quran.com). + +## What Users See On Quran.com/apps + +The public Quran.com/apps page is designed +for user discovery, not for internal review history. It can show featured apps, +browsable app cards, categories, icons, platform links, taglines, short +descriptions, and labels where a reviewed label applies. + +Directory cards should help users answer five questions quickly: + +
+
+

User questions the listing should answer

+ +
+
+

What a directory card is not

+ +
+
+ +## Visibility Paths And Labels + +Visibility is not a single switch. Directory listing, reviewed labels, account +connection, and featured placement each answer a different user need. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PathWhat Quran Foundation reviewsWhat the app may sayWhat the app must not imply
ListedComplete listing package, working destination links, ownership and support contacts, lawful product, clear purpose, and basic quality fit.The app is listed in the Quran.com Connected Apps directory.Quran Foundation ownership, guaranteed traffic, homepage exposure, or endorsement of every feature.
Verified ListingEligibility gates, approved content sources, clear attribution, and reliable basic UX.The app has completed the checks required for a verified directory listing.A broad guarantee that every product area, future release, or partner claim is approved.
Aligned AppVerified listing checks plus mission alignment and readiness to coordinate on content, API, or deprecation changes.The app has completed the checks described for mission-aligned visibility.Permanent status, exclusive relationship, or Quran Foundation ownership.
Connected AppOAuth readiness, OAuth consent copy, redirect URIs, proportionate scopes, privacy information, data security, incident contact, and support route.The app can connect to approved Quran Foundation account or user-data features.Permission to request unnecessary scopes, bypass consent, or reuse data outside the approved purpose.
Featured AppUser value, quality, timing, audience fit, support readiness, current availability, and suitability for the placement.The app is featured in a specific Quran Foundation surface or campaign while that placement is active.Permanent status, paid advertising, ranking guarantees, or an ownership relationship.
+
+ +## Visibility Tiers In Detail + +Higher levels of visibility, trust, and ecosystem participation are earned +incrementally. Each tier builds on the one below it and never replaces the +eligibility gates. A genuinely valuable app can remain at a lower tier if it has +not implemented the integration the higher tier describes; that is expected, not +a penalty. + +Listed is the baseline directory status. An app may be listed once it has +passed the eligibility gates and listing review. Listing confirms that the app +meets Quran Foundation's baseline requirements for public discovery; it does not +by itself mean the app has completed deeper verification, account-continuity +integration, or editorial review. + +The tiers below are intentionally progressive. They reflect increasing +integration depth, trust, and shared responsibility within the ecosystem. +Partners are encouraged to adopt OAuth2 where account continuity creates +meaningful user value, such as carrying bookmarks, reading progress, notes, +goals, or preferences across participating apps. Content-only apps remain +welcome and can be valuable at the Listed, Verified, or Aligned level. Where an +app has no meaningful account-based experience to connect, Connected status is +not expected. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TierWho it is forIncremental requirementsWhat it grants
Verified Listing
Tier 1
Listed apps seeking confirmation of deeper content and operational readiness.Listed baseline plus confirmed content provenance: approved Quran Foundation APIs or a written license where Quran Foundation content is used, and verifiable rights for approved external content where it is used; clear attribution; verified update and maintenance arrangements; reliable basic UX.Verified label in the directory and eligibility for enhanced discovery opportunities.
Aligned App
Tier 2
Mission-aligned apps that want a closer relationship but are not yet deeply integrated.Tier 1 plus demonstrated mission alignment and clear user value; responsible-use standards; participation in change management for material updates, deprecations, and content corrections.Directory listing plus eligibility for curated ecosystem roundups, relevant partner showcases, and enhanced discovery opportunities.
Connected App
Tier 3
Apps integrating deeply enough to support account continuity across the ecosystem.Tier 2 plus OAuth2 integration and use of user-related APIs for continuity where relevant to the product's user journey. OAuth2 should be implemented where continuity is meaningful, such as carrying bookmarks, progress, notes, goals, or preferences across participating apps; it is not expected where the app has no meaningful account-based experience to connect.Eligibility for enhanced placement and Featured consideration, subject to editorial discretion and current ecosystem priorities.
Featured App
Tier 4, time-boxed
Best-in-class, high-impact apps advancing ecosystem goals.Tier 3 plus demonstrated user value, active collaboration cadence, current availability, and support readiness.Time-boxed Featured placement, at Quran Foundation's editorial discretion, re-evaluated each cycle.
+
+ +Featured status reflects both product quality and ecosystem participation. It +is reserved for Connected Apps that demonstrate sustained user value, +reliability, and active collaboration. Content-only apps remain eligible for +directory discovery, verification, alignment review, and curated editorial +roundups where appropriate. + +Listing is requested through the listing package. Verified, Aligned, and +Connected status are reviewed against the requirements above. Request review via +[developers@quran.com](mailto:developers@quran.com); Developer Console +self-service may follow. Featured placement is selected, not applied for. It is +editorial and time-boxed, though partners may express interest. + +:::caution +Final published criteria for Verified, Aligned, Connected, and Featured status +are being confirmed after the first partner cohort. Until then, treat the rows +above as the working definition. +::: + +## Visibility Is Not For Sale + +Directory placement, reviewed labels, badges, and featured placement are +non-commercial. They cannot be bought, and they cannot be improved through: + +- donations, sponsorship, or paid advertising; +- data-sharing or privileged-access arrangements with Quran Foundation; +- any other commercial relationship. + +Ranking, labels, and featuring reflect eligibility, integration depth, trust, +and demonstrated user value, nothing else. The presence of a fundraising +campaign, for example on a crowdfunding platform, does not by itself disqualify +an app, but fundraising language and campaign behavior must still meet the same +mission, transparency, and responsible-use standards. + +## OAuth And Continuity Requirements + +OAuth2 is what turns a collection of apps into a connected ecosystem. Where an +app meaningfully benefits from continuity of account, bookmarks, reading +progress, notes, goals, or preferences, OAuth2 is required for Connected status +(Tier 3) and above. + +
+ + + + + + + + + + + + + + + + + +
IntegrationRecommended flow
User APIs
Signed-in, per-user data
Authorization Code with PKCE and OpenID Connect; backend token exchange for confidential clients.
Content APIs
Content only, no per-user data
Backend Client Credentials, or the official SDK.
+
+ +- Request the minimum scopes your product needs, and explain the benefit to the + user before consent. +- Content-only apps that do not need cross-app continuity remain eligible for + lower tiers without OAuth2. +- Direct in-app token exchange for public-client handling is permitted only + where Quran Foundation has explicitly confirmed it for your client. +- Scope escalation requires approval. New or expanded user-data access must be + reviewed and approved before release. Where the purpose materially changes, + users must be shown updated consent information and may need to reconnect. + +See the [OAuth2 / OpenID Connect tutorials](/docs/tutorials/oidc/getting-started-with-oauth2/) +and the [OAuth2 Scopes reference](/docs/user_related_apis_versioned/scopes/) +for implementation detail. + +## Listing Package + +A listing package should make the product understandable, reviewable, and safe +to present to users. Incomplete or unclear packages slow down review. + +
+
+

Required for review

+ +
+
+

Recommended for a stronger listing

+ +
+
+ +## Listing Card Specs + +The Quran.com/apps card currently renders an icon, name, short descriptor, +description, categories, and CTA links. The product UI clamps app names and +taglines to one line and descriptions to three lines, so submissions should be +short enough to remain readable across mobile and desktop cards. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldRequiredFormat or limitNotes
App nameYes40 characters maximumExactly as it should appear publicly. Shorter names work better because the card title is one line.
Short descriptor / taglineYes60 characters maximumA few words; descriptive, not promotional. The Quran.com/apps card displays this on one line.
Short descriptionYes1 to 2 sentences, 160 characters maximumExplain what the app does and who it helps. Avoid hype, unverifiable claims, and repeated tagline text.
Icon / logoYesSquare asset, minimum 512 x 512 px, PNG, SVG, or WebPThe card renders icons at approximately 52 x 52 px on desktop and 48 x 48 px on mobile. Use safe contrast, clean edges, and confirmed source rights.
Primary categoryYesOne approved categoryDrives filtering and discovery.
Secondary tagsOptionalApproved taxonomy termsUsed for filtering where helpful.
CTA linksYesValid web, iOS, and/or Android destinationsOnly working, official links should be submitted.
Support contact and public support routeYesPublicly accessible support email or URLOperational accountability.
Privacy policy linkYesPublic URLRequired for review readiness.
Attribution / content-source declarationYesRequired where Quranic, scholarly, or supporting content is usedSee Attribution And Content Sources.
Technical contact / update ownerYesNamed operational contact, supplied privately where not suitable for public displayFor change management and breaking-change response.
Badge / tierIf displayedVerified Listing, Aligned App, Connected App, or Featured AppSet by review, not self-assigned.
+
+ +## Attribution And Content Sources + +- Quran Foundation-provided Quranic content, including text, translations, + tafsir, and recitations, must be accessed through approved Quran Foundation + endpoints or a written license. +- External Quranic, scholarly, or supporting content must have verifiable rights, + accurate attribution, and any additional approval required for its category. +- Display attribution wherever Quranic content is surfaced, both in the product + and in listing copy. +- Provide a content-source declaration in your listing package stating which + Quran Foundation APIs, licensed content, partner content, or other sources the + app uses. +- Keep content current. Corrections, removals, or restrictions made upstream + should be reflected promptly so users are not left with stale material. +- Translations, tafsir editions, and recitations must be credited to their named + source or edition within their licensing terms. + +Use the following attribution when Quran Foundation data is surfaced: + +> Quran data provided by [Quran.Foundation](https://quran.foundation). + +Where translations, tafsir editions, or recitations are surfaced, credit each by +its named source or edition and note that it is sourced through Quran.Foundation +where applicable. + +## Review Criteria + +Review is contextual. The same product can be suitable for a directory listing +but not for OAuth scopes, homepage placement, or a reviewed label. + +
+
+

Mission and usefulness

+

+ Does the product solve a real user need and support Quran reading, + listening, understanding, memorization, reflection, or continuity? +

+
+
+

Content and attribution

+

+ Are Quranic text, translations, tafsir, recitations, and derived content + sourced, represented, kept current, and attributed accurately? +

+
+
+

Data and consent

+

+ Are requested scopes proportionate, explained clearly, secured + appropriately, and limited to the product function? +

+
+
+

Product quality

+

+ Does the product work reliably, avoid avoidable confusion, and provide a + support route for users who need help? +

+
+
+

Commercial model

+

+ Are charges, ads, donations, sponsorships, or affiliate models + transparent, proportionate, and compatible with content obligations? +

+
+
+

Ongoing accountability

+

+ Can the app owner keep listing details current, respond to issues, and + cooperate with reasonable review or corrective action? +

+
+
+ +## User-Facing Clarity + +These expectations are for app owners and partners. Communicate them to users +where they matter: in the app, listing copy, consent screens, privacy notices, +terms, onboarding, support pages, or release notes. + +
+
+

Make clear to users

+ +
+
+

Avoid misleading claims

+ +
+
+ +## Responsible Use + +Products that handle Quranic material, user progress, religious learning, or AI +assistance need extra clarity. Build trust before asking for visibility. + +
+
+

Build toward trust

+ +
+
+

Avoid avoidable harm

+ +
+
+ +### Gamification + +Gamification is acceptable only when it supports sincere, respectful, +non-coercive progress. The goal is gentle encouragement, not spiritual pressure. + +- Helpful patterns include reminders, milestones, memorization support, and + reflection prompts that preserve sincerity and dignity. +- Streaks and badges need caution. They must not shame users, imply spiritual + rank, or create coercive loss-aversion around acts of worship. +- Avoid FOMO-heavy countdowns, manipulative push tactics, vanity leaderboards + for sacred acts, and deceptive scarcity or reward framing that cheapens + religious practice. + +Any mechanic that changes religious behavior, drives social comparison, or +applies emotional pressure should be flagged for review before launch or +featuring. + +### AI Features + +AI features that touch Quranic material, religious learning, or user data carry +the highest trust risk in the ecosystem. The requirements below are hard +requirements, not guidance. They apply whether the AI runs live in the product +or is used to pre-generate content that ships as if curated, such as labels, +verse connections, summaries, or explanations. + +:::caution +**AI must never replace or modify canonical source material.** Quranic Arabic, +named translations, tafsir quotations, and sourced hadith material must be +rendered verbatim from verified Quran Foundation or approved sources. +AI-generated commentary may help users navigate, compare, summarize concepts, or +explain context, but it must be clearly identified, visibly separated from +source material, grounded in real citations where it makes claims, and never +presented as a substitute for, alteration of, or binding interpretation of those +sources. +::: + +**Disclosure and separation** + +- **Disclose generated output.** Clearly indicate when an answer or explanation + is AI-generated, so users never mistake it for verified source material. +- **Separate source from explanation.** Visibly distinguish retrieved source + material, such as verse text, translation, tafsir, or hadith, from any + AI-generated explanation around it. Do not present the two as the same kind of + authority. + +**Provenance** + +- **Cite claims.** Where an AI feature makes a Quranic or scholarly claim, show + the citation or source link it rests on. +- **Use real citations.** Any reference must resolve to a genuine, verifiable + source. Fabricated, approximate, or unverifiable citations are a violation. + +**Authority and neutrality** + +- **Do not present AI as religious authority.** AI output must not be presented + as binding religious authority, and must not issue fatwas, halal or haram + verdicts, or personalized religious directives. +- **Stay neutral on contested matters.** On sectarian or madhhab-sensitive + questions, AI must not assert a single position as the Islamic view. It should + defer to qualified scholars or present recognized views without endorsing one. +- Do not describe AI output as "verified," "scholarship," or equivalent unless + it has actually been through the corresponding human or scholarly review. + +**Human oversight** + +- **Review curated AI content before publishing.** AI content that ships as part + of the product should be human-reviewed before publication. +- **Scale review to risk.** Generated content making substantive interpretive, + legal, theological, or sectarian claims requires review appropriate to its + risk, including qualified scholarly review where necessary. + +**Grounding** + +- **Use the grounding rails.** Apps using Quran Foundation MCP or AI tooling + must follow the current published grounding, attribution, and safety + requirements for that integration. + +**Data and providers** + +- **Do not train on protected data.** Do not train models on Quran Foundation + user data or restricted content without written permission. +- **Disclose third-party processing.** Where user data is processed by model + providers, disclose that processing, minimize prompt data, configure providers + not to retain or train on that data, and name material subprocessors. +- **Disclose material changes.** Disclose material model or provider changes + where user data is processed. + +**Safety** + +- **Hard content lines.** AI features must not produce content that + misrepresents Islam, promotes extremism, or incites sectarian hatred. In a + sacred context, this is a hard line. + +**Accountability** + +- **Provide accountability.** Give users a way to report inaccurate or + inappropriate AI output, and maintain an owner-side process to review and + correct it. + +## Changes That Can Require Re-Review + +Keep listing, privacy, support, and integration details current. Material +changes can require updated review before continued listing, labels, scopes, or +featured placement. + +
+
+

Product or ownership changes

+

+ New owner, major repositioning, discontinued support, broken destination + links, or a change in the primary user experience. +

+
+
+

Data or permission changes

+

+ New OAuth scopes, expanded user-data use, changed consent copy, new + processors, or security and incident-response changes. +

+
+
+

Content or AI changes

+

+ New Quranic sources, generated religious content, AI explanations, model + or provider changes where user data is processed, attribution changes, or + mixing reviewed sources with unreviewed output. +

+
+
+

Commercial changes

+

+ New ads, subscriptions, purchases, donations, sponsorships, affiliate + links, or paid access around Quranic content or user features. +

+
+
+

Listing changes

+

+ New claims, screenshots, categories, platform links, app descriptions, or + relationship statements shown to Quran.com users. +

+
+
+

Visibility changes

+

+ Quran Foundation may update, pause, or remove directory visibility, + labels, connected access, or featured placement when requirements are no + longer met. +

+
+
+ +## Enforcement And Reinstatement + +Enforcement is transparent, documented, and proportional, while remaining +capable of swift action for serious harm. Issues are handled along a defined +ladder: + +1. **Notice**: Quran Foundation notifies the app owner of the issue and records + the concern. +2. **Remediation window**: Quran Foundation sets a timeline to fix the issue, + based on severity. +3. **Visibility restriction**: if unresolved, the app may lose its badge, + placement, featuring, category visibility, or connected access. +4. **Suspension or delisting**: serious or repeated breaches can lead to removal + from the directory and revocation of access where appropriate. +5. **Reinstatement**: visibility or access may be restored after evidence of + correction, completion of review, and where relevant re-testing or scholarly + sign-off. + +Serious user harm, security incidents, or misrepresentation may move directly to +restriction or suspension. To respond to a notice or request reinstatement, +contact [developers@quran.com](mailto:developers@quran.com). + +**Reconsideration.** A partner may request clarification or reconsideration by +submitting updated evidence to [developers@quran.com](mailto:developers@quran.com). +Decisions involving user safety, content integrity, security, or legal +obligations remain at Quran Foundation's discretion. + +## Directory Listing And Homepage Placement + +Being listed in Connected Apps and being promoted on the Quran.com homepage are +related but separate. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QuestionConnected Apps directoryQuran.com homepage
PurposeHelp users browse and evaluate relevant Quran-related apps.Introduce a broad audience to a selected, high-confidence experience.
Default expectationEligible reviewed apps can be listed with categories and platform links.Placement is selective, time-sensitive, and not guaranteed by listing approval.
Data shapeDirectory cards can include title, tagline, description, icon, categories, relationship type, and platform links.Homepage cards should be fewer, concise, current, and appropriate for broad Quran.com traffic.
Change controlListing details should stay current and may be paused when required.Placement can change based on review, quality, editorial priorities, timing, or product status.
+
+ +## Support And Office Hours + +- **General questions**: for access, scopes, listing readiness, or review + status, contact [developers@quran.com](mailto:developers@quran.com). +- **Partner office hours**: available at various times throughout the week, + updated regularly as slots open or close. Book a slot through the + [office-hours calendar](https://calendar.app.google/hxLjubo5LR1iHjiDA) for + help with onboarding, OAuth, or listing review. +- **Response expectations**: Quran Foundation aims to respond to partner queries + within 1 to 2 business days. + +## Recommended Next Steps + +
+
+

New integration

+

Request access

+

Get credentials, redirect URI review, and scope guidance before implementation.

+ Open Request Access +
+
+

Choosing APIs

+

Developer Journey

+

Choose Content APIs, Search APIs, User APIs, OAuth2, or SDK docs by app shape.

+ Open Developer Journey +
+
+

Signed-in apps

+

User APIs Quickstart

+

Build OAuth-backed bookmarks, notes, reading sessions, goals, and preferences.

+ Open User APIs Quickstart +
+
+ +## FAQ + +
+ Can my app charge for a service? +

+ Potentially. Monetization is evaluated in context. The product should + provide genuine user value, describe charges honestly, respect content + obligations, and avoid using Quranic material as a superficial marketing + vehicle. Commercial content use may require separate written permission. +

+
+ +
+ Can we show ads or accept donations? +

+ Possible models should be transparent, proportionate, and respectful of the + user experience. Intrusive, deceptive, or contextually inappropriate + promotion can affect eligibility or visibility. +

+
+ +
+ Does every listed app need OAuth? +

+ No. OAuth is most important where Quran Foundation account continuity, + personal user data, or signed-in user actions are central. Where OAuth is + used, the app should request only the permissions it truly needs and explain + the benefit before consent. +

+
+ +
+ Is a directory card an endorsement? +

+ No. A listing helps users discover an independent product. It does not mean + Quran Foundation owns the app, provides its support, or endorses every + current and future feature. A badge or label applies only to the checks + described for that badge or label. +

+
+ +
+ What is the difference between an app partner and a content partner? +

+ App partners build user-facing experiences and are reviewed for product, + data, support, and ecosystem fit. Content partners can have additional + source, rights, attribution, licensing, and usage considerations. The review + tracks should be distinct when those obligations differ. +

+
+ +For questions about access, scopes, listing readiness, or review status, contact +[developers@quran.com](mailto:developers@quran.com). + +## Change Log + +Material changes to this page, especially to terms, licensing, monetization, AI +requirements, labels, and enforcement, are recorded here. Existing partners are +notified by email to registered partner contacts when changes materially affect +eligibility, visibility, data access, attribution, AI requirements, enforcement, +or compliance obligations. Unless Quran Foundation needs to act sooner for +security, legal, user-safety, or content-integrity reasons, material changes +take effect after a 14-day notice period. + +| Version | Date | Material changes | +| --- | --- | --- | +| 1.0 | 2026-06-30 | Initial publication. | diff --git a/docusaurus.config.js b/docusaurus.config.js index ced11fe9..633c9964 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -200,6 +200,12 @@ const config = { position: "left", label: "Updates", }, + { + type: "doc", + docId: "connected-apps", + position: "left", + label: "Connected Apps", + }, { type: "docSidebar", @@ -233,7 +239,6 @@ const config = { ], }, { - sidebarId: "APIsSidebar", type: "dropdown", label: "APIs", position: "left", diff --git a/package.json b/package.json index dd0cf7cd..d30472d3 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "deploy:pages": "yarn run build && wrangler pages deploy build", "docusaurus": "npx docusaurus", "llms:sync": "node scripts/sync-static-llms-txt.js", - "test": "node --test \"tests/**/*.test.cjs\"", + "test": "node scripts/run-tests.cjs", "audit:search-console:local": "node scripts/audit-search-console-coverage.js --mode=local", "audit:search-console:live": "node scripts/audit-search-console-coverage.js --mode=live", "postbuild:seo": "node scripts/postbuild-seo.js", diff --git a/plugins/llms-txt-plugin.js b/plugins/llms-txt-plugin.js index c111871f..cfda7e42 100644 --- a/plugins/llms-txt-plugin.js +++ b/plugins/llms-txt-plugin.js @@ -55,6 +55,7 @@ const SECTION_ORDER = [ const URL_PRIORITY = [ `${BASE_URL}/docs/developer-journey/`, + `${BASE_URL}/docs/connected-apps/`, `${BASE_URL}/docs/api-reference/`, `${BASE_URL}/docs/tutorials/oidc/starter-with-npx/`, `${BASE_URL}/docs/sdk/javascript/`, @@ -104,6 +105,7 @@ const OPENAPI_HEADER = [ '- [QF_REVIEW_EXISTING_INTEGRATION_PROMPT_V1](https://api-docs.quran.foundation/agent-prompts/qf-review-existing-integration.md): Copyable prompt for auditing an existing Quran Foundation integration', '- [Agent prompt registry](https://api-docs.quran.foundation/.well-known/agent-prompts/index.json): Machine-readable prompt catalog', '- [Developer Journey](https://api-docs.quran.foundation/docs/developer-journey/): Choose the right starting point by app shape', + '- [Connected Apps](https://api-docs.quran.foundation/docs/connected-apps/): Partner guide for app discovery, listing review, visibility, and responsible integration', '- [API Reference](https://api-docs.quran.foundation/docs/api-reference/): Choose between Content, Search, User APIs, OAuth2, and pre-live endpoint references', '- [Starter With NPX](https://api-docs.quran.foundation/docs/tutorials/oidc/starter-with-npx/): One-command Next.js app scaffold', '- [JavaScript SDK](https://api-docs.quran.foundation/docs/sdk/javascript/): Runtime-split SDK guidance for public and server code', diff --git a/scripts/run-tests.cjs b/scripts/run-tests.cjs new file mode 100644 index 00000000..20bbd583 --- /dev/null +++ b/scripts/run-tests.cjs @@ -0,0 +1,36 @@ +const { spawnSync } = require('node:child_process'); +const fs = require('node:fs'); +const path = require('node:path'); + +const repoRoot = path.join(__dirname, '..'); +const testsDir = path.join(repoRoot, 'tests'); + +const collectTestFiles = (dir) => { + const entries = fs.readdirSync(dir, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + const entryPath = path.join(dir, entry.name); + + if (entry.isDirectory()) { + files.push(...collectTestFiles(entryPath)); + } else if (/\.test\.cjs$/u.test(entry.name)) { + files.push(entryPath); + } + } + + return files; +}; + +const testFiles = collectTestFiles(testsDir).sort(); + +if (testFiles.length === 0) { + console.error('No test files found under tests/**/*.test.cjs'); + process.exit(1); +} + +const result = spawnSync(process.execPath, ['--test', ...testFiles], { + stdio: 'inherit', +}); + +process.exit(result.status ?? 1); diff --git a/sidebars.js b/sidebars.js index 3e9e492a..7daaa9b7 100644 --- a/sidebars.js +++ b/sidebars.js @@ -624,6 +624,11 @@ const makeSharedDocsSidebar = (apiFamilies) => [ id: "developer-journey", label: "Developer Journey", }, + { + type: "doc", + id: "connected-apps", + label: "Connected Apps", + }, { type: "doc", id: "ai-agents/index", diff --git a/src/css/custom.css b/src/css/custom.css index bf0d8eac..c369afb6 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -451,3 +451,271 @@ a.navbar__item--request-access:hover { transform: translateY(-1px); box-shadow: var(--qf-shadow-md); } + +/* Connected Apps guide */ +.connectedAppsDoc { + --connected-apps-border: var(--qf-border-card); + --connected-apps-soft: rgba(62, 193, 201, 0.08); + --connected-apps-soft-strong: rgba(62, 193, 201, 0.14); +} + +.connectedAppsVersion { + display: flex; + flex-wrap: wrap; + gap: 0.35rem 0.75rem; + margin: -0.4rem 0 1rem; + color: var(--qf-text-muted); + font-size: 0.82rem; +} + +.connectedAppsHero { + margin: 0 0 1.25rem; + padding: 1.5rem; + border: 1px solid var(--connected-apps-border, var(--qf-border-card)); + border-radius: var(--qf-radius-xl); + background: + linear-gradient(135deg, var(--connected-apps-soft, rgba(62, 193, 201, 0.08)), transparent 68%), + var(--ifm-background-surface-color); + box-shadow: var(--qf-shadow-sm); +} + +.connectedAppsEyebrow, +.connectedAppsCardKicker { + margin: 0 0 0.35rem; + color: var(--ifm-color-primary-dark); + font-size: 0.75rem; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.connectedAppsHero h2 { + margin: 0; + color: var(--ifm-heading-color); + font-size: clamp(1.75rem, 4vw, 2.55rem); + line-height: 1.12; +} + +.connectedAppsHero p:not(.connectedAppsEyebrow) { + max-width: 46rem; + margin: 0.85rem 0 0; + color: var(--ifm-color-emphasis-800); + font-size: 1rem; + line-height: 1.65; +} + +.connectedAppsHeroActions { + display: flex; + flex-wrap: wrap; + gap: 0.65rem; + margin-top: 1rem; +} + +.connectedAppsPrimaryLink, +.connectedAppsSecondaryLink { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 2.35rem; + padding: 0.5rem 0.9rem; + border-radius: var(--ifm-global-radius); + font-size: 0.88rem; + font-weight: 800; + text-decoration: none; +} + +.connectedAppsPrimaryLink { + background: var(--ifm-color-primary); + color: #ffffff; +} + +.connectedAppsPrimaryLink:hover { + background: var(--ifm-color-primary-dark); + color: #ffffff; + text-decoration: none; +} + +.connectedAppsSecondaryLink { + border: 1px solid var(--connected-apps-border, var(--qf-border-card)); + color: var(--ifm-color-primary-dark); + background: var(--ifm-background-color); +} + +.connectedAppsSecondaryLink:hover { + color: var(--ifm-color-primary-darker); + text-decoration: none; +} + +.connectedAppsPillRow { + display: flex; + flex-wrap: wrap; + gap: 0.45rem; + margin-top: 1rem; +} + +.connectedAppsPill { + display: inline-flex; + align-items: center; + border: 1px solid var(--connected-apps-border, var(--qf-border-card)); + border-radius: 999px; + padding: 0.28rem 0.6rem; + color: var(--ifm-color-primary-dark); + background: var(--ifm-background-color); + font-size: 0.76rem; + font-weight: 800; +} + +.connectedAppsCallout { + margin: 1rem 0 1.25rem; + padding: 0.9rem 1rem; + border: 1px solid rgba(62, 193, 201, 0.32); + border-left: 4px solid var(--ifm-color-primary); + border-radius: 0 var(--qf-radius-lg) var(--qf-radius-lg) 0; + background: var(--connected-apps-soft, rgba(62, 193, 201, 0.08)); + color: var(--ifm-color-emphasis-800); + line-height: 1.55; +} + +.connectedAppsGrid { + display: grid; + gap: 0.85rem; + margin: 1rem 0 1.35rem; +} + +.connectedAppsGridTwo { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.connectedAppsGridThree { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.connectedAppsCard { + min-width: 0; + padding: 1rem; + border: 1px solid var(--connected-apps-border, var(--qf-border-card)); + border-radius: var(--qf-radius-lg); + background: var(--ifm-background-surface-color); + box-shadow: var(--qf-shadow-sm); +} + +.connectedAppsCard h3 { + margin: 0; + color: var(--ifm-heading-color); + font-size: 1.05rem; + line-height: 1.3; +} + +.connectedAppsCard p, +.connectedAppsCard li { + color: var(--ifm-color-emphasis-800); + font-size: 0.9rem; + line-height: 1.55; +} + +.connectedAppsCard p { + margin: 0.5rem 0 0; +} + +.connectedAppsCard > a { + display: inline-flex; + margin-top: 0.7rem; + font-size: 0.88rem; + font-weight: 800; +} + +.connectedAppsCard p a, +.connectedAppsCard li a { + display: inline; + margin-top: 0; + font-size: inherit; + font-weight: 800; +} + +.connectedAppsNumber { + display: grid; + width: 1.65rem; + height: 1.65rem; + margin-bottom: 0.65rem; + place-items: center; + border-radius: 8px; + color: var(--ifm-color-primary-dark); + background: var(--connected-apps-soft-strong, rgba(62, 193, 201, 0.14)); + font-size: 0.76rem; + font-weight: 800; +} + +.connectedAppsChecklist { + margin: 0.65rem 0 0; + padding-left: 1.15rem; +} + +.connectedAppsChecklist li + li { + margin-top: 0.35rem; +} + +.connectedAppsTableWrap { + margin: 1rem 0 1.5rem; + overflow-x: auto; + border: 1px solid var(--connected-apps-border, var(--qf-border-card)); + border-radius: var(--qf-radius-lg); + background: var(--ifm-background-surface-color); +} + +.connectedAppsTable { + width: 100%; + min-width: 760px; + border-collapse: collapse; + font-size: 0.88rem; +} + +.connectedAppsTable th, +.connectedAppsTable td { + padding: 0.8rem; + border-bottom: 1px solid var(--connected-apps-border, var(--qf-border-card)); + text-align: left; + vertical-align: top; +} + +.connectedAppsTable th { + color: var(--qf-text-muted); + background: var(--ifm-color-emphasis-100); + font-size: 0.73rem; + font-weight: 800; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.connectedAppsTable tr:last-child td { + border-bottom: 0; +} + +[data-theme='dark'] .connectedAppsEyebrow, +[data-theme='dark'] .connectedAppsCardKicker, +[data-theme='dark'] .connectedAppsPill, +[data-theme='dark'] .connectedAppsSecondaryLink, +[data-theme='dark'] .connectedAppsNumber { + color: var(--ifm-color-primary-light); +} + +@media screen and (max-width: 996px) { + .connectedAppsGridThree { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media screen and (max-width: 760px) { + .connectedAppsHero { + padding: 1.1rem; + } + + .connectedAppsGridTwo, + .connectedAppsGridThree { + grid-template-columns: 1fr; + } + + .connectedAppsPrimaryLink, + .connectedAppsSecondaryLink { + width: 100%; + } +} diff --git a/static/.well-known/mcp/server-card.json b/static/.well-known/mcp/server-card.json index c3f363a2..f7cabc55 100644 --- a/static/.well-known/mcp/server-card.json +++ b/static/.well-known/mcp/server-card.json @@ -45,6 +45,13 @@ "description": "Starting-point guide for choosing between the starter app, Content APIs, User APIs, OAuth2, and API reference docs.", "mimeType": "text/html" }, + { + "name": "connected_apps", + "title": "Connected Apps", + "uri": "https://api-docs.quran.foundation/docs/connected-apps/", + "description": "Partner guide for Quran Foundation app discovery, listing review, visibility, and responsible integration.", + "mimeType": "text/html" + }, { "name": "api_reference", "title": "API Reference", diff --git a/static/llms.txt b/static/llms.txt index 5ce79dee..27db2f12 100644 --- a/static/llms.txt +++ b/static/llms.txt @@ -20,6 +20,7 @@ - [QF_REVIEW_EXISTING_INTEGRATION_PROMPT_V1](https://api-docs.quran.foundation/agent-prompts/qf-review-existing-integration.md): Copyable prompt for auditing an existing Quran Foundation integration - [Agent prompt registry](https://api-docs.quran.foundation/.well-known/agent-prompts/index.json): Machine-readable prompt catalog - [Developer Journey](https://api-docs.quran.foundation/docs/developer-journey/): Choose the right starting point by app shape +- [Connected Apps](https://api-docs.quran.foundation/docs/connected-apps/): Partner guide for app discovery, listing review, visibility, and responsible integration - [API Reference](https://api-docs.quran.foundation/docs/api-reference/): Choose between Content, Search, User APIs, OAuth2, and pre-live endpoint references - [Starter With NPX](https://api-docs.quran.foundation/docs/tutorials/oidc/starter-with-npx/): One-command Next.js app scaffold - [JavaScript SDK](https://api-docs.quran.foundation/docs/sdk/javascript/): Runtime-split SDK guidance for public and server code @@ -48,28 +49,27 @@ - [Full-Stack Quickstart](https://api-docs.quran.foundation/docs/sdk/javascript/full-stack/) - [Common Errors](https://api-docs.quran.foundation/docs/sdk/javascript/common-errors/) - [Migration Cheat Sheet](https://api-docs.quran.foundation/docs/sdk/javascript/migration-cheat-sheet/) +- [Authentication](https://api-docs.quran.foundation/docs/sdk/python/authentication/) +- [Content API Helpers](https://api-docs.quran.foundation/docs/sdk/python/content/) +- [Search API](https://api-docs.quran.foundation/docs/sdk/python/search/) +- [User APIs](https://api-docs.quran.foundation/docs/sdk/python/user-apis/) +- [Common Errors](https://api-docs.quran.foundation/docs/sdk/python/common-errors/) - [Answers API](https://api-docs.quran.foundation/docs/sdk/javascript/answers/) - [Answers API](https://api-docs.quran.foundation/docs/sdk/python/answers/) - [Audio API](https://api-docs.quran.foundation/docs/sdk/javascript/audio/) - [Audio API](https://api-docs.quran.foundation/docs/sdk/python/audio/) -- [Authentication](https://api-docs.quran.foundation/docs/sdk/python/authentication/) - [Chapters API](https://api-docs.quran.foundation/docs/sdk/javascript/chapters/) - [Chapters API](https://api-docs.quran.foundation/docs/sdk/python/chapters/) -- [Common Errors](https://api-docs.quran.foundation/docs/sdk/python/common-errors/) -- [Content API Helpers](https://api-docs.quran.foundation/docs/sdk/python/content/) - [Hadith References API](https://api-docs.quran.foundation/docs/sdk/javascript/hadith-references/) - [Hadith References API](https://api-docs.quran.foundation/docs/sdk/python/hadith-references/) - [Juzs API](https://api-docs.quran.foundation/docs/sdk/javascript/juzs/) - [Juzs API](https://api-docs.quran.foundation/docs/sdk/python/juzs/) - [Legacy Migration Guide](https://api-docs.quran.foundation/docs/sdk/javascript/v1-migration-guide/) -- [Python SDK](https://api-docs.quran.foundation/docs/sdk/python/) - [QuranReflect Posts](https://api-docs.quran.foundation/docs/sdk/javascript/quranreflect-posts/) - [Resources API](https://api-docs.quran.foundation/docs/sdk/javascript/resources/) - [Resources API](https://api-docs.quran.foundation/docs/sdk/python/resources/) - [SDKs](https://api-docs.quran.foundation/docs/sdk/) - [Search API](https://api-docs.quran.foundation/docs/sdk/javascript/search/) -- [Search API](https://api-docs.quran.foundation/docs/sdk/python/search/) -- [User APIs](https://api-docs.quran.foundation/docs/sdk/python/user-apis/) - [Verses API](https://api-docs.quran.foundation/docs/sdk/javascript/verses/) - [Verses API](https://api-docs.quran.foundation/docs/sdk/python/verses/) diff --git a/tests/connected-apps-docs.test.cjs b/tests/connected-apps-docs.test.cjs new file mode 100644 index 00000000..72476a2e --- /dev/null +++ b/tests/connected-apps-docs.test.cjs @@ -0,0 +1,226 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); + +const repoRoot = path.join(__dirname, '..'); +const docsDir = path.join(repoRoot, 'docs'); +const docPath = path.join(docsDir, 'connected-apps.mdx'); +const doc = fs.readFileSync(docPath, 'utf8'); +const customCss = fs.readFileSync( + path.join(repoRoot, 'src', 'css', 'custom.css'), + 'utf8', +); +const packageJson = require(path.join(repoRoot, 'package.json')); +const sidebars = require(path.join(repoRoot, 'sidebars.js')); +const docusaurusConfig = require(path.join(repoRoot, 'docusaurus.config.js')); +const { generateLlmsTxt } = require(path.join( + repoRoot, + 'plugins', + 'llms-txt-plugin.js', +)); + +const findSidebarDoc = (sidebarName, docId) => { + const sidebar = sidebars[sidebarName]; + assert.ok(sidebar, `expected ${sidebarName} to exist`); + + return sidebar.find( + (item) => item && item.type === 'doc' && item.id === docId, + ); +}; + +test('adds a production Connected Apps docs page', () => { + assert.match(doc, /^title: "Connected Apps"$/m); + assert.match(doc, /^sidebar_label: "Connected Apps"$/m); + assert.match(doc, /^displayed_sidebar: "APIsSidebar"$/m); + + for (const prototypeOnlyText of [ + 'Atlas Docs Hub', + 'Concept 01', + 'body.dark', + 'mobile-nav', + 'Quran.Foundation / Connected Apps', + 'Boundaries to communicate', + 'Internal visibility controls', + 'teams need', + 'source of truth', + 'promoting apps', + 'planned partner workspace', + 'not just a page of links', + 'when enabled', + ]) { + assert.doesNotMatch( + doc, + new RegExp(prototypeOnlyText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')), + `expected page to exclude prototype-only text: ${prototypeOnlyText}`, + ); + } + + assert.doesNotMatch( + doc, + /\[FILL:|ƒ|Â|â|�/, + 'expected production page to exclude placeholders and mojibake', + ); +}); + +test('documents the core Connected Apps production concepts', () => { + const requiredPatterns = [ + /Policy version:<\/strong> 1\.0/, + /Last updated: 2026-06-30/, + /Effective date: 2026-06-30/, + /listing package/i, + /review criteria/i, + /Developer Console/, + /Request Access/, + /homepage/i, + /directory/i, + /does not mean Quran Foundation owns/, + /Do not describe a directory listing as broad endorsement/, + /Quran\.com\/apps/, + /OAuth consent/i, + /User-Facing Clarity/, + /Communicate them to users/, + /Changes That Can Require Re-Review/, + /Commercial changes/, + /AI explanations/, + /developers@quran\.com/, + /Eligibility Gates/, + /pass\/fail,\s+and they are the baseline protections/, + /No app may be listed, receive a reviewed\s+label, become Connected, or be Featured/, + /Visibility Tiers In Detail/, + /Higher levels of visibility, trust, and ecosystem participation/, + /Listed is the baseline directory status/, + /Verified Listing/, + /Aligned App/, + /Connected App/, + /Featured App/, + /Final published criteria for Verified, Aligned, Connected, and Featured status/, + /Visibility Is Not For Sale/, + /OAuth And Continuity Requirements/, + /Partner Terms And Compliance/, + /Quran\.com Terms & Conditions/, + /Quran Foundation Developer Terms/, + /Listing Card Specs/, + /40 characters maximum/, + /60 characters maximum/, + /160 characters maximum/, + /minimum 512 x 512 px/, + /Attribution And Content Sources/, + /Quran data provided by \[Quran\.Foundation\]\(https:\/\/quran\.foundation\)/, + /Gamification/, + /AI must never replace or modify canonical source material/, + /Scale review to risk/, + /Use the grounding rails/, + /Enforcement And Reinstatement/, + /Support And Office Hours/, + /Partner office hours[\s\S]*available at various times throughout the week/, + /Change Log/, + /14-day notice period/, + ]; + + for (const pattern of requiredPatterns) { + assert.match(doc, pattern); + } +}); + +test('places eligibility gates before review process', () => { + const howItWorksIndex = doc.indexOf('## How Connected Apps Works'); + const eligibilityIndex = doc.indexOf('## Eligibility Gates'); + const reviewProcessIndex = doc.indexOf('## Review Process And Timelines'); + const reviewCriteriaIndex = doc.indexOf('## Review Criteria'); + + assert.ok(howItWorksIndex >= 0, 'expected How Connected Apps Works heading'); + assert.ok(eligibilityIndex >= 0, 'expected Eligibility Gates heading'); + assert.ok(reviewProcessIndex >= 0, 'expected Review Process heading'); + assert.ok(reviewCriteriaIndex >= 0, 'expected Review Criteria heading'); + assert.ok( + howItWorksIndex < eligibilityIndex, + 'expected Eligibility Gates after How Connected Apps Works', + ); + assert.ok( + eligibilityIndex < reviewProcessIndex, + 'expected Eligibility Gates before Review Process And Timelines', + ); + assert.ok( + reviewProcessIndex < reviewCriteriaIndex, + 'expected Review Criteria after the process explanation', + ); +}); + +test('uses Docusaurus Link for internal Connected Apps routes', () => { + assert.match(doc, /import Link from '@docusaurus\/Link';/); + assert.doesNotMatch( + doc, + /]*href="\//, + 'internal routes in MDX JSX blocks should use Docusaurus Link', + ); + assert.match(doc, //); + assert.match(doc, //); + assert.match(doc, /href="#listing-package"/); + assert.match(doc, /href="https:\/\/quran\.com\/apps"/); +}); + +test('surfaces Connected Apps in navbar and shared sidebars', () => { + const navbarItems = docusaurusConfig.themeConfig.navbar.items; + const updatesIndex = navbarItems.findIndex( + (item) => item.type === 'doc' && item.docId === 'updates/index', + ); + const connectedAppsIndex = navbarItems.findIndex( + (item) => item.type === 'doc' && item.docId === 'connected-apps', + ); + + assert.ok(updatesIndex >= 0, 'expected Updates navbar item'); + assert.equal( + connectedAppsIndex, + updatesIndex + 1, + 'expected Connected Apps directly after Updates', + ); + assert.equal(navbarItems[connectedAppsIndex].label, 'Connected Apps'); + + const apisDropdown = navbarItems.find( + (item) => item.type === 'dropdown' && item.label === 'APIs', + ); + assert.ok(apisDropdown, 'expected APIs dropdown'); + assert.equal( + Object.hasOwn(apisDropdown, 'sidebarId'), + false, + 'dropdown navbar items should not pass sidebarId through to the DOM', + ); + + for (const sidebarName of ['APIsSidebar', 'APIsVersionedSidebar']) { + assert.deepEqual(findSidebarDoc(sidebarName, 'connected-apps'), { + type: 'doc', + id: 'connected-apps', + label: 'Connected Apps', + }); + } +}); + +test('includes Connected Apps in generated llms.txt discovery', () => { + const { content } = generateLlmsTxt(docsDir); + + assert.match( + content, + /\[Connected Apps\]\(https:\/\/api-docs\.quran\.foundation\/docs\/connected-apps\/\): Partner guide/, + ); +}); + +test('keeps Connected Apps styling scoped, theme-token based, and responsive', () => { + assert.match(customCss, /\.connectedAppsDoc\s*{/); + assert.match(customCss, /\.connectedAppsVersion\s*{/); + assert.match(customCss, /\.connectedAppsCard\s*>\s*a\s*{/); + assert.match(customCss, /\.connectedAppsCard p a,\s*\.connectedAppsCard li a\s*{/); + assert.doesNotMatch(customCss, /--connected-apps-muted/); + assert.match(customCss, /var\(--connected-apps-border, var\(--qf-border-card\)\)/); + assert.match(customCss, /var\(--connected-apps-soft, rgba\(62, 193, 201, 0\.08\)\)/); + assert.match(customCss, /@media screen and \(max-width: 760px\)[\s\S]*\.connectedAppsGridTwo,\s*\.connectedAppsGridThree\s*{\s*grid-template-columns: 1fr;/); + assert.match(customCss, /@media screen and \(max-width: 760px\)[\s\S]*\.connectedAppsPrimaryLink,\s*\.connectedAppsSecondaryLink\s*{\s*width: 100%;/); +}); + +test('uses the cross-platform test runner wrapper', () => { + assert.equal(packageJson.scripts.test, 'node scripts/run-tests.cjs'); + assert.ok( + fs.existsSync(path.join(repoRoot, 'scripts', 'run-tests.cjs')), + 'expected test runner wrapper to exist', + ); +}); diff --git a/tests/mcp-server-card.test.cjs b/tests/mcp-server-card.test.cjs index bf42093d..2ee44c8b 100644 --- a/tests/mcp-server-card.test.cjs +++ b/tests/mcp-server-card.test.cjs @@ -54,6 +54,9 @@ test('includes curated onboarding pages alongside API resources', () => { assert.ok( resourceUris.has('https://api-docs.quran.foundation/docs/quickstart/'), ); + assert.ok( + resourceUris.has('https://api-docs.quran.foundation/docs/connected-apps/'), + ); assert.ok( resourceUris.has( 'https://api-docs.quran.foundation/docs/tutorials/oidc/getting-started-with-oauth2/',