├── .commitlintrc.ts ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── BUG_REPORT.yml │ └── FEATURE_REQUEST.yml ├── PULL_REQUEST_TEMPLATE.md ├── filters.yml └── workflows │ ├── commitlint.yml │ ├── issues_dailyCron.yml │ ├── issues_handleLabel.yml │ └── tests.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .lintstagedrc ├── .prettierignore ├── .prettierrc.js ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── demo ├── .strapi-app │ ├── .env.example │ ├── .gitignore │ ├── README.md │ ├── config │ │ ├── admin.ts │ │ ├── api.ts │ │ ├── database.ts │ │ ├── middlewares.ts │ │ ├── plugins.ts │ │ └── server.ts │ ├── data │ │ ├── data.json │ │ └── uploads │ │ │ ├── a-bug-is-becoming-a-meme-on-the-internet.jpg │ │ │ ├── beautiful-picture.jpg │ │ │ ├── coffee-art.jpg │ │ │ ├── coffee-beans.jpg │ │ │ ├── coffee-shadow.jpg │ │ │ ├── daviddoe@strapi.io.jpg │ │ │ ├── default-image.png │ │ │ ├── favicon.png │ │ │ ├── sarahbaker@strapi.io.jpg │ │ │ ├── the-internet-s-own-boy.jpg │ │ │ ├── this-shrimp-is-awesome.jpg │ │ │ ├── we-love-pizza.jpg │ │ │ └── what-s-inside-a-black-hole.jpg │ ├── database │ │ └── migrations │ │ │ └── .gitkeep │ ├── favicon.png │ ├── package.json │ ├── pnpm-lock.yaml │ ├── public │ │ ├── robots.txt │ │ └── uploads │ │ │ └── .gitkeep │ ├── scripts │ │ └── seed.js │ ├── src │ │ ├── admin │ │ │ ├── app.example.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.example.ts │ │ ├── api │ │ │ ├── .gitkeep │ │ │ ├── about │ │ │ │ ├── content-types │ │ │ │ │ └── about │ │ │ │ │ │ └── schema.json │ │ │ │ ├── controllers │ │ │ │ │ └── about.ts │ │ │ │ ├── routes │ │ │ │ │ └── about.ts │ │ │ │ └── services │ │ │ │ │ └── about.ts │ │ │ ├── article │ │ │ │ ├── content-types │ │ │ │ │ └── article │ │ │ │ │ │ └── schema.json │ │ │ │ ├── controllers │ │ │ │ │ └── article.ts │ │ │ │ ├── routes │ │ │ │ │ └── article.ts │ │ │ │ └── services │ │ │ │ │ └── article.ts │ │ │ ├── author │ │ │ │ ├── content-types │ │ │ │ │ └── author │ │ │ │ │ │ └── schema.json │ │ │ │ ├── controllers │ │ │ │ │ └── author.ts │ │ │ │ ├── routes │ │ │ │ │ └── author.ts │ │ │ │ └── services │ │ │ │ │ └── author.ts │ │ │ ├── category │ │ │ │ ├── content-types │ │ │ │ │ └── category │ │ │ │ │ │ └── schema.json │ │ │ │ ├── controllers │ │ │ │ │ └── category.ts │ │ │ │ ├── routes │ │ │ │ │ └── category.ts │ │ │ │ └── services │ │ │ │ │ └── category.ts │ │ │ └── global │ │ │ │ ├── content-types │ │ │ │ └── global │ │ │ │ │ └── schema.json │ │ │ │ ├── controllers │ │ │ │ └── global.ts │ │ │ │ ├── routes │ │ │ │ └── global.ts │ │ │ │ └── services │ │ │ │ └── global.ts │ │ ├── components │ │ │ └── shared │ │ │ │ ├── media.json │ │ │ │ ├── quote.json │ │ │ │ ├── rich-text.json │ │ │ │ ├── seo.json │ │ │ │ └── slider.json │ │ ├── extensions │ │ │ └── .gitkeep │ │ └── index.ts │ ├── tsconfig.json │ └── types │ │ └── generated │ │ ├── components.d.ts │ │ └── contentTypes.d.ts ├── next-server-components │ ├── .gitignore │ ├── README.md │ ├── eslint.config.mjs │ ├── next.config.ts │ ├── package.json │ ├── pnpm-lock.yaml │ ├── postcss.config.mjs │ ├── public │ │ └── .gitkeep │ ├── src │ │ └── app │ │ │ ├── category-files │ │ │ └── page.tsx │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── tailwind.config.ts │ └── tsconfig.json ├── node-javascript │ ├── package.json │ ├── pnpm-lock.yaml │ └── src │ │ └── index.js ├── node-typescript │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── index.ts │ └── tsconfig.json └── react-vite │ ├── .gitignore │ ├── README.md │ ├── eslint.config.js │ ├── index.html │ ├── package.json │ ├── pnpm-lock.yaml │ ├── public │ └── favicon.ico │ ├── src │ ├── app.tsx │ ├── components │ │ ├── CTA.tsx │ │ ├── CategoryCard.tsx │ │ ├── FileCard.tsx │ │ ├── FileGallery.tsx │ │ ├── Nav.tsx │ │ ├── QueryParamsPicker.tsx │ │ └── QueryPreview.tsx │ ├── hooks │ │ ├── useCollection.ts │ │ ├── useFiles.ts │ │ └── useStrapi.ts │ ├── index.css │ ├── layouts │ │ └── Layout.tsx │ ├── main.tsx │ ├── pages │ │ ├── CollectionDemo.tsx │ │ ├── FilesDemo.tsx │ │ └── Home.tsx │ ├── types.ts │ ├── utils │ │ └── constants.ts │ └── vite-env.d.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── eslint.config.mjs ├── jest.config.js ├── package.json ├── pnpm-lock.yaml ├── rollup.config.mjs ├── scripts ├── demo.sh └── pre-pack.sh ├── src ├── auth │ ├── factory │ │ ├── factory.ts │ │ ├── index.ts │ │ └── types.ts │ ├── index.ts │ ├── manager.ts │ └── providers │ │ ├── abstract.ts │ │ ├── api-token.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── users-permissions.ts ├── client.ts ├── content-types │ ├── abstract.ts │ ├── collection │ │ ├── index.ts │ │ └── manager.ts │ ├── index.ts │ └── single │ │ ├── index.ts │ │ └── manager.ts ├── errors │ ├── http.ts │ ├── index.ts │ ├── strapi.ts │ └── url.ts ├── exports.ts ├── files │ ├── constants.ts │ ├── errors.ts │ ├── index.ts │ ├── manager.ts │ └── types.ts ├── formatters │ ├── index.ts │ └── path.ts ├── global.d.ts ├── http │ ├── client.ts │ ├── constants.ts │ ├── index.ts │ ├── interceptor-manager.ts │ └── types.ts ├── index.ts ├── interceptors │ ├── auth.ts │ ├── http.ts │ └── index.ts ├── types │ └── content-api.ts ├── utilities │ ├── index.ts │ ├── request-helper.ts │ └── url-helper.ts └── validators │ ├── client.ts │ ├── index.ts │ └── url.ts ├── tests ├── fixtures │ ├── files.ts │ ├── http-error-associations.ts │ └── invalid-urls.json └── unit │ ├── auth │ ├── factory.test.ts │ ├── manager.test.ts │ └── providers │ │ ├── api-token.test.ts │ │ └── users-permissions.test.ts │ ├── client.test.ts │ ├── content-types │ └── collection │ │ ├── collection-manager.test.ts │ │ └── single-manager.test.ts │ ├── errors │ ├── client-errors.test.ts │ ├── http-errors.test.ts │ └── url-errors.test.ts │ ├── files │ ├── files-client-integration.test.ts │ ├── files-manager.test.ts │ └── url-helper-files.test.ts │ ├── formatters │ └── path.test.ts │ ├── http │ ├── client.test.ts │ └── interceptor-manager.test.ts │ ├── index.test.ts │ ├── interceptors │ ├── auth.test.ts │ └── http.test.ts │ ├── mocks │ ├── auth-manager.mock.ts │ ├── auth-provider-factory.mock.ts │ ├── auth-provider.mock.ts │ ├── flaky-url-validator.mock.ts │ ├── http-client.mock.ts │ ├── index.ts │ ├── request.mock.ts │ ├── response.mock.ts │ ├── strapi-config-validator.mock.ts │ └── url-validator.mock.ts │ ├── utilities │ ├── request-helper.test.ts │ └── url-helper.test.ts │ └── validators │ ├── strapi-config.test.ts │ └── url.test.ts ├── tsconfig.build.json ├── tsconfig.eslint.json └── tsconfig.json /.commitlintrc.ts: -------------------------------------------------------------------------------- 1 | import { RuleConfigSeverity } from '@commitlint/types'; 2 | 3 | import type { UserConfig } from '@commitlint/types'; 4 | 5 | const config: UserConfig = { 6 | extends: ['@commitlint/config-conventional'], 7 | rules: { 8 | 'type-enum': [ 9 | RuleConfigSeverity.Error, 10 | 'always', 11 | [ 12 | 'chore', 13 | 'ci', 14 | 'docs', 15 | 'enhancement', 16 | 'feat', 17 | 'fix', 18 | 'release', 19 | 'revert', 20 | 'security', 21 | 'test', 22 | ], 23 | ], 24 | }, 25 | // ignore commit messages github uses on their PR buttons, "Update" or "Merge branch" 26 | ignores: [ 27 | (commitMessage) => { 28 | // add an exception for github 29 | return ( 30 | commitMessage.startsWith('Update ') || 31 | /^Merge branch '.*' into [a-zA-Z0-9\/\-_]+$/.test(commitMessage) 32 | ); 33 | }, 34 | ], 35 | }; 36 | 37 | export default config; 38 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug Report 2 | description: Help us improve this repository by filing a detailed bug report. 3 | title: '[bug]: ' 4 | labels: ['issue: bug', 'status: to be confirmed'] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Bug Description 9 | description: Provide a clear and concise description of the issue or unexpected behavior related to the Strapi Client. 10 | placeholder: Using the Strapi client to fetch data from the "articles" collection does not return the expected results. 11 | validations: 12 | required: true 13 | 14 | - type: textarea 15 | attributes: 16 | label: Steps to Reproduce 17 | description: Provide a detailed, step-by-step guide on how to reproduce the issue. Include code snippets or links to repositories if applicable. 18 | placeholder: | 19 | Example: 20 | 1. Initialize a new Strapi project with an "article" collection type defined as "...". 21 | 2. Configure the Strapi client with your Strapi API URL and authentication token. 22 | 3. Perform a query to fetch entries from a collection: `client.collection('articles').find()`. 23 | 4. Observe the unexpected behavior or error in the response/output. 24 | validations: 25 | required: true 26 | 27 | - type: textarea 28 | attributes: 29 | label: Expected Behavior 30 | description: Provide a detailed explanation of what you expected to happen instead of the observed issue. Be as specific as possible. 31 | validations: 32 | required: true 33 | 34 | - type: input 35 | id: version 36 | attributes: 37 | label: Version 38 | description: The version of the Strapi Client that was used. 39 | placeholder: 1.0.0 40 | validations: 41 | required: true 42 | 43 | - type: dropdown 44 | id: os 45 | attributes: 46 | label: Operating System 47 | description: Select the operating system where you are experiencing the issue. 48 | multiple: false 49 | options: 50 | - MacOS 51 | - Linux 52 | - Windows 53 | - Other 54 | validations: 55 | required: true 56 | 57 | - type: dropdown 58 | id: runtime 59 | attributes: 60 | label: Runtime Environment 61 | description: Select all runtime environments where the issue has occurred. 62 | multiple: true 63 | options: 64 | - Browser 65 | - Node.js 66 | - Bun 67 | - Deno 68 | - Other 69 | validations: 70 | required: true 71 | 72 | - type: textarea 73 | id: logs 74 | attributes: 75 | label: Logs 76 | description: If available, please provide the logs generated while using the client. 77 | render: shell 78 | 79 | - type: textarea 80 | id: screenshots 81 | attributes: 82 | label: Media 83 | description: If available, please upload screenshots or videos to illustrate the issue. 84 | 85 | - type: checkboxes 86 | id: checklist 87 | attributes: 88 | label: Confirmation Checklist 89 | options: 90 | - label: I have checked the existing [issues](https://github.com/strapi/client/issues) 91 | required: true 92 | 93 | - label: I agree to follow this project's [Code of Conduct](https://github.com/strapi/client/blob/main/CODE_OF_CONDUCT.md) 94 | required: true 95 | 96 | - label: I would like to work on this issue 97 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Feature Request 2 | description: Submit a request for a new feature 3 | title: '[feat]: ' 4 | labels: ['issue: enhancement'] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thank you for contributing a feature request! 10 | - type: textarea 11 | attributes: 12 | label: A clear and concise description of what the feature is 13 | validations: 14 | required: true 15 | - type: textarea 16 | attributes: 17 | label: Why should this feature be included? 18 | validations: 19 | required: true 20 | - type: textarea 21 | attributes: 22 | label: Please provide an example for how this would work 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### What does it do? 2 | 3 | Describe the technical changes you did. 4 | 5 | ### Why is it needed? 6 | 7 | Describe the issue you are solving. 8 | 9 | ### How to test it? 10 | 11 | Provide information about the environment and the path to verify the behaviour. 12 | 13 | ### Related issue(s)/PR(s) 14 | 15 | Let us know if this is related to any issue/pull request 16 | -------------------------------------------------------------------------------- /.github/filters.yml: -------------------------------------------------------------------------------- 1 | unit: 2 | - 'tests/unit/**/*.(ts)' 3 | -------------------------------------------------------------------------------- /.github/workflows/commitlint.yml: -------------------------------------------------------------------------------- 1 | name: 'Commitlint' 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | permissions: 10 | contents: read # to fetch code (actions/checkout) 11 | actions: read 12 | 13 | jobs: 14 | commitlint: 15 | runs-on: ubuntu-22.04 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | - uses: actions/setup-node@v4 21 | with: 22 | node-version: 20 23 | - uses: pnpm/action-setup@v4 24 | name: Install pnpm 25 | with: 26 | version: 9.1.0 27 | run_install: true 28 | - name: Validate PR commits with commitlint 29 | if: github.event_name == 'pull_request' 30 | run: pnpx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose 31 | -------------------------------------------------------------------------------- /.github/workflows/issues_dailyCron.yml: -------------------------------------------------------------------------------- 1 | name: 'Daily Cron - 00:00' 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | permissions: 8 | issues: write 9 | statuses: read 10 | 11 | jobs: 12 | cron-tasks: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: check for inactive issues that can't be reproduced 16 | uses: actions-cool/issues-helper@v3 17 | with: 18 | actions: 'close-issues' 19 | token: ${{ secrets.GITHUB_TOKEN }} 20 | labels: 'status: can not reproduce' 21 | inactive-day: 14 22 | close-reason: 'completed' 23 | body: | 24 | Hello! 25 | 26 | As we have not received any new or updated information to reproduce this issue in the last 14 days we are marking this issue as closed. Should you have new information please feel free to respond and we will consider reopening it. 27 | 28 | If anyone else has updated information for this issue, please open up a new bug report and simply reference this closed bug report so that we can get any new information you may have. If you have questions please refer to the [contributor's guide](https://github.com/strapi/strapi/blob/main/CONTRIBUTING.md#reporting-an-issue) on opening issues. 29 | 30 | Thank you and have a great day! 31 | -------------------------------------------------------------------------------- /.github/workflows/issues_handleLabel.yml: -------------------------------------------------------------------------------- 1 | name: Issue Labeled 2 | 3 | on: 4 | issues: 5 | types: [labeled] 6 | 7 | permissions: 8 | issues: write 9 | pull-requests: write 10 | actions: read 11 | checks: read 12 | contents: read 13 | repository-projects: read 14 | statuses: read 15 | 16 | jobs: 17 | issue-labeled: 18 | runs-on: ubuntu-latest 19 | steps: 20 | # Unable to Reproduce Tasks 21 | - name: 'Comment: unable to reproduce' 22 | if: "${{ github.event.label.name == 'status: can not reproduce' }}" 23 | uses: actions-cool/issues-helper@v3 24 | with: 25 | actions: 'create-comment' 26 | token: ${{ secrets.GITHUB_TOKEN }} 27 | issue-number: ${{ github.event.issue.number }} 28 | body: | 29 | > This is a templated message 30 | 31 | Hello @${{ github.event.issue.user.login }}, 32 | 33 | Thank you for reporting this bug, however we are unable to reproduce the issue you described given the information we have on hand. Can you please create a fresh project that you are able to reproduce the issue in, provide clear steps to reproduce this issue, and either upload this fresh project to a new GitHub repo or compress it into a `.zip` and upload it on this issue? 34 | 35 | We would greatly appreciate your assistance with this, by working in a fresh project it will cut out any possible variables that might be unrelated. 36 | Please note that issues labeled with `status: can not reproduce` will be closed in 14 days if there is no activity. 37 | 38 | Thank you! 39 | 40 | # Invalid bug report template actions 41 | - name: 'Comment: invalid bug report template' 42 | if: "${{ github.event.label.name == 'flag: invalid template' }}" 43 | uses: actions-cool/issues-helper@v3 44 | with: 45 | actions: 'create-comment' 46 | token: ${{ secrets.GITHUB_TOKEN }} 47 | issue-number: ${{ github.event.issue.number }} 48 | body: | 49 | > This is a templated message 50 | 51 | Hello @${{ github.event.issue.user.login }}, 52 | 53 | We ask that you please follow the [issue template](https://raw.githubusercontent.com/strapi/strapi/master/.github/ISSUE_TEMPLATE/BUG_REPORT.md). 54 | A proper issue submission let's us better understand the origin of your bug and therefore help you. We will reopen your issue when we receive the issue following the template guidelines and properly fill out the template. You can see the template guidelines for bug reports [here](https://github.com/strapi/strapi/blob/master/CONTRIBUTING.md#reporting-an-issue). 55 | 56 | Please update the issue with the template and we can reopen this report. 57 | 58 | Thank you. 59 | 60 | - name: 'Close: invalid bug report template' 61 | if: "${{ github.event.label.name == 'flag: invalid template' }}" 62 | uses: actions-cool/issues-helper@v3 63 | with: 64 | actions: 'close-issue' 65 | token: ${{ secrets.GITHUB_TOKEN }} 66 | issue-number: ${{ github.event.issue.number }} 67 | close-reason: 'not_planned' 68 | # Redirect questions to community sources 69 | - name: 'Comment: redirect question to community' 70 | if: "${{ github.event.label.name == 'flag: question' }}" 71 | uses: actions-cool/issues-helper@v3 72 | with: 73 | actions: 'create-comment' 74 | token: ${{ secrets.GITHUB_TOKEN }} 75 | issue-number: ${{ github.event.issue.number }} 76 | body: | 77 | > This is a templated message 78 | 79 | Hello @${{ github.event.issue.user.login }}, 80 | 81 | I see you are wanting to ask a question that is not really a bug report, 82 | 83 | - questions should be directed to [our forum](https://forum.strapi.io) or our [Discord](https://discord.strapi.io) 84 | - feature requests should be directed to our [feedback and feature request database](https://feedback.strapi.io) 85 | 86 | Please see the following contributing guidelines for asking a question [here](https://github.com/strapi/strapi/blob/master/CONTRIBUTING.md#reporting-an-issue). 87 | 88 | Thank you. 89 | - name: 'Close: redirect question to community' 90 | if: "${{ github.event.label.name == 'flag: question' }}" 91 | uses: actions-cool/issues-helper@v3 92 | with: 93 | actions: 'close-issue' 94 | token: ${{ secrets.GITHUB_TOKEN }} 95 | issue-number: ${{ github.event.issue.number }} 96 | close-reason: 'complete' 97 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests' 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | permissions: 10 | contents: read # to fetch code (actions/checkout) 11 | actions: read 12 | 13 | jobs: 14 | cache-and-install: 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node: [20, 22] 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | 25 | - uses: pnpm/action-setup@v4 26 | name: Install pnpm 27 | with: 28 | version: 9.1.0 29 | run_install: true 30 | 31 | - name: Install Node.js 32 | uses: actions/setup-node@v4 33 | with: 34 | node-version: ${{ matrix.node }} 35 | 36 | build: 37 | name: 'build (node: ${{ matrix.node }})' 38 | needs: [cache-and-install] 39 | runs-on: ubuntu-latest 40 | strategy: 41 | matrix: 42 | node: [20, 22] 43 | steps: 44 | - name: Checkout 45 | uses: actions/checkout@v4 46 | 47 | - uses: pnpm/action-setup@v4 48 | name: Install pnpm 49 | with: 50 | version: 9.1.0 51 | run_install: true 52 | 53 | - name: Install Node.js 54 | uses: actions/setup-node@v4 55 | with: 56 | node-version: ${{ matrix.node }} 57 | cache: 'pnpm' 58 | 59 | - name: Project build 60 | shell: bash 61 | run: pnpm run build:clean 62 | 63 | unit_back: 64 | name: 'unit_back (node: ${{ matrix.node }})' 65 | needs: [cache-and-install, build] 66 | runs-on: ubuntu-latest 67 | strategy: 68 | matrix: 69 | node: [20, 22] 70 | steps: 71 | - name: Checkout 72 | uses: actions/checkout@v4 73 | 74 | - uses: pnpm/action-setup@v4 75 | name: Install pnpm 76 | with: 77 | version: 9.1.0 78 | run_install: true 79 | 80 | - name: Install Node.js 81 | uses: actions/setup-node@v4 82 | with: 83 | node-version: ${{ matrix.node }} 84 | cache: 'pnpm' 85 | 86 | - name: Run tests 87 | run: pnpm run test 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ############################ 2 | # OS X 3 | ############################ 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | Icon 9 | .Spotlight-V100 10 | .Trashes 11 | ._* 12 | 13 | ############################ 14 | # Linux 15 | ############################ 16 | 17 | *~ 18 | 19 | ############################ 20 | # Windows 21 | ############################ 22 | 23 | Thumbs.db 24 | ehthumbs.db 25 | Desktop.ini 26 | $RECYCLE.BIN/ 27 | *.cab 28 | *.msi 29 | *.msm 30 | *.msp 31 | 32 | ############################ 33 | # Packages 34 | ############################ 35 | 36 | *.7z 37 | *.csv 38 | *.dat 39 | *.dmg 40 | *.gz 41 | *.iso 42 | *.jar 43 | *.rar 44 | *.tar 45 | *.tgz 46 | *.zip 47 | *.com 48 | *.class 49 | *.dll 50 | *.exe 51 | *.o 52 | *.seed 53 | *.so 54 | *.swo 55 | *.swp 56 | *.swn 57 | *.swm 58 | *.out 59 | *.pid 60 | 61 | ############################ 62 | # Logs and databases 63 | ############################ 64 | 65 | .tmp 66 | *.log 67 | *.sql 68 | *.sqlite 69 | 70 | ############################ 71 | # Misc. 72 | ############################ 73 | 74 | *# 75 | .idea 76 | nbproject 77 | .tsbuildinfo 78 | .eslintcache 79 | .env 80 | 81 | ############################ 82 | # Node.js 83 | ############################ 84 | 85 | .coverage 86 | .node_history 87 | dist 88 | lcov.info 89 | lib-cov 90 | logs 91 | node_modules 92 | package-lock.json 93 | pids 94 | results 95 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no-install -- commitlint --edit ${1} 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx --no-install lint-staged 2 | pnpm run ts:check 3 | pnpm run test --coverage --verbose=false 4 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "{src,tests}/**/*.{js,ts,jsx,tsx,yml,yaml}": ["pnpm run prettier:write", "pnpm run lint:fix"] 3 | } 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | bin 2 | coverage 3 | dist 4 | build 5 | pnpm-lock.yaml 6 | .strapi 7 | .next 8 | .idea 9 | node_modules 10 | .strapi-updater.json 11 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | endOfLine: 'lf', 3 | semi: true, 4 | singleQuote: true, 5 | tabWidth: 2, 6 | trailingComma: 'es5', 7 | printWidth: 100, 8 | arrowParens: 'always', 9 | }; 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project and everyone participating in it are governed by the [Strapi Code of Conduct](https://github.com/strapi/strapi/blob/master/CODE_OF_CONDUCT.md). 4 | By participating, you are expected to uphold this code. Please read the [full text](https://github.com/strapi/strapi/blob/master/CODE_OF_CONDUCT.md) 5 | so that you can read which actions may or may not be tolerated. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-present Strapi Solutions SAS 2 | 3 | Portions of the Strapi software are licensed as follows: 4 | 5 | - All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined in "ee/LICENSE". 6 | 7 | - All software outside of the above-mentioned directories or restrictions above is available under the "MIT Expat" license as set forth below. 8 | 9 | MIT Expat License 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /demo/.strapi-app/.env.example: -------------------------------------------------------------------------------- 1 | HOST=0.0.0.0 2 | PORT=1337 3 | APP_KEYS="toBeModified1,toBeModified2" 4 | API_TOKEN_SALT=tobemodified 5 | ADMIN_JWT_SECRET=tobemodified 6 | TRANSFER_TOKEN_SALT=tobemodified 7 | JWT_SECRET=tobemodified 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/.gitignore: -------------------------------------------------------------------------------- 1 | ############################ 2 | # OS X 3 | ############################ 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | Icon 9 | .Spotlight-V100 10 | .Trashes 11 | ._* 12 | 13 | 14 | ############################ 15 | # Linux 16 | ############################ 17 | 18 | *~ 19 | 20 | 21 | ############################ 22 | # Windows 23 | ############################ 24 | 25 | Thumbs.db 26 | ehthumbs.db 27 | Desktop.ini 28 | $RECYCLE.BIN/ 29 | *.cab 30 | *.msi 31 | *.msm 32 | *.msp 33 | 34 | 35 | ############################ 36 | # Packages 37 | ############################ 38 | 39 | *.7z 40 | *.csv 41 | *.dat 42 | *.dmg 43 | *.gz 44 | *.iso 45 | *.jar 46 | *.rar 47 | *.tar 48 | *.zip 49 | *.com 50 | *.class 51 | *.dll 52 | *.exe 53 | *.o 54 | *.seed 55 | *.so 56 | *.swo 57 | *.swp 58 | *.swn 59 | *.swm 60 | *.out 61 | *.pid 62 | 63 | 64 | ############################ 65 | # Logs and databases 66 | ############################ 67 | 68 | .tmp 69 | *.log 70 | *.sql 71 | *.sqlite 72 | *.sqlite3 73 | 74 | 75 | ############################ 76 | # Misc. 77 | ############################ 78 | 79 | *# 80 | ssl 81 | .idea 82 | nbproject 83 | public/uploads/* 84 | !public/uploads/.gitkeep 85 | .tsbuildinfo 86 | .eslintcache 87 | 88 | ############################ 89 | # Node.js 90 | ############################ 91 | 92 | lib-cov 93 | lcov.info 94 | pids 95 | logs 96 | results 97 | node_modules 98 | .node_history 99 | 100 | ############################ 101 | # Package managers 102 | ############################ 103 | 104 | .yarn/* 105 | !.yarn/cache 106 | !.yarn/unplugged 107 | !.yarn/patches 108 | !.yarn/releases 109 | !.yarn/sdks 110 | !.yarn/versions 111 | .pnp.* 112 | yarn-error.log 113 | 114 | ############################ 115 | # Tests 116 | ############################ 117 | 118 | coverage 119 | 120 | ############################ 121 | # Strapi 122 | ############################ 123 | 124 | .env 125 | license.txt 126 | exports 127 | .strapi 128 | dist 129 | build 130 | .strapi-updater.json 131 | .strapi-cloud.json -------------------------------------------------------------------------------- /demo/.strapi-app/README.md: -------------------------------------------------------------------------------- 1 | # 🚀 Getting started with Strapi 2 | 3 | Strapi comes with a full featured [Command Line Interface](https://docs.strapi.io/dev-docs/cli) (CLI) which lets you scaffold and manage your project in seconds. 4 | 5 | ### `develop` 6 | 7 | Start your Strapi application with autoReload enabled. [Learn more](https://docs.strapi.io/dev-docs/cli#strapi-develop) 8 | 9 | ``` 10 | npm run develop 11 | # or 12 | yarn develop 13 | ``` 14 | 15 | ### `start` 16 | 17 | Start your Strapi application with autoReload disabled. [Learn more](https://docs.strapi.io/dev-docs/cli#strapi-start) 18 | 19 | ``` 20 | npm run start 21 | # or 22 | yarn start 23 | ``` 24 | 25 | ### `build` 26 | 27 | Build your admin panel. [Learn more](https://docs.strapi.io/dev-docs/cli#strapi-build) 28 | 29 | ``` 30 | npm run build 31 | # or 32 | yarn build 33 | ``` 34 | 35 | ## ⚙️ Deployment 36 | 37 | Strapi gives you many possible deployment options for your project including [Strapi Cloud](https://cloud.strapi.io). Browse the [deployment section of the documentation](https://docs.strapi.io/dev-docs/deployment) to find the best solution for your use case. 38 | 39 | ``` 40 | yarn strapi deploy 41 | ``` 42 | 43 | ## 📚 Learn more 44 | 45 | - [Resource center](https://strapi.io/resource-center) - Strapi resource center. 46 | - [Strapi documentation](https://docs.strapi.io) - Official Strapi documentation. 47 | - [Strapi tutorials](https://strapi.io/tutorials) - List of tutorials made by the core team and the community. 48 | - [Strapi blog](https://strapi.io/blog) - Official Strapi blog containing articles made by the Strapi team and the community. 49 | - [Changelog](https://strapi.io/changelog) - Find out about the Strapi product updates, new features and general improvements. 50 | 51 | Feel free to check out the [Strapi GitHub repository](https://github.com/strapi/strapi). Your feedback and contributions are welcome! 52 | 53 | ## ✨ Community 54 | 55 | - [Discord](https://discord.strapi.io) - Come chat with the Strapi community including the core team. 56 | - [Forum](https://forum.strapi.io/) - Place to discuss, ask questions and find answers, show your Strapi project and get feedback or just talk with other Community members. 57 | - [Awesome Strapi](https://github.com/strapi/awesome-strapi) - A curated list of awesome things related to Strapi. 58 | 59 | --- 60 | 61 | 🤫 Psst! [Strapi is hiring](https://strapi.io/careers). 62 | -------------------------------------------------------------------------------- /demo/.strapi-app/config/admin.ts: -------------------------------------------------------------------------------- 1 | export default ({ env }) => ({ 2 | auth: { 3 | secret: env('ADMIN_JWT_SECRET'), 4 | }, 5 | apiToken: { 6 | salt: env('API_TOKEN_SALT'), 7 | }, 8 | transfer: { 9 | token: { 10 | salt: env('TRANSFER_TOKEN_SALT'), 11 | }, 12 | }, 13 | flags: { 14 | nps: env.bool('FLAG_NPS', true), 15 | promoteEE: env.bool('FLAG_PROMOTE_EE', true), 16 | }, 17 | autoOpen: false, 18 | }); 19 | -------------------------------------------------------------------------------- /demo/.strapi-app/config/api.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | rest: { 3 | defaultLimit: 25, 4 | maxLimit: 100, 5 | withCount: true, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/config/database.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | export default ({ env }) => { 4 | const client = env('DATABASE_CLIENT', 'sqlite'); 5 | 6 | const connections = { 7 | mysql: { 8 | connection: { 9 | host: env('DATABASE_HOST', 'localhost'), 10 | port: env.int('DATABASE_PORT', 3306), 11 | database: env('DATABASE_NAME', 'strapi'), 12 | user: env('DATABASE_USERNAME', 'strapi'), 13 | password: env('DATABASE_PASSWORD', 'strapi'), 14 | ssl: env.bool('DATABASE_SSL', false) && { 15 | key: env('DATABASE_SSL_KEY', undefined), 16 | cert: env('DATABASE_SSL_CERT', undefined), 17 | ca: env('DATABASE_SSL_CA', undefined), 18 | capath: env('DATABASE_SSL_CAPATH', undefined), 19 | cipher: env('DATABASE_SSL_CIPHER', undefined), 20 | rejectUnauthorized: env.bool('DATABASE_SSL_REJECT_UNAUTHORIZED', true), 21 | }, 22 | }, 23 | pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) }, 24 | }, 25 | postgres: { 26 | connection: { 27 | connectionString: env('DATABASE_URL'), 28 | host: env('DATABASE_HOST', 'localhost'), 29 | port: env.int('DATABASE_PORT', 5432), 30 | database: env('DATABASE_NAME', 'strapi'), 31 | user: env('DATABASE_USERNAME', 'strapi'), 32 | password: env('DATABASE_PASSWORD', 'strapi'), 33 | ssl: env.bool('DATABASE_SSL', false) && { 34 | key: env('DATABASE_SSL_KEY', undefined), 35 | cert: env('DATABASE_SSL_CERT', undefined), 36 | ca: env('DATABASE_SSL_CA', undefined), 37 | capath: env('DATABASE_SSL_CAPATH', undefined), 38 | cipher: env('DATABASE_SSL_CIPHER', undefined), 39 | rejectUnauthorized: env.bool('DATABASE_SSL_REJECT_UNAUTHORIZED', true), 40 | }, 41 | schema: env('DATABASE_SCHEMA', 'public'), 42 | }, 43 | pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) }, 44 | }, 45 | sqlite: { 46 | connection: { 47 | filename: path.join(__dirname, '..', '..', env('DATABASE_FILENAME', '.tmp/data.db')), 48 | }, 49 | useNullAsDefault: true, 50 | }, 51 | }; 52 | 53 | return { 54 | connection: { 55 | client, 56 | ...connections[client], 57 | acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000), 58 | }, 59 | }; 60 | }; 61 | -------------------------------------------------------------------------------- /demo/.strapi-app/config/middlewares.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | 'strapi::logger', 3 | 'strapi::errors', 4 | 'strapi::security', 5 | 'strapi::cors', 6 | 'strapi::poweredBy', 7 | 'strapi::query', 8 | 'strapi::body', 9 | 'strapi::session', 10 | 'strapi::favicon', 11 | 'strapi::public', 12 | ]; 13 | -------------------------------------------------------------------------------- /demo/.strapi-app/config/plugins.ts: -------------------------------------------------------------------------------- 1 | export default () => ({}); 2 | -------------------------------------------------------------------------------- /demo/.strapi-app/config/server.ts: -------------------------------------------------------------------------------- 1 | export default ({ env }) => ({ 2 | host: env('HOST', '0.0.0.0'), 3 | port: env.int('PORT', 1337), 4 | app: { 5 | keys: env.array('APP_KEYS'), 6 | }, 7 | }); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/a-bug-is-becoming-a-meme-on-the-internet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/a-bug-is-becoming-a-meme-on-the-internet.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/beautiful-picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/beautiful-picture.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/coffee-art.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/coffee-art.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/coffee-beans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/coffee-beans.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/coffee-shadow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/coffee-shadow.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/daviddoe@strapi.io.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/daviddoe@strapi.io.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/default-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/default-image.png -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/favicon.png -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/sarahbaker@strapi.io.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/sarahbaker@strapi.io.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/the-internet-s-own-boy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/the-internet-s-own-boy.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/this-shrimp-is-awesome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/this-shrimp-is-awesome.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/we-love-pizza.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/we-love-pizza.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/data/uploads/what-s-inside-a-black-hole.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/data/uploads/what-s-inside-a-black-hole.jpg -------------------------------------------------------------------------------- /demo/.strapi-app/database/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/database/migrations/.gitkeep -------------------------------------------------------------------------------- /demo/.strapi-app/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/favicon.png -------------------------------------------------------------------------------- /demo/.strapi-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "strapi", 3 | "version": "0.1.0", 4 | "private": true, 5 | "description": "A Strapi application", 6 | "scripts": { 7 | "build": "strapi build", 8 | "deploy": "strapi deploy", 9 | "develop": "strapi develop", 10 | "seed:example": "node ./scripts/seed.js", 11 | "start": "strapi start", 12 | "strapi": "strapi" 13 | }, 14 | "dependencies": { 15 | "@strapi/plugin-cloud": "latest", 16 | "@strapi/plugin-users-permissions": "latest", 17 | "@strapi/strapi": "latest", 18 | "better-sqlite3": "11.3.0", 19 | "fs-extra": "^10.0.0", 20 | "mime-types": "^2.1.27", 21 | "react": "^18.0.0", 22 | "react-dom": "^18.0.0", 23 | "react-router-dom": "^6.0.0", 24 | "styled-components": "^6.0.0" 25 | }, 26 | "devDependencies": { 27 | "@types/node": "^20", 28 | "@types/react": "^18", 29 | "@types/react-dom": "^18", 30 | "typescript": "^5" 31 | }, 32 | "engines": { 33 | "node": ">=18.0.0 <=22.x.x", 34 | "npm": ">=6.0.0" 35 | }, 36 | "strapi": { 37 | "uuid": "getstarted" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /demo/.strapi-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # To prevent search engines from seeing the site altogether, uncomment the next two lines: 2 | # User-Agent: * 3 | # Disallow: / 4 | -------------------------------------------------------------------------------- /demo/.strapi-app/public/uploads/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/public/uploads/.gitkeep -------------------------------------------------------------------------------- /demo/.strapi-app/src/admin/app.example.tsx: -------------------------------------------------------------------------------- 1 | import type { StrapiApp } from '@strapi/strapi/admin'; 2 | 3 | export default { 4 | config: { 5 | locales: [ 6 | // 'ar', 7 | // 'fr', 8 | // 'cs', 9 | // 'de', 10 | // 'dk', 11 | // 'es', 12 | // 'he', 13 | // 'id', 14 | // 'it', 15 | // 'ja', 16 | // 'ko', 17 | // 'ms', 18 | // 'nl', 19 | // 'no', 20 | // 'pl', 21 | // 'pt-BR', 22 | // 'pt', 23 | // 'ru', 24 | // 'sk', 25 | // 'sv', 26 | // 'th', 27 | // 'tr', 28 | // 'uk', 29 | // 'vi', 30 | // 'zh-Hans', 31 | // 'zh', 32 | ], 33 | }, 34 | bootstrap(app: StrapiApp) { 35 | console.log(app); 36 | }, 37 | }; 38 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/admin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Bundler", 6 | "useDefineForClassFields": true, 7 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 8 | "allowJs": false, 9 | "skipLibCheck": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "resolveJsonModule": true, 15 | "noEmit": true, 16 | "jsx": "react-jsx" 17 | }, 18 | "include": ["../plugins/**/admin/src/**/*", "./"], 19 | "exclude": ["node_modules/", "build/", "dist/", "**/*.test.ts"] 20 | } 21 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/admin/vite.config.example.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig, type UserConfig } from 'vite'; 2 | 3 | export default (config: UserConfig) => { 4 | // Important: always return the modified config 5 | return mergeConfig(config, { 6 | resolve: { 7 | alias: { 8 | '@': '/src', 9 | }, 10 | }, 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/src/api/.gitkeep -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/about/content-types/about/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "singleType", 3 | "collectionName": "abouts", 4 | "info": { 5 | "singularName": "about", 6 | "pluralName": "abouts", 7 | "displayName": "About", 8 | "description": "Write about yourself and the content you create" 9 | }, 10 | "options": { 11 | "draftAndPublish": false 12 | }, 13 | "pluginOptions": {}, 14 | "attributes": { 15 | "title": { 16 | "type": "string" 17 | }, 18 | "blocks": { 19 | "type": "dynamiczone", 20 | "components": ["shared.media", "shared.quote", "shared.rich-text", "shared.slider"] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/about/controllers/about.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * about controller 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreController('api::about.about'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/about/routes/about.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * about router. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreRouter('api::about.about'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/about/services/about.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * about service. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreService('api::about.about'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/article/content-types/article/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "collectionType", 3 | "collectionName": "articles", 4 | "info": { 5 | "singularName": "article", 6 | "pluralName": "articles", 7 | "displayName": "Article", 8 | "description": "Create your blog content" 9 | }, 10 | "options": { 11 | "draftAndPublish": true 12 | }, 13 | "pluginOptions": {}, 14 | "attributes": { 15 | "title": { 16 | "type": "string" 17 | }, 18 | "description": { 19 | "type": "text", 20 | "maxLength": 80 21 | }, 22 | "slug": { 23 | "type": "uid", 24 | "targetField": "title" 25 | }, 26 | "cover": { 27 | "type": "media", 28 | "multiple": false, 29 | "required": false, 30 | "allowedTypes": ["images", "files", "videos"] 31 | }, 32 | "author": { 33 | "type": "relation", 34 | "relation": "manyToOne", 35 | "target": "api::author.author", 36 | "inversedBy": "articles" 37 | }, 38 | "category": { 39 | "type": "relation", 40 | "relation": "manyToOne", 41 | "target": "api::category.category", 42 | "inversedBy": "articles" 43 | }, 44 | "blocks": { 45 | "type": "dynamiczone", 46 | "components": ["shared.media", "shared.quote", "shared.rich-text", "shared.slider"] 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/article/controllers/article.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * article controller 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreController('api::article.article'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/article/routes/article.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * article router. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreRouter('api::article.article'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/article/services/article.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * article service. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreService('api::article.article'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/author/content-types/author/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "collectionType", 3 | "collectionName": "authors", 4 | "info": { 5 | "singularName": "author", 6 | "pluralName": "authors", 7 | "displayName": "Author", 8 | "description": "Create authors for your content" 9 | }, 10 | "options": { 11 | "draftAndPublish": false 12 | }, 13 | "pluginOptions": {}, 14 | "attributes": { 15 | "name": { 16 | "type": "string" 17 | }, 18 | "avatar": { 19 | "type": "media", 20 | "multiple": false, 21 | "required": false, 22 | "allowedTypes": ["images", "files", "videos"] 23 | }, 24 | "email": { 25 | "type": "string" 26 | }, 27 | "articles": { 28 | "type": "relation", 29 | "relation": "oneToMany", 30 | "target": "api::article.article", 31 | "mappedBy": "author" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/author/controllers/author.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * author controller 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreController('api::author.author'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/author/routes/author.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * author router. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreRouter('api::author.author'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/author/services/author.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * author service. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreService('api::author.author'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/category/content-types/category/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "collectionType", 3 | "collectionName": "categories", 4 | "info": { 5 | "singularName": "category", 6 | "pluralName": "categories", 7 | "displayName": "Category", 8 | "description": "Organize your content into categories" 9 | }, 10 | "options": { 11 | "draftAndPublish": false 12 | }, 13 | "pluginOptions": {}, 14 | "attributes": { 15 | "name": { 16 | "type": "string" 17 | }, 18 | "slug": { 19 | "type": "uid" 20 | }, 21 | "articles": { 22 | "type": "relation", 23 | "relation": "oneToMany", 24 | "target": "api::article.article", 25 | "mappedBy": "category" 26 | }, 27 | "description": { 28 | "type": "text" 29 | }, 30 | "image": { 31 | "type": "media", 32 | "multiple": false, 33 | "required": false, 34 | "allowedTypes": ["images"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/category/controllers/category.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * category controller 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreController('api::category.category'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/category/routes/category.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * category router. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreRouter('api::category.category'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/category/services/category.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * category service. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreService('api::category.category'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/global/content-types/global/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "singleType", 3 | "collectionName": "globals", 4 | "info": { 5 | "singularName": "global", 6 | "pluralName": "globals", 7 | "displayName": "Global", 8 | "description": "Define global settings" 9 | }, 10 | "options": { 11 | "draftAndPublish": false 12 | }, 13 | "pluginOptions": {}, 14 | "attributes": { 15 | "siteName": { 16 | "type": "string", 17 | "required": true 18 | }, 19 | "favicon": { 20 | "type": "media", 21 | "multiple": false, 22 | "required": false, 23 | "allowedTypes": ["images", "files", "videos"] 24 | }, 25 | "siteDescription": { 26 | "type": "text", 27 | "required": true 28 | }, 29 | "defaultSeo": { 30 | "type": "component", 31 | "repeatable": false, 32 | "component": "shared.seo" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/global/controllers/global.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * global controller 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreController('api::global.global'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/global/routes/global.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * global router. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreRouter('api::global.global'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/api/global/services/global.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * global service. 3 | */ 4 | 5 | import { factories } from '@strapi/strapi'; 6 | 7 | export default factories.createCoreService('api::global.global'); 8 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/components/shared/media.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectionName": "components_shared_media", 3 | "info": { 4 | "displayName": "Media", 5 | "icon": "file-video" 6 | }, 7 | "options": {}, 8 | "attributes": { 9 | "file": { 10 | "allowedTypes": ["images", "files", "videos"], 11 | "type": "media", 12 | "multiple": false 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/components/shared/quote.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectionName": "components_shared_quotes", 3 | "info": { 4 | "displayName": "Quote", 5 | "icon": "indent" 6 | }, 7 | "options": {}, 8 | "attributes": { 9 | "title": { 10 | "type": "string" 11 | }, 12 | "body": { 13 | "type": "text" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/components/shared/rich-text.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectionName": "components_shared_rich_texts", 3 | "info": { 4 | "displayName": "Rich text", 5 | "icon": "align-justify", 6 | "description": "" 7 | }, 8 | "options": {}, 9 | "attributes": { 10 | "body": { 11 | "type": "richtext" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/components/shared/seo.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectionName": "components_shared_seos", 3 | "info": { 4 | "name": "Seo", 5 | "icon": "allergies", 6 | "displayName": "Seo", 7 | "description": "" 8 | }, 9 | "options": {}, 10 | "attributes": { 11 | "metaTitle": { 12 | "type": "string", 13 | "required": true 14 | }, 15 | "metaDescription": { 16 | "type": "text", 17 | "required": true 18 | }, 19 | "shareImage": { 20 | "type": "media", 21 | "multiple": false, 22 | "required": false, 23 | "allowedTypes": ["images"] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/components/shared/slider.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectionName": "components_shared_sliders", 3 | "info": { 4 | "displayName": "Slider", 5 | "icon": "address-book", 6 | "description": "" 7 | }, 8 | "options": {}, 9 | "attributes": { 10 | "files": { 11 | "type": "media", 12 | "multiple": true, 13 | "required": false, 14 | "allowedTypes": ["images"] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /demo/.strapi-app/src/extensions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/.strapi-app/src/extensions/.gitkeep -------------------------------------------------------------------------------- /demo/.strapi-app/src/index.ts: -------------------------------------------------------------------------------- 1 | // import type { Core } from '@strapi/strapi'; 2 | 3 | export default { 4 | /** 5 | * An asynchronous register function that runs before 6 | * your application is initialized. 7 | * 8 | * This gives you an opportunity to extend code. 9 | */ 10 | register(/* { strapi }: { strapi: Core.Strapi } */) {}, 11 | 12 | /** 13 | * An asynchronous bootstrap function that runs before 14 | * your application gets started. 15 | * 16 | * This gives you an opportunity to set up your data model, 17 | * run jobs, or perform some special logic. 18 | */ 19 | bootstrap(/* { strapi }: { strapi: Core.Strapi } */) {}, 20 | }; 21 | -------------------------------------------------------------------------------- /demo/.strapi-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "moduleResolution": "Node", 5 | "lib": ["ES2020"], 6 | "target": "ES2019", 7 | "strict": false, 8 | "skipLibCheck": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "incremental": true, 11 | "esModuleInterop": true, 12 | "resolveJsonModule": true, 13 | "noEmitOnError": true, 14 | "noImplicitThis": true, 15 | "outDir": "dist", 16 | "rootDir": "." 17 | }, 18 | "include": [ 19 | // Include root files 20 | "./", 21 | // Include all ts files 22 | "./**/*.ts", 23 | // Include all js files 24 | "./**/*.js", 25 | // Force the JSON files in the src folder to be included 26 | "src/**/*.json" 27 | ], 28 | 29 | "exclude": [ 30 | "node_modules/", 31 | "build/", 32 | "dist/", 33 | ".cache/", 34 | ".tmp/", 35 | 36 | // Do not include admin files in the server compilation 37 | "src/admin/", 38 | // Do not include test files 39 | "**/*.test.*", 40 | // Do not include plugins in the server compilation 41 | "src/plugins/**" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /demo/.strapi-app/types/generated/components.d.ts: -------------------------------------------------------------------------------- 1 | import type { Schema, Struct } from '@strapi/strapi'; 2 | 3 | export interface SharedMedia extends Struct.ComponentSchema { 4 | collectionName: 'components_shared_media'; 5 | info: { 6 | displayName: 'Media'; 7 | icon: 'file-video'; 8 | }; 9 | attributes: { 10 | file: Schema.Attribute.Media<'images' | 'files' | 'videos'>; 11 | }; 12 | } 13 | 14 | export interface SharedQuote extends Struct.ComponentSchema { 15 | collectionName: 'components_shared_quotes'; 16 | info: { 17 | displayName: 'Quote'; 18 | icon: 'indent'; 19 | }; 20 | attributes: { 21 | body: Schema.Attribute.Text; 22 | title: Schema.Attribute.String; 23 | }; 24 | } 25 | 26 | export interface SharedRichText extends Struct.ComponentSchema { 27 | collectionName: 'components_shared_rich_texts'; 28 | info: { 29 | description: ''; 30 | displayName: 'Rich text'; 31 | icon: 'align-justify'; 32 | }; 33 | attributes: { 34 | body: Schema.Attribute.RichText; 35 | }; 36 | } 37 | 38 | export interface SharedSeo extends Struct.ComponentSchema { 39 | collectionName: 'components_shared_seos'; 40 | info: { 41 | description: ''; 42 | displayName: 'Seo'; 43 | icon: 'allergies'; 44 | name: 'Seo'; 45 | }; 46 | attributes: { 47 | metaDescription: Schema.Attribute.Text & Schema.Attribute.Required; 48 | metaTitle: Schema.Attribute.String & Schema.Attribute.Required; 49 | shareImage: Schema.Attribute.Media<'images'>; 50 | }; 51 | } 52 | 53 | export interface SharedSlider extends Struct.ComponentSchema { 54 | collectionName: 'components_shared_sliders'; 55 | info: { 56 | description: ''; 57 | displayName: 'Slider'; 58 | icon: 'address-book'; 59 | }; 60 | attributes: { 61 | files: Schema.Attribute.Media<'images', true>; 62 | }; 63 | } 64 | 65 | declare module '@strapi/strapi' { 66 | export module Public { 67 | export interface ComponentSchemas { 68 | 'shared.media': SharedMedia; 69 | 'shared.quote': SharedQuote; 70 | 'shared.rich-text': SharedRichText; 71 | 'shared.seo': SharedSeo; 72 | 'shared.slider': SharedSlider; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /demo/next-server-components/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | -------------------------------------------------------------------------------- /demo/next-server-components/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. 37 | -------------------------------------------------------------------------------- /demo/next-server-components/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from 'node:path'; 2 | import { fileURLToPath } from 'node:url'; 3 | import { FlatCompat } from '@eslint/eslintrc'; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [...compat.extends('next/core-web-vitals', 'next/typescript')]; 13 | 14 | export default eslintConfig; 15 | -------------------------------------------------------------------------------- /demo/next-server-components/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from 'next'; 2 | import path from 'node:path'; 3 | 4 | const nextConfig: NextConfig = { 5 | // Ensure Turbo-pack compatibility with Next's module loading 6 | // See https://github.com/vercel/next.js/issues/64472#issuecomment-2077483493 7 | outputFileTracingRoot: path.join(__dirname, '../../'), 8 | 9 | // Logs outbounds requests, including ones restored from the HMR cache 10 | logging: { 11 | fetches: { 12 | fullUrl: true, 13 | hmrRefreshes: true, 14 | }, 15 | }, 16 | 17 | // Allow images from Strapi server 18 | images: { 19 | remotePatterns: [ 20 | { 21 | protocol: 'http', 22 | hostname: 'localhost', 23 | port: '1337', 24 | pathname: '/**', 25 | }, 26 | ], 27 | }, 28 | }; 29 | 30 | export default nextConfig; 31 | -------------------------------------------------------------------------------- /demo/next-server-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-next-server-components", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --turbopack", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@strapi/client": "link:../..", 13 | "dotenv": "16.4.7", 14 | "next": "15.1.7", 15 | "react": "^19.0.0", 16 | "react-dom": "^19.0.0" 17 | }, 18 | "devDependencies": { 19 | "@eslint/eslintrc": "^3", 20 | "@types/node": "^20", 21 | "@types/react": "^19", 22 | "@types/react-dom": "^19", 23 | "eslint": "^9", 24 | "eslint-config-next": "15.1.7", 25 | "postcss": "^8", 26 | "tailwindcss": "^3.4.1", 27 | "typescript": "^5" 28 | }, 29 | "keywords": [], 30 | "author": { 31 | "name": "Strapi Solutions SAS", 32 | "email": "hi@strapi.io", 33 | "url": "https://strapi.io" 34 | }, 35 | "license": "ISC" 36 | } 37 | -------------------------------------------------------------------------------- /demo/next-server-components/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /demo/next-server-components/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/next-server-components/public/.gitkeep -------------------------------------------------------------------------------- /demo/next-server-components/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/next-server-components/src/app/favicon.ico -------------------------------------------------------------------------------- /demo/next-server-components/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --background: #ffffff; 7 | --foreground: #171717; 8 | } 9 | 10 | @media (prefers-color-scheme: dark) { 11 | :root { 12 | --background: #0a0a0a; 13 | --foreground: #ededed; 14 | } 15 | } 16 | 17 | body { 18 | color: var(--foreground); 19 | background: var(--background); 20 | font-family: Arial, Helvetica, sans-serif; 21 | } 22 | -------------------------------------------------------------------------------- /demo/next-server-components/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Geist, Geist_Mono } from 'next/font/google'; 3 | 4 | import type { Metadata } from 'next'; 5 | 6 | import './globals.css'; 7 | 8 | const geistSans = Geist({ 9 | variable: '--font-geist-sans', 10 | subsets: ['latin'], 11 | }); 12 | 13 | const geistMono = Geist_Mono({ 14 | variable: '--font-geist-mono', 15 | subsets: ['latin'], 16 | }); 17 | 18 | export const metadata: Metadata = { 19 | title: 'Create Next App', 20 | description: 'Generated by create next app', 21 | }; 22 | 23 | export default function RootLayout({ 24 | children, 25 | }: Readonly<{ 26 | children: React.ReactNode; 27 | }>) { 28 | return ( 29 | 30 | {children} 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /demo/next-server-components/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | import { strapi } from '@strapi/client'; 3 | import Link from 'next/link'; 4 | 5 | dotenv.config(); 6 | 7 | export const revalidate = 60; // Revalidate this page once per minute 8 | 9 | // Define article interface for type safety 10 | interface Article { 11 | id: number; 12 | title: string; 13 | description?: string; 14 | slug: string; 15 | createdAt: string; 16 | } 17 | 18 | // Sample fallback data for when the API is unavailable (e.g., during build) 19 | const fallbackData: Article[] = [ 20 | { 21 | id: 1, 22 | title: "What's inside a Black Hole", 23 | description: 'Maybe the answer is in this article, or not...', 24 | slug: 'what-s-inside-a-black-hole', 25 | createdAt: '2023-01-01T00:00:00.000Z', 26 | }, 27 | { 28 | id: 2, 29 | title: "The internet's Own boy", 30 | description: 'Follow the story of Aaron Swartz, the boy who could change the world', 31 | slug: 'the-internet-s-own-boy', 32 | createdAt: '2023-01-02T00:00:00.000Z', 33 | }, 34 | { 35 | id: 3, 36 | title: 'A bug is becoming a meme on the internet', 37 | description: 'How a bug on MySQL is becoming a meme on the internet', 38 | slug: 'a-bug-is-becoming-a-meme-on-the-internet', 39 | createdAt: '2023-01-03T00:00:00.000Z', 40 | }, 41 | ]; 42 | 43 | export default async function Home() { 44 | let articles = fallbackData; 45 | let isError = false; 46 | let errorMessage = ''; 47 | 48 | try { 49 | const api_token = process.env.FULL_ACCESS_TOKEN; // READ_ONLY_TOKEN is also available 50 | 51 | // Only attempt to fetch if we have a token 52 | if (api_token) { 53 | console.log('Running with api token ' + api_token); 54 | 55 | // Create the Strapi client instance 56 | const client = strapi({ 57 | baseURL: 'http://localhost:1337/api', 58 | auth: api_token, 59 | }); 60 | 61 | // Create a collection type query manager for the articles 62 | const articlesApi = client.collection('articles'); 63 | 64 | // Fetch the list of all articles 65 | const result = await articlesApi.find({ status: 'draft' }); 66 | 67 | if (result && result.data) { 68 | articles = result.data as unknown as Article[]; 69 | } 70 | } else { 71 | console.warn('API token not available. Using fallback data.'); 72 | isError = true; 73 | errorMessage = 'API token not available. This is likely happening during build time.'; 74 | } 75 | 76 | return ( 77 |
78 | {isError && ( 79 |
80 |

Note:

81 |

82 | {errorMessage} 83 |
84 | Showing fallback data. When running with a proper Strapi server, you'll see real 85 | data. 86 |

87 |
88 | )} 89 | 90 | {articles.map((article) => ( 91 |
95 |

{article.title}

96 | {article.description &&

{article.description}

} 97 |

98 | {new Date(article.createdAt).toLocaleDateString()} 99 |

100 |
101 | ))} 102 | 109 |
110 | ); 111 | } catch (error) { 112 | return ( 113 |
114 |

115 | Error: {error instanceof Error ? error.message : 'Unknown error'} 116 |

117 | {error instanceof Error && 'cause' in error ? ( 118 |

Cause: {error.cause?.toString()}

119 | ) : null} 120 |
121 | ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /demo/next-server-components/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss'; 2 | 3 | export default { 4 | content: [ 5 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 7 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 8 | ], 9 | theme: { 10 | extend: { 11 | colors: { 12 | background: 'var(--background)', 13 | foreground: 'var(--foreground)', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } satisfies Config; 19 | -------------------------------------------------------------------------------- /demo/next-server-components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /demo/node-javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-node-javascript", 3 | "version": "1.0.0", 4 | "description": "A Strapi Client demo using a Node x JavaScript application", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node src/index.js", 8 | "debug": "DEBUG=strapi:* node src/index.js" 9 | }, 10 | "dependencies": { 11 | "@strapi/client": "link:../..", 12 | "dotenv": "16.4.7" 13 | }, 14 | "keywords": [], 15 | "author": { 16 | "name": "Strapi Solutions SAS", 17 | "email": "hi@strapi.io", 18 | "url": "https://strapi.io" 19 | }, 20 | "license": "ISC" 21 | } 22 | -------------------------------------------------------------------------------- /demo/node-javascript/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@strapi/client': 12 | specifier: link:../.. 13 | version: link:../.. 14 | dotenv: 15 | specifier: 16.4.7 16 | version: 16.4.7 17 | 18 | packages: 19 | 20 | dotenv@16.4.7: 21 | resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} 22 | engines: {node: '>=12'} 23 | 24 | snapshots: 25 | 26 | dotenv@16.4.7: {} 27 | -------------------------------------------------------------------------------- /demo/node-typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-node-typescript", 3 | "version": "1.0.0", 4 | "description": "A Strapi Client demo using a Node x TypeScript application", 5 | "main": "dist/index.js", 6 | "private": true, 7 | "type": "module", 8 | "scripts": { 9 | "build": "tsc -p tsconfig.json", 10 | "watch": "tsc -p tsconfig.json -w", 11 | "start": "node dist/index.js", 12 | "debug": "DEBUG=strapi:* node dist/index.js" 13 | }, 14 | "dependencies": { 15 | "@strapi/client": "link:../..", 16 | "dotenv": "16.4.7" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "22.12.0", 20 | "typescript": "5.7.3" 21 | }, 22 | "keywords": [], 23 | "author": { 24 | "name": "Strapi Solutions SAS", 25 | "email": "hi@strapi.io", 26 | "url": "https://strapi.io" 27 | }, 28 | "license": "ISC" 29 | } 30 | -------------------------------------------------------------------------------- /demo/node-typescript/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@strapi/client': 12 | specifier: link:../.. 13 | version: link:../.. 14 | dotenv: 15 | specifier: 16.4.7 16 | version: 16.4.7 17 | devDependencies: 18 | '@types/node': 19 | specifier: 22.12.0 20 | version: 22.12.0 21 | typescript: 22 | specifier: 5.7.3 23 | version: 5.7.3 24 | 25 | packages: 26 | 27 | '@types/node@22.12.0': 28 | resolution: {integrity: sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==} 29 | 30 | dotenv@16.4.7: 31 | resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} 32 | engines: {node: '>=12'} 33 | 34 | typescript@5.7.3: 35 | resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} 36 | engines: {node: '>=14.17'} 37 | hasBin: true 38 | 39 | undici-types@6.20.0: 40 | resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} 41 | 42 | snapshots: 43 | 44 | '@types/node@22.12.0': 45 | dependencies: 46 | undici-types: 6.20.0 47 | 48 | dotenv@16.4.7: {} 49 | 50 | typescript@5.7.3: {} 51 | 52 | undici-types@6.20.0: {} 53 | -------------------------------------------------------------------------------- /demo/node-typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Language and Environment */ 4 | "allowSyntheticDefaultImports": true, 5 | 6 | /* Modules */ 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "module": "NodeNext", 10 | 11 | /* Emit */ 12 | "moduleResolution": "NodeNext", 13 | 14 | /* Interop Constraints */ 15 | 16 | "outDir": "./dist", 17 | "rootDir": "./src", 18 | "skipLibCheck": false, 19 | 20 | /* Type Checking */ 21 | "strict": true, 22 | 23 | /* Completeness */ 24 | "target": "ESNext" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/react-vite/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | .env 26 | -------------------------------------------------------------------------------- /demo/react-vite/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: 13 | 14 | ```js 15 | export default tseslint.config({ 16 | extends: [ 17 | // Remove ...tseslint.configs.recommended and replace with this 18 | ...tseslint.configs.recommendedTypeChecked, 19 | // Alternatively, use this for stricter rules 20 | ...tseslint.configs.strictTypeChecked, 21 | // Optionally, add this for stylistic rules 22 | ...tseslint.configs.stylisticTypeChecked, 23 | ], 24 | languageOptions: { 25 | // other options... 26 | parserOptions: { 27 | project: ['./tsconfig.node.json', './tsconfig.app.json'], 28 | tsconfigRootDir: import.meta.dirname, 29 | }, 30 | }, 31 | }); 32 | ``` 33 | 34 | You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: 35 | 36 | ```js 37 | // eslint.config.js 38 | import reactX from 'eslint-plugin-react-x'; 39 | import reactDom from 'eslint-plugin-react-dom'; 40 | 41 | export default tseslint.config({ 42 | plugins: { 43 | // Add the react-x and react-dom plugins 44 | 'react-x': reactX, 45 | 'react-dom': reactDom, 46 | }, 47 | rules: { 48 | // other rules... 49 | // Enable its recommended typescript rules 50 | ...reactX.configs['recommended-typescript'].rules, 51 | ...reactDom.configs.recommended.rules, 52 | }, 53 | }); 54 | ``` 55 | -------------------------------------------------------------------------------- /demo/react-vite/eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import globals from 'globals'; 3 | import reactHooks from 'eslint-plugin-react-hooks'; 4 | import reactRefresh from 'eslint-plugin-react-refresh'; 5 | import tseslint from 'typescript-eslint'; 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], 23 | }, 24 | } 25 | ); 26 | -------------------------------------------------------------------------------- /demo/react-vite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Strapi + React + Vite 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /demo/react-vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-vite", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@strapi/client": "link:../..", 14 | "@tailwindcss/vite": "^4.1.3", 15 | "framer-motion": "^12.6.3", 16 | "react": "^19.0.0", 17 | "react-dom": "^19.0.0", 18 | "react-hot-toast": "^2.5.2", 19 | "react-router-dom": "^7.5.0", 20 | "tailwindcss": "^4.1.3" 21 | }, 22 | "devDependencies": { 23 | "@eslint/js": "^9.21.0", 24 | "@types/node": "^22.14.0", 25 | "@types/react": "^19.0.10", 26 | "@types/react-dom": "^19.0.4", 27 | "@vitejs/plugin-react": "^4.3.4", 28 | "eslint": "^9.21.0", 29 | "eslint-plugin-react-hooks": "^5.1.0", 30 | "eslint-plugin-react-refresh": "^0.4.19", 31 | "typescript": "~5.7.2", 32 | "typescript-eslint": "^8.24.1", 33 | "vite": "^6.2.0" 34 | }, 35 | "pnpm": { 36 | "onlyBuiltDependencies": [ 37 | "esbuild" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /demo/react-vite/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strapi/client/f4a5d0dad9de23513f572700bc48ba9f1bafb3a9/demo/react-vite/public/favicon.ico -------------------------------------------------------------------------------- /demo/react-vite/src/app.tsx: -------------------------------------------------------------------------------- 1 | import { CollectionDemo } from '@/pages/CollectionDemo.tsx'; 2 | import { FilesDemo } from '@/pages/FilesDemo.tsx'; 3 | 4 | import { Home } from '@/pages/Home.tsx'; 5 | import { Toaster } from 'react-hot-toast'; 6 | import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; 7 | 8 | export default function App() { 9 | return ( 10 | <> 11 | 12 | 13 | } /> 14 | } /> 15 | } /> 16 | 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /demo/react-vite/src/components/CTA.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | type CTAProps = React.ButtonHTMLAttributes; 4 | 5 | export const CTA: React.FC = (props) => { 6 | return ( 7 |
8 |
9 | 16 |
17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /demo/react-vite/src/components/CategoryCard.tsx: -------------------------------------------------------------------------------- 1 | import type { Category } from '@/types.ts'; 2 | import { BASE_URL } from '@/utils/constants'; 3 | import React from 'react'; 4 | 5 | interface CategoryCardProps { 6 | category: Category; 7 | } 8 | 9 | export const CategoryCard: React.FC = ({ category }) => ( 10 | <> 11 |

{category.name}

12 | {category.image && ( 13 | {category.image.alternativeText 18 | )} 19 |

Slug: {category.slug ?? 'N/A'}

20 |

21 | Created At: {category.createdAt ? new Date(category.createdAt).toLocaleString() : 'N/A'} 22 |

23 | 24 | ); 25 | -------------------------------------------------------------------------------- /demo/react-vite/src/components/FileCard.tsx: -------------------------------------------------------------------------------- 1 | import type { File } from '@/types.ts'; 2 | import { BASE_URL } from '@/utils/constants.ts'; 3 | import React from 'react'; 4 | 5 | interface FileCardProps { 6 | file: File; 7 | } 8 | 9 | export const FileCard: React.FC = ({ file }) => ( 10 |
14 | {file.alternativeText 19 |

{file.name}

20 |

Size: {file.size} KB

21 |
22 | ); 23 | -------------------------------------------------------------------------------- /demo/react-vite/src/components/FileGallery.tsx: -------------------------------------------------------------------------------- 1 | import { FileCard } from '@/components/FileCard.tsx'; 2 | 3 | import type { File } from '@/types.ts'; 4 | import React from 'react'; 5 | 6 | interface FileGalleryProps { 7 | files: File[]; 8 | } 9 | 10 | export const FileGallery: React.FC = ({ files }) => ( 11 |
12 | {files.map((file) => ( 13 | 14 | ))} 15 |
16 | ); 17 | -------------------------------------------------------------------------------- /demo/react-vite/src/components/Nav.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link, useLocation } from 'react-router-dom'; 3 | 4 | export const Nav: React.FC = () => { 5 | const location = useLocation(); 6 | 7 | const navItems = [ 8 | { emoji: '🏠', text: 'Home', href: '/', color: 'var(--neon-green)' }, 9 | { emoji: '📚', text: 'Collections', href: '/demos/collections', color: 'var(--neon-pink)' }, 10 | { emoji: '📁', text: 'Files', href: '/demos/files', color: 'var(--neon-yellow)' }, 11 | ]; 12 | 13 | return ( 14 | 54 | ); 55 | }; 56 | -------------------------------------------------------------------------------- /demo/react-vite/src/components/QueryParamsPicker.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | interface QueryParamsPickerProps { 4 | queryParams: Record; 5 | onQueryChange: (param: string, checked: boolean) => void; 6 | } 7 | 8 | export const QueryParamsPicker: React.FC = ({ 9 | queryParams, 10 | onQueryChange, 11 | }) => ( 12 |
13 | {Object.keys(queryParams).map((param) => ( 14 | 23 | ))} 24 |
25 | ); 26 | -------------------------------------------------------------------------------- /demo/react-vite/src/components/QueryPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | interface QueryPreviewProps { 4 | query: Record; 5 | } 6 | 7 | export const QueryPreview: React.FC = ({ query }) => ( 8 |
9 |

Query Preview

10 |
11 |       {JSON.stringify(query, null, 2)}
12 |     
13 |
14 | ); 15 | -------------------------------------------------------------------------------- /demo/react-vite/src/hooks/useCollection.ts: -------------------------------------------------------------------------------- 1 | import { useStrapi } from '@/hooks/useStrapi.ts'; 2 | 3 | export const useCollection = (collectionName: string) => { 4 | const strapi = useStrapi(); 5 | 6 | return strapi.collection(collectionName); 7 | }; 8 | -------------------------------------------------------------------------------- /demo/react-vite/src/hooks/useFiles.ts: -------------------------------------------------------------------------------- 1 | import { useStrapi } from '@/hooks/useStrapi.ts'; 2 | 3 | import type { File } from '@/types.ts'; 4 | import React from 'react'; 5 | import toast from 'react-hot-toast'; 6 | 7 | export const useFiles = () => { 8 | const strapi = useStrapi(); 9 | const [files, setFiles] = React.useState([]); 10 | 11 | const fetchFiles = async () => { 12 | try { 13 | const response = await strapi.files.find(); 14 | setFiles(response); 15 | toast.success(`${response.length} files fetched successfully`); 16 | } catch (error) { 17 | toast.error(error instanceof Error ? error.message : `${error}`); 18 | } 19 | }; 20 | 21 | return [files, fetchFiles] as const; 22 | }; 23 | -------------------------------------------------------------------------------- /demo/react-vite/src/hooks/useStrapi.ts: -------------------------------------------------------------------------------- 1 | import { BASE_API_PATH, BASE_URL } from '@/utils/constants'; 2 | import type { Strapi } from '@strapi/client'; 3 | import { strapi } from '@strapi/client'; 4 | import { useMemo } from 'react'; 5 | 6 | export function useStrapi() { 7 | return useMemo(() => createClient(), []); 8 | } 9 | 10 | function createClient(): Strapi { 11 | const apiToken = process.env.FULL_ACCESS_TOKEN; 12 | 13 | if (!apiToken) { 14 | throw new Error('API token not found. Please set FULL_ACCESS_TOKEN in .env'); 15 | } 16 | 17 | const baseURL = `${BASE_URL}${BASE_API_PATH}`; 18 | 19 | return strapi({ baseURL, auth: apiToken }); 20 | } 21 | -------------------------------------------------------------------------------- /demo/react-vite/src/index.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | 3 | @tailwind utilities; 4 | 5 | @theme (dark) { 6 | /* Neon Colors */ 7 | --neon-pink: #ff2d76; 8 | --neon-blue: #00f9ff; 9 | --neon-purple: #b537f2; 10 | --neon-green: #3fff00; 11 | --neon-yellow: #ffff00; 12 | --neon-orange: #ff675e; 13 | 14 | /* Dark Theme Base Colors */ 15 | --bg-primary: #0a0a1f; 16 | --bg-secondary: #13132b; 17 | --bg-tertiary: #1c1c3b; 18 | --text-primary: #ffffff; 19 | --text-secondary: #a0a0c0; 20 | } 21 | 22 | @layer base { 23 | *, 24 | *::before, 25 | *::after { 26 | box-sizing: border-box; 27 | } 28 | 29 | *:focus { 30 | outline: none; 31 | } 32 | 33 | * { 34 | margin: 0; 35 | padding: 0; 36 | } 37 | 38 | html, 39 | body { 40 | @apply bg-[var(--bg-primary)] text-[var(--text-primary)]; 41 | 42 | font-family: 'Inter', system-ui, sans-serif; 43 | color: var(--text-primary); 44 | 45 | /* Ensure the body takes full height */ 46 | min-height: 100vh; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /demo/react-vite/src/layouts/Layout.tsx: -------------------------------------------------------------------------------- 1 | import { Nav } from '@/components/Nav.tsx'; 2 | import React from 'react'; 3 | 4 | interface LayoutProps { 5 | children: React.ReactNode; 6 | } 7 | 8 | export const Layout: React.FC = ({ children }) => { 9 | return ( 10 | <> 11 |