├── .env.sample ├── .gitignore ├── LICENSE ├── POSTGRES_DB_MOVE.md ├── README.md ├── UPGRADE_NOTES.md ├── extension_docs ├── endpoints │ └── endpoints.md ├── hooks │ ├── context.md │ ├── defineHook.md │ ├── events │ │ ├── auth.login.md │ │ └── users.create.md │ └── filter.md ├── operations │ └── context.md └── query_converter.html ├── extensions ├── directus-extension-app-bundle │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── hooks │ │ │ └── auth │ │ │ │ └── index.ts │ │ └── utils │ │ │ └── config.ts │ └── tsconfig.json └── modules │ ├── api-viewer │ └── index.js │ └── generate-types │ └── index.js ├── package-lock.json ├── package.json └── tasks ├── pg_backup_db.sh └── pg_install_postgis.sql /.env.sample: -------------------------------------------------------------------------------- 1 | #################################################################################################### 2 | ## General 3 | 4 | HOST="localhost" 5 | PORT=8055 6 | PUBLIC_URL="http://localhost:8055" 7 | 8 | #################################################################################################### 9 | ## Database 10 | DB_CLIENT="pg" 11 | DB_HOST="localhost" 12 | DB_PORT="5432" 13 | DB_DATABASE="directus" 14 | DB_USER="postgres" 15 | DB_PASSWORD="" 16 | DB_SSL="false" 17 | 18 | 19 | #################################################################################################### 20 | ## Rate Limiting 21 | 22 | RATE_LIMITER_ENABLED=true 23 | RATE_LIMITER_STORE=memory 24 | RATE_LIMITER_POINTS=25 25 | RATE_LIMITER_DURATION=1 26 | 27 | #################################################################################################### 28 | ## Cache 29 | 30 | CACHE_ENABLED=false 31 | 32 | #################################################################################################### 33 | ## File Storage 34 | 35 | # FILE_METADATA_ALLOW_LIST="*" 36 | 37 | STORAGE_LOCATIONS="local" 38 | STORAGE_LOCAL_DRIVER="local" 39 | STORAGE_LOCAL_ROOT="./uploads" 40 | 41 | # STORAGE_LOCATIONS="s3" 42 | # STORAGE_S3_DRIVER="s3" 43 | # STORAGE_S3_ROOT="directus-uploads" 44 | 45 | # STORAGE_S3_KEY="XXXXXXXXXXXXXXX" 46 | # STORAGE_S3_SECRET="XXXXXXXXXXXXXX" 47 | # STORAGE_S3_BUCKET="bucket-name" 48 | # STORAGE_S3_REGION="us-west-1" 49 | # STORAGE_S3_ENDPOINT="s3.amazonaws.com" 50 | # STORAGE_S3_ACL="private" 51 | 52 | #################################################################################################### 53 | ## Security 54 | 55 | KEY="db43b7af-xxxx-xxxx-xxxx-20825dc96bdc" 56 | SECRET="uXTlkJXXXgFgoUXXXdUjSPoXXXXXXXXj86K" 57 | 58 | ACCESS_TOKEN_TTL="15m" 59 | REFRESH_TOKEN_TTL="7d" 60 | REFRESH_TOKEN_COOKIE_SECURE=false 61 | REFRESH_TOKEN_COOKIE_SAME_SITE="lax" 62 | REFRESH_TOKEN_COOKIE_NAME="directus_refresh_token" 63 | 64 | #################################################################################################### 65 | ## Auth Providers 66 | 67 | # AUTH_PROVIDERS="facebook,google" 68 | # AUTH_DEFAULT_ROLE_ID="xxxxx-xxxxx-xxxxx-xxxxxxx" 69 | 70 | # AUTH_FACEBOOK_DRIVER="oauth2" 71 | # AUTH_FACEBOOK_CLIENT_ID="string:1234567890" 72 | # AUTH_FACEBOOK_CLIENT_SECRET="xxxxxxxxxxxxxxxxxx" 73 | 74 | # AUTH_FACEBOOK_IDENTIFIER_KEY="id" 75 | # AUTH_FACEBOOK_EMAIL_KEY="email" 76 | # AUTH_FACEBOOK_FIRST_NAME_KEY="first_name" 77 | # AUTH_FACEBOOK_LAST_NAME_KEY="last_name" 78 | 79 | # AUTH_FACEBOOK_ICON="facebook" 80 | # AUTH_FACEBOOK_ALLOW_PUBLIC_REGISTRATION="true" 81 | # AUTH_FACEBOOK_DEFAULT_ROLE_ID="xxxxx-xxxxx-xxxxx-xxxxxxx" 82 | 83 | # # v17.0 Auth URLs 84 | # AUTH_FACEBOOK_SCOPE="public_profile" 85 | # AUTH_FACEBOOK_AUTHORIZE_URL="https://www.facebook.com/v17.0/dialog/oauth" 86 | # AUTH_FACEBOOK_ACCESS_URL="https://graph.facebook.com/v17.0/oauth/access_token" 87 | # AUTH_FACEBOOK_PROFILE_URL="https://graph.facebook.com/v17.0/me?fields=id,name,email,first_name,last_name" 88 | 89 | # OLD facebook settings 90 | # AUTH_FACEBOOK_SCOPE="email" 91 | # AUTH_FACEBOOK_AUTHORIZE_URL="https://www.facebook.com/dialog/oauth" 92 | # AUTH_FACEBOOK_ACCESS_URL="https://graph.facebook.com/oauth/access_token" 93 | # AUTH_FACEBOOK_PROFILE_URL="https://graph.facebook.com/me?fields=email" 94 | 95 | # Google 96 | # AUTH_GOOGLE_DRIVER="openid" 97 | # AUTH_GOOGLE_CLIENT_ID="XXXXXXXXXXXXXXXXX@d.apps.googleusercontent.com" 98 | # AUTH_GOOGLE_CLIENT_SECRET="XXXXXX-XXXXXX-XXXXX-XXXXXX" 99 | # AUTH_GOOGLE_ISSUER_URL="https://accounts.google.com" 100 | # AUTH_GOOGLE_IDENTIFIER_KEY="email" 101 | # AUTH_GOOGLE_ICON="google" 102 | # AUTH_GOOGLE_ALLOW_PUBLIC_REGISTRATION="true" 103 | # AUTH_GOOGLE_DEFAULT_ROLE_ID="xxxxx-xxxxx-xxxxx-xxxxxxx" 104 | 105 | #################################################################################################### 106 | ## Extensions 107 | 108 | EXTENSIONS_PATH="./extensions" 109 | EXTENSIONS_AUTO_RELOAD="true" 110 | 111 | #################################################################################################### 112 | ## Email 113 | 114 | EMAIL_FROM="no-reply@ched.dev" 115 | 116 | # Sendmail 117 | # EMAIL_TRANSPORT="sendmail" 118 | # EMAIL_SENDMAIL_NEW_LINE="unix" 119 | # EMAIL_SENDMAIL_PATH="/usr/sbin/sendmail" 120 | 121 | # Sendgrid 122 | EMAIL_TRANSPORT="sendgrid" 123 | SENDGRID_SENDER_ID="no-reply@ched.dev" 124 | EMAIL_SENDGRID_API_KEY="SG.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 125 | 126 | #################################################################################################### 127 | ## Bootstrap 128 | 129 | ADMIN_EMAIL="cheddevdev@gmail.com" 130 | ADMIN_PASSWORD="password" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules 3 | pg_backup*.sql 4 | *.log 5 | uploads/* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 ched.dev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /POSTGRES_DB_MOVE.md: -------------------------------------------------------------------------------- 1 | # Moving Postgres DB from one server to another 2 | 3 | - Backup DB from existing server `npm run backup-db` 4 | - Modify backup file: 5 | - If new db user has changed: 6 | - Replace existing db user text, ex: "postgres" to "newusername" 7 | - If you get timescaledb errors: 8 | - Comment out "timescaledb" lines 9 | - Comment out "COPY _timescaledb" lines 10 | - If you have operations with run scripts: 11 | - JSON fields will not accept newlines, tabs, or double quotes, to fix: 12 | - Within "COPY public.directus_operations": 13 | - Replace "\n\t" with empty string, then replace "\n" with empty string 14 | - Replace double quotes " with escaped single quotes \' or backticks ` 15 | - Within "COPY public.directus_activity" and "COPY public.directus_revisions": 16 | - Fix unacceptable characters or remove all revisions containing invalid JSON fields 17 | - Connect to your new database via psql cli 18 | - `psql -h host -d database -U user` 19 | - Import the backup file 20 | - `\i 'path/to/file.sql'` 21 | - Fix any errors you might see 22 | - Verify all tables have expected data 23 | - May need to fix any "Run Scripts" you modified for import 24 | - If you have pg_hba.conf error & self-signed certificate error, add the following to your env config 25 | - Remove DB_SSL="true" if it's there 26 | - DB_SSL__REJECT_UNAUTHORIZED="true" 27 | - DB_SSL__CA="-----BEGIN CERTIFICATE----- 28 | ... 29 | -----END CERTIFICATE-----" 30 | - Update environment variables to new database connection info and verify Directus admin still loads, along with Flows and Operations. 31 | 32 | ## Notes 33 | 34 | Successfully moved database from Railway to Supabase with these instructions. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Directus Init 2 | 3 | > A preconfigured Directus install with PostgreSQL - intended for extension development or self-hosting 4 | 5 | by [ched.dev](https://ched.dev) 6 | 7 | Features: 8 | - Default [Directus.io](https://directus.io) ^10.6.0 installation with PostgreSQL 9 | - Install SQL command to support location data in PostgreSQL 10 | - Bash script to save database backups (run `npm run backup-db`) 11 | - Directus schema snapshots npm commands (run `npm run snapshot`) 12 | - Example [extension bundle](https://docs.directus.io/extensions/bundles.html) to add extensions to (includes example hooks for authentication & user creation) 13 | - [API Viewer Module](https://github.com/u12206050/directus-extension-api-viewer-module/releases/tag/1.1.1) included in extensions 14 | - [Generate Types Module](https://github.com/maltejur/directus-extension-generate-types/releases/tag/0.5.1) included in extensions 15 | - [Additional Directus extensions documentation](./extension_docs/) included in this repo 16 | 17 | ## Install 18 | 19 | Steps: 20 | - [Download a zip](https://github.com/ched-dev/directus-init/archive/refs/heads/main.zip) of this repo, extract it, and rename the folder to your project name and change into the new folder 21 | - Create a `.env` with contents from `.env.sample` and [update config options](https://docs.directus.io/self-hosted/config-options.html) as desired 22 | - Create your PostgreSQL DB wherever you plan to host or locally in CLI run `createdb directus`, then add connection options to `.env` 23 | - (Optional) Run the `tasks/pg_install_postgis.sql` in your database if you want to support location data 24 | - Run `npm run build` (installs packages & builds extensions) 25 | - Run `npx directus bootstrap` (creates local folders and runs initial db one-time setup) 26 | - Create an `uploads` directory if you are storing files locally, alternatively set the S3 config options in `.env` 27 | - Run `npm start` (use this each time to boot up server) 28 | 29 | ## Directus Studio Setup 30 | 31 | After you've installed everything and are running the Directus Studio, you should update a few things. 32 | 33 | **In Settings > Project Settings** 34 | - Update Project Name as this will be used for email sender name 35 | - Update branding and style (color) to make this instance yours 36 | - Turn on the API Viewer Module & Generate Types Module in the sidebar (Modules > check to enable) 37 | - Set a requirement for strong passwords (Security > Auth Password Policy) & login attempts 38 | 39 | **In Settings > Roles & Permissions** 40 | - Create a role for non-admin users (if needed) 41 | - Require 2FA on any roles you think should have it 42 | 43 | ## Extensions 44 | 45 | We've created a bundle which can hold all of your custom extensions. This approach allows you to add it's own dependencies in one place, as well as integrate into the build process easily. 46 | 47 | See the `extensions/directus-extension-app-bundle/README.md` file to learn more about adding extensions. 48 | 49 | If you are developing extensions, open a second terminal to watch and rebuild with `npm run extensions`. 50 | 51 | ## Upgrading 52 | 53 | If this repos Directus version is behind the latest, you can upgrade it following the [Directus Upgrades & Migrations Guide](https://docs.directus.io/self-hosted/upgrades-migrations.html). 54 | 55 | We've created a [UPGRADE_NOTES.md](./UPGRADE_NOTES.md) file which outlines all the new features and breaking changes since Directus v9.5.2. This will help you decide what fixes might be required before and after you update. 56 | 57 | # License 58 | 59 | Directus is covered under [BSL-1.1 License](https://github.com/directus/directus/blob/main/license). Any additional code in this repo is covered under MIT license. -------------------------------------------------------------------------------- /UPGRADE_NOTES.md: -------------------------------------------------------------------------------- 1 | # Directus Upgrade Notes 2 | 3 | > An abbreviation of the full [Directus Release Notes](https://github.com/directus/directus/releases) highlighting breaking changes and new features 4 | 5 | \*\* Denotes a breaking change 6 | 7 | | Version | Notes | 8 | | ------- | ----- | 9 | | 10.8.3 [^](https://github.com/directus/directus/releases/tag/v10.8.3) | Fixed GraphQL Content Versions \*\*, Renamed the type `ExtensionItem` to `DirectusExtension`, Added `EXTENSIONS_MUST_LOAD` config option [^](https://docs.directus.io/self-hosted/config-options.html#extensions) | 10 | | 10.8.0 [^](https://github.com/directus/directus/releases/tag/v10.8.0) | Lots of new theming options with theme-selector \*\*, Added theme extension type [^](https://docs.directus.io/extensions/themes.html) | 11 | | 10.7.2 [^](https://github.com/directus/directus/releases/tag/v10.7.2) | Added support for navigation dividers, configurable borders | 12 | | 10.7.1 [^](https://github.com/directus/directus/releases/tag/v10.7.1) | `create-directus-project` switched from CJS to ESM, changed license from GPL to MIT \*\* | 13 | | 10.7.0 [^](https://github.com/directus/directus/releases/tag/v10.7.0) | Allow enabling/disable extensions through app and api (see settings page) \*\*, Added support for Content Versioning [^](https://docs.directus.io/guides/headless-cms/content-versioning.html), Support for uploading custom favicons [^](https://docs.directus.io/user-guide/settings/theming.html#branding) | 14 | | 10.6.4 [^](https://github.com/directus/directus/releases/tag/v10.6.4) | Moved `@directus/constants`, `@directus/types`, `@directus/utils` into one package `@directus/extensions` \*\* [^](https://github.com/directus/directus/pull/19922), Added `readAssetRaw()` to `@directus/sdk` [^](https://github.com/directus/directus/pull/20041/files#diff-c49a51d0dd22dafbfce0de626c647b15c90a81b0b763539cb0f6fd016e917c3bR160), Move all errors to `@directus/errors` [^](https://github.com/directus/directus/tree/main/packages/errors) | 15 | | 10.6.3 [^](https://github.com/directus/directus/releases/tag/v10.6.3) | If you saved field conditions in 10.6.2 release they need to be manually fixed in 10.6.3+ \*\* [^](https://github.com/directus/directus/issues/19757#issuecomment-1734162756) | 16 | | 10.6.2 [^](https://github.com/directus/directus/releases/tag/v10.6.2) | `@directus/sdk` changed `asSearch` to `withSearch` \*\* [^](https://github.com/directus/directus/pull/19354), Fix for including auth credentials with fetch [^](https://github.com/directus/directus/pull/19354) | 17 | | 10.6 [^](https://github.com/directus/directus/releases/tag/v10.6.0) | Replaced vm2 with isolated-vm for sandboxing the "Run Script"-Operation in Flows (removes npm package use in Flows)\*\* [^](https://github.com/directus/directus/pull/19332), Added (JWT) operation to Flows [^](https://docs.directus.io/app/flows/operations.html#json-web-token-jwt) | 18 | | 10.5 [^](https://github.com/directus/directus/releases/tag/v10.5.0) | New SDK released [^](https://docs.directus.io/packages/@directus/sdk/), Supabase storage for files [^](https://docs.directus.io/self-hosted/config-options.html#supabase-supabase) | 19 | | 10.4 [^](https://github.com/directus/directus/releases/tag/v10.4.0) | Removed `context.exceptions` in extensions\*\*, Added `@directus/errors` instead [^](https://docs.directus.io/packages/@directus/errors/), Moved Redis env vars\*\* [^](https://github.com/directus/directus/releases/tag/v10.4.0), Drop memcached support\*\*, Beta SDK | 20 | | 10.3 [^](https://github.com/directus/directus/releases/tag/v10.3.0) | Added Websocket support to REST and GraphQL [^](https://docs.directus.io/guides/real-time/getting-started/) | 21 | | 10.2 [^](https://github.com/directus/directus/releases/tag/v10.2.0) | Live preview functionality [^](https://docs.directus.io/guides/headless-cms/live-preview/), added env vars `FILES_MAX_UPLOAD_SIZE` and `FILES_MIME_TYPE_ALLOW_LIST` [^](https://docs.directus.io/self-hosted/config-options.html#upload-limits) | 22 | | 10.1.1 [^](https://github.com/directus/directus/releases/tag/v10.1.1) | Vue 3.3 in Admin | 23 | | 10.1 [^](https://github.com/directus/directus/releases/tag/v10.1.0) | Added Kanban Layout [^](https://docs.directus.io/user-guide/content-module/layouts.html#kanban-layout), Additional Insight Panels [^](https://docs.directus.io/user-guide/insights/panels.html), Block editor interface [^](https://docs.directus.io/app/data-model/fields/text-numbers.html#block-editor), Pressure based rate limiter [^](https://docs.directus.io/self-hosted/config-options.html#pressure-based-rate-limiter), Extensions building to ESM | 24 | | 10.0 [^](https://github.com/directus/directus/releases/tag/v10.0.0) | New BSL 1.1 License [^](https://directus.io/bsl-faq/) | 25 | | 9.26 [^](https://github.com/directus/directus/releases/tag/v9.26.0) | Mail templates in Flows [^](https://docs.directus.io/extensions/email-templates.html) | 26 | | 9.25 [^](https://github.com/directus/directus/releases/tag/v9.25.0) | API changed from CJS to ESM (re-test extensions)\*\*, support for AVIF files, Migrate to Material Symbols (more icons) [^](https://docs.directus.io/user-guide/overview/glossary.html#material-icons) | 27 | | 9.23.4 [^](https://github.com/directus/directus/releases/tag/v9.23.4) | GraphQL `expires` property changed from int to string\*\* [^](https://github.com/directus/directus/releases/tag/v9.23.4) | 28 | | 9.23.2 [^](https://github.com/directus/directus/releases/tag/v9.23.2) | Global rate limiter introduced [^](https://docs.directus.io/self-hosted/config-options.html#rate-limiting) | 29 | | 9.23 [^](https://github.com/directus/directus/releases/tag/v9.23.0) | New `/schema` endpoints [^](https://docs.directus.io/reference/system/schema.html) | 30 | | 9.22.2 [^](https://github.com/directus/directus/releases/tag/v9.22.2) | Top level extensions support Ex: `extensions/directus-extension-*` | 31 | | 9.22 [^](https://github.com/directus/directus/releases/tag/v9.22.0) | Node v18 requirement\*\*, Replace `@directus/drive`\*\*, Add `REGION` for S3 env config, File metadata abstraction replaced | 32 | | 9.21 [^](https://github.com/directus/directus/releases/tag/v9.21.0) | Add Bundle extension type [^](https://docs.directus.io/extensions/bundles.html) | 33 | | 9.20 [^](https://github.com/directus/directus/releases/tag/v9.20.0) | Add SAML support in Auth [^](https://docs.directus.io/self-hosted/sso-examples.html#saml-examples) | 34 | | 9.17.1 [^](https://github.com/directus/directus/releases/tag/v9.17.1) | Add SendGrid email transport [^](https://docs.directus.io/self-hosted/config-options.html#sendgrid-sendgrid) | 35 | | 9.13 [^](https://github.com/directus/directus/releases/tag/v9.13.0) | Insights 2.0 [^](https://docs.directus.io/user-guide/insights/dashboards.html) | 36 | | 9.12 [^](https://github.com/directus/directus/releases/tag/v9.12.0) | Added Data Flows [^](https://docs.directus.io/app/flows.html) | 37 | | 9.7 [^](https://github.com/directus/directus/releases/tag/v9.7.0) | Update `CORS_ENABLED` and `CORS_ORIGIN` env vars to default disabled\*\* [^](https://docs.directus.io/self-hosted/config-options.html#cors) | 38 | | 9.6 [^](https://github.com/directus/directus/releases/tag/v9.6.0) | New base theme in Data Studio [^](https://docs.directus.io/extensions/themes.html) | 39 | | 9.5.2 [^](https://github.com/directus/directus/releases/tag/v9.5.2) | Changed SDK `.readMany()` to `.readByQuery()` | 40 | -------------------------------------------------------------------------------- /extension_docs/endpoints/endpoints.md: -------------------------------------------------------------------------------- 1 | # Extensions: Endpoints 2 | 3 | Endpoints are basically passed as middleware to ExpressJS under the hood. You should be familiar enough with ExpressJS to use the `router`, `req` and `res` APIs. 4 | 5 | ## `req` properties 6 | 7 | Additional properties from Directus: 8 | ```js 9 | req.schema; // Directus Schema access (req.schema.collections) 10 | req.token; // Directus authorization token (no bearer) 11 | req.accountablility; // Directus authenticated user permissions 12 | ``` 13 | 14 | Common ExpressJS properties: 15 | ```js 16 | req.body; // Body contents of the request, already parsed 17 | req.params; // Query params from URL (`/endpoint/:param`) 18 | req.query; // Query string params from URL (`?example=true`) 19 | ``` 20 | 21 | __Full `req` Schema__ 22 | ```sh 23 | GET /test/dynamic?queryParam=true 24 | 25 | req IncomingMessage { 26 | rawHeaders: [ 27 | 'Host', 28 | 'localhost:8055', 29 | 'User-Agent', 30 | 'insomnia/2023.4.0', 31 | 'Content-Type', 32 | 'application/json', 33 | 'Authorization', 34 | 'Bearer ey......yE', 35 | 'Accept', 36 | '*/*', 37 | 'Content-Length', 38 | '41' 39 | ], 40 | url: '/dynamic?queryParam=true', 41 | method: 'GET', 42 | statusCode: null, 43 | statusMessage: null, 44 | # Express Client `req.client` 45 | client: Socket { 46 | connecting: false, 47 | allowHalfOpen: true, 48 | server: Server { 49 | ... 50 | }, 51 | parser: HTTPParser { 52 | ... 53 | }, 54 | on: [Function: socketListenerWrap], 55 | addListener: [Function: socketListenerWrap], 56 | prependListener: [Function: socketListenerWrap], 57 | setEncoding: [Function: socketSetEncoding], 58 | }, 59 | next: [Function: next], 60 | baseUrl: '/test', 61 | originalUrl: '/test/dynamic?queryParam=true', 62 | params: { testParam: 'dynamic' }, # Endpoint `/test/:testParam` 63 | query: { queryParam: 'true' }, # `?queryParam=true` 64 | id: 3, 65 | log: EventEmitter { 66 | trace: [Function: noop], 67 | debug: [Function: noop], 68 | info: [Function: LOG], 69 | warn: [Function: LOG], 70 | error: [Function: LOG], 71 | fatal: [Function (anonymous)], 72 | }, 73 | allLogs: [ 74 | EventEmitter { 75 | trace: [Function: noop], 76 | debug: [Function: noop], 77 | info: [Function: LOG], 78 | warn: [Function: LOG], 79 | error: [Function: LOG], 80 | fatal: [Function (anonymous)], 81 | } 82 | ], 83 | # Express `req.body` 84 | body: { email: 'test@gmail.com' }, 85 | length: undefined, 86 | secret: undefined, 87 | cookies: [Object: null prototype] {}, 88 | signedCookies: [Object: null prototype] {}, 89 | token: 'ey......yE', 90 | # Directus Accountability of logged in user `req.accountability` 91 | accountability: { 92 | user: 'ea19d63c-xxxx-xxxx-xxxx-ad24bc2b98ad', # or `null` 93 | role: '62c04234-xxxx-xxxx-xxxx-01600e46de49', # or `null` 94 | admin: true, 95 | app: true, 96 | ip: '::1', 97 | userAgent: 'insomnia/2023.4.0', 98 | permissions: [] 99 | }, 100 | sanitizedQuery: { fields: [ '*' ] }, 101 | # Directus Schema access `req.schema` 102 | schema: { 103 | collections: { 104 | # System collections 105 | directus_roles: [Object], 106 | directus_folders: [Object], 107 | directus_activity: [Object], 108 | directus_files: [Object], 109 | directus_collections: [Object], 110 | directus_users: [Object], 111 | directus_fields: [Object], 112 | directus_permissions: [Object], 113 | directus_settings: [Object], 114 | directus_sessions: [Object], 115 | directus_revisions: [Object], 116 | directus_webhooks: [Object], 117 | directus_migrations: [Object], 118 | directus_presets: [Object], 119 | directus_relations: [Object], 120 | directus_panels: [Object], 121 | directus_flows: [Object], 122 | directus_notifications: [Object], 123 | directus_shares: [Object], 124 | directus_translations: [Object], 125 | directus_operations: [Object], 126 | directus_dashboards: [Object], 127 | # Created collections 128 | topics: [Object], 129 | video_pages: [Object], 130 | video_pages_topics: [Object], 131 | video_pages_directus_roles: [Object], 132 | test_collection: [Object] 133 | }, 134 | relations: [ 135 | [Object], ... 136 | ] 137 | }, 138 | route: Route { 139 | path: '/:testParam', 140 | stack: [ [Layer] ], 141 | methods: { get: true } 142 | }, 143 | } 144 | ``` -------------------------------------------------------------------------------- /extension_docs/hooks/context.md: -------------------------------------------------------------------------------- 1 | # Context usage in Hooks 2 | 3 | The `context` argument contains access to Directus internals which are useful when developing extensions. 4 | 5 | The `context` argument is used in two formats: 6 | - Inside a `defineHook()` callback (better described as Hook `context`) 7 | - Inside a `filter()` or `action()` callback (better described as Event `context`) 8 | 9 | `defineHook()` callback runs when the application is started up and does not have information about the logged in user. 10 | 11 | `filter()` and `action()` callbacks run when an event is emitted by Directus and will have user information included. 12 | 13 | ## `defineHook()` context 14 | 15 | The `defineHook()` is used to create the default export for a Hook extension. Within it, you will have a specific hook event such as `filter()`, `action()`, etc. 16 | 17 | ```js 18 | defineHook.context [ 19 | 'services', 20 | 'exceptions', 21 | 'env', 22 | 'database', 23 | 'emitter', 24 | 'logger', 25 | 'getSchema' // async method 26 | ] // Object.keys() 27 | ``` 28 | 29 | ### Services: `context.services` 30 | 31 | Services are used to connect to Directus data. 32 | 33 | ```js 34 | context.services [ 35 | 'ActivityService', 'AssetsService', 36 | 'AuthenticationService', 'AuthorizationService', 37 | 'CollectionsService', 'DashboardsService', 38 | 'ExportService', 'FieldsService', 39 | 'FilesService', 'FlowsService', 40 | 'FoldersService', 'GraphQLService', 41 | 'ImportService', 'ItemsService', 42 | 'MailService', 'MetaService', 43 | 'NotificationsService', 'OperationsService', 44 | 'PanelsService', 'PayloadService', 45 | 'PermissionsService', 'PresetsService', 46 | 'RelationsService', 'RevisionsService', 47 | 'RolesService', 'SchemaService', 48 | 'ServerService', 'SettingsService', 49 | 'SharesService', 'SpecificationService', 50 | 'TFAService', 'TranslationsService', 51 | 'UsersService', 'UtilsService', 52 | 'WebhooksService' 53 | ] 54 | ``` 55 | 56 | A few services to be familiar with are documented below. 57 | 58 | #### ItemsService: `context.services.ItemsService()` 59 | 60 | The Service used to connect to any of your Collection's Items. 61 | 62 | ```js 63 | // Example: Getting many items via ItemsService 64 | const blogPostsService = new context.services.ItemsService("blog_posts", { 65 | schema: await context.getSchema(), 66 | }); 67 | 68 | const blogPosts = await blogPostsService.readMany([...ids], { 69 | fields: [ 70 | "title", 71 | ], 72 | }); 73 | ``` 74 | 75 | ```js 76 | // Example: Getting a single user via ItemsService 77 | const userService = new context.services.ItemsService("directus_users", { 78 | schema: await context.getSchema(), 79 | }); 80 | 81 | const user = await userService.readOne(user_id, { 82 | fields: [ 83 | "email", 84 | "first_name", 85 | "last_name" 86 | ], 87 | }); 88 | ``` 89 | 90 | ### Exceptions: `context.exceptions` (<= v10.3.x) 91 | 92 | > Removed in Directus v10.4. use `@directus/errors` instead 93 | 94 | Directus provides common exceptions for throwing in your extension code. 95 | 96 | See a full list of available exceptions in the [exceptions/*.ts files](https://github.com/directus/directus/tree/v10.3.0/api/src/exceptions) of the github repo. 97 | 98 | Usage: 99 | ```js 100 | const { InvalidPayloadException } = context.exceptions; 101 | 102 | throw new InvalidPayloadException(`Missing required "email"`); 103 | ``` 104 | 105 | ### Environment: `context.env` 106 | 107 | Environment variables can be accessed using `context.env` as well as `process.env`. You get the benefit of type casting and nesting if you use `context.env` (see [config options docs](https://docs.directus.io/self-hosted/config-options.html#type-casting-and-nesting)). 108 | 109 | ```js 110 | context.env.PUBLIC_URL; 111 | context.env.AUTH_DEFAULT_ROLE_ID; 112 | context.env.SENDGRID_SENDER_ID; 113 | ``` 114 | 115 | ### Schema: `context.getSchema()` 116 | 117 | To use the Services you will need to pass the schema. You can access the schema via an async method: 118 | 119 | ```js 120 | await context.getSchema() 121 | ``` 122 | 123 | **WARNING:** When you are within a filter or action, you will have access to the alternate `context` which will have `context.schema` as a property. Be aware of which is available and which you are using. Prefer to use `context.schema` if available over `await context.getSchema()` as it will refer to the schema available to the current user. `context.getSchema()` will return the full Directus schema. 124 | 125 | 126 | 127 | --- 128 | 129 | 130 | 131 | ## `filter()` & `action()` context 132 | 133 | The context for filters and actions is simplified but includes information about the user making the request. 134 | 135 | ```js 136 | context: [ 'database', 'schema', 'accountability' ] // Object.keys() 137 | ``` 138 | 139 | The values on this context are reflective the the user triggering the event. This means your values on `schema` and `accountability` will be reflective of the user's role & permissions. 140 | 141 | ### Schema: `context.schema` 142 | 143 | The Schema available to the user who triggered this event. Mostly used to pass along to any Service that requires it. 144 | 145 | When passing `context` to Services, it's best to pass the whole `context` object as it will include only data the user has access to. 146 | 147 | ```js 148 | // NOTE: `hookContext` is referring to `context` from `defineHook()` while `context` is referring to the user specific context 149 | filter("auth.login", async (payload, meta, context) => { 150 | const userService = new hookContext.services.ItemsService("directus_users", context); 151 | 152 | const user = await userService.readOne(meta.user, { 153 | fields: [ 154 | "email", 155 | "first_name", 156 | "last_name" 157 | ], 158 | }); 159 | }); 160 | ``` 161 | 162 | ### Accountability: `context.accountability` 163 | 164 | The role & permissions available to the user who triggered this event. Used to pass along to any Service that requires it, or if you need to allow / deny based on permissions. 165 | 166 | When passing `context` to Services, it's best to pass the whole `context` object as it will include only data the user has access to. 167 | 168 | ```js 169 | // NOTE: `services` is referring to `context.services` from `defineHook()` 170 | filter("auth.login", async (payload, meta, context) => { 171 | const userService = new services.ItemsService("directus_users", context); 172 | 173 | const user = await userService.readOne(meta.user, { 174 | fields: [ 175 | "email", 176 | "first_name", 177 | "last_name" 178 | ], 179 | }); 180 | }); 181 | ``` 182 | 183 | If you want to override accountability to provide admin access for specific actions (such as inviting a user), you can pass it in when creating the service: 184 | 185 | ```js 186 | const { services, getSchema } = context 187 | 188 | const usersService = new services.UsersService({ 189 | accountability: { 190 | // user: uuid | null, // access based on user 191 | // role: uuid | null, // access based on role 192 | admin: true, // admin access (everything) 193 | // app: boolean, // app access 194 | }, 195 | schema: await getSchema() 196 | }) 197 | 198 | // requires admin access 199 | await usersService.inviteUser(email, USER_DEFAULT_ROLE_ID, INVITE_URL) 200 | ``` -------------------------------------------------------------------------------- /extension_docs/hooks/defineHook.md: -------------------------------------------------------------------------------- 1 | # `defineHook()` 2 | 3 | The entrypoint to define custom hooks within Directus. 4 | 5 | ```js 6 | export default defineHook((hookEvents, hookContext) => { 7 | // event hooks 8 | hookEvents.filter("auth.login", (payload, meta, context) => ...) 9 | hookEvents.action("auth.login", (meta, context) => ...) 10 | hookEvents.init("middlewares.after", (meta) => ...) 11 | hookEvents.schedule("*/15 * * * *", () => ...) 12 | hookEvents.embed("head", () => ...) 13 | }); 14 | ``` 15 | 16 | ## Context `hookContext` 17 | 18 | See the full explanation of the `hookContext` in the [context documentation](./context.md). -------------------------------------------------------------------------------- /extension_docs/hooks/events/auth.login.md: -------------------------------------------------------------------------------- 1 | # `auth.login` Event 2 | 3 | Runs when a user authenticates using **ANY** of the authentication providers. 4 | 5 | ## Providers 6 | 7 | Response varies based on the Provider. 8 | 9 | ### `default` Provider 10 | 11 | ```js 12 | filter: auth.login { 13 | payload: { 14 | email: 'cheddevdev@gmail.com', 15 | password: 'password', 16 | mode: 'cookie' 17 | }, 18 | meta: { 19 | event: 'auth.login', 20 | status: 'pending', 21 | user: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX', 22 | provider: 'default' 23 | }, 24 | context: [ 'database', 'schema', 'accountability' ] // Object.keys() 25 | } 26 | ``` 27 | 28 | ```js 29 | action: auth.login { 30 | meta: { 31 | event: 'auth.login', 32 | payload: { 33 | email: 'cheddevdev@gmail.com', 34 | password: 'password', 35 | mode: 'cookie' 36 | }, 37 | status: 'success', 38 | user: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX', 39 | provider: 'default' 40 | }, 41 | context: [ 'database', 'schema', 'accountability' ] // Object.keys() 42 | } 43 | ``` 44 | 45 | ### `facebook` Facebook OAuth Provider 46 | 47 | ```js 48 | filter: auth.login { 49 | payload: { 50 | code: 'xxxxxxxxxx', 51 | codeVerifier: 'xxxxxxxxxx', 52 | state: 'xxxxxxxxxx' 53 | }, 54 | meta: { 55 | event: 'auth.login', 56 | status: 'pending', 57 | user: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX', 58 | provider: 'facebook' 59 | } 60 | } 61 | ``` -------------------------------------------------------------------------------- /extension_docs/hooks/events/users.create.md: -------------------------------------------------------------------------------- 1 | # `users.create` Event 2 | 3 | Triggers when a user is created in Directus. This happens with **ANY** provider configuration. 4 | 5 | ## Providers 6 | 7 | Response varies based on the Provider. 8 | 9 | ### `default` Provider 10 | 11 | ```js 12 | filter: users.create { 13 | payload: { 14 | first_name: 'the', 15 | last_name: 'dude', 16 | email: 'test@gmail.com', 17 | password: 'password' 18 | }, 19 | meta: { collection: 'directus_users' } 20 | } 21 | ``` 22 | 23 | ```js 24 | action: users.create { 25 | meta: { 26 | payload: { 27 | first_name: 'the', 28 | last_name: 'dude', 29 | email: 'test@gmail.com', 30 | password: 'password' 31 | }, 32 | key: 'XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX', 33 | collection: 'directus_users' 34 | } 35 | } 36 | ``` 37 | 38 | ### `facebook` Facebook OAuth Provider 39 | 40 | ```js 41 | filter: users.create { 42 | payload: { 43 | provider: 'facebook', 44 | first_name: 'ched', 45 | last_name: 'dev', 46 | email: undefined, 47 | external_identifier: '1234567890', 48 | role: 'XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX', 49 | auth_data: undefined 50 | }, 51 | meta: { event: 'users.create', collection: 'directus_users' } 52 | } 53 | ``` -------------------------------------------------------------------------------- /extension_docs/hooks/filter.md: -------------------------------------------------------------------------------- 1 | # Filter (Blocking) Extensions 2 | 3 | In Directus, a Filter is a before hook allowing you to modify the payload before being processed, among other things. 4 | 5 | ## Example Filter 6 | 7 | ```js 8 | filter("auth.login", async (payload, meta, context) => { 9 | console.log("filter: auth.login", { 10 | payload, meta, context: Object.keys(context) 11 | }); 12 | }); 13 | ``` 14 | 15 | ## Example Payloads 16 | 17 | Payloads change based on the event and data submitted. Here is a general example: 18 | 19 | ```js 20 | // filter: auth.login 21 | { 22 | payload: { 23 | email: 'cheddevdev@gmail.com', 24 | password: 'password', 25 | mode: 'cookie' 26 | }, 27 | meta: { 28 | event: 'auth.login', 29 | status: 'pending', 30 | user: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX', 31 | provider: 'default' 32 | }, 33 | context: [ 'database', 'schema', 'accountability' ] // Object.keys() 34 | } 35 | ``` 36 | 37 | See a full list of responses in the `./events/*.md` files. -------------------------------------------------------------------------------- /extension_docs/operations/context.md: -------------------------------------------------------------------------------- 1 | # Context usage in Operations 2 | 3 | Operation `context` is mostly the same as the [hooks context](../hooks/context.md). Please refer there for the majority of properties. We will only document what is exclusive to operations in this file. 4 | 5 | ## Flow & Step Data: `context.data` 6 | 7 | With `context.data` you can tap in to all of the prior operations results. This allows you to use data from another operation or special values such as `$trigger` or `$last`. 8 | 9 | The following is an example from a flow with a webhook trigger: 10 | 11 | ```js 12 | { 13 | '$trigger': { 14 | path: '/trigger/7e4d086e-4414-4385-beaf-5fb417d89806', 15 | query: {}, 16 | body: { email: 'test@gmail.com' }, 17 | method: 'POST', 18 | headers: { 19 | host: 'localhost:8055', 20 | connection: 'keep-alive', 21 | 'content-length': '37', 22 | 'sec-ch-ua': '"Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"', 23 | 'sec-ch-ua-platform': '"macOS"', 24 | 'sec-ch-ua-mobile': '?0', 25 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36', 26 | 'content-type': 'application/json', 27 | accept: '*/*', 28 | origin: 'http://localhost:3000', 29 | 'sec-fetch-site': 'same-site', 30 | 'sec-fetch-mode': 'cors', 31 | 'sec-fetch-dest': 'empty', 32 | referer: 'http://localhost:3000/', 33 | 'accept-encoding': 'gzip, deflate, br', 34 | 'accept-language': 'en-US,en;q=0.9' 35 | } 36 | }, 37 | '$last': ..., 38 | '$accountability': { 39 | user: null, 40 | role: null, 41 | admin: false, 42 | app: false, 43 | ip: '::1', 44 | userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36', 45 | origin: 'http://localhost:3000', 46 | permissions: [] 47 | }, 48 | '$env': {}, 49 | // result of a "Read Data" step, key name matches your "step key" 50 | item_read_5u3da: [ 51 | ... 52 | ], 53 | ``` -------------------------------------------------------------------------------- /extension_docs/query_converter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Query Converter 5 | 6 | 7 | 8 | 9 | 10 | 47 | 61 | 62 | 63 |
64 |

Directus Query Object & Query String Converter

65 |

Convert between formats for a Directus Query

66 |
67 |
68 |
69 | 79 |
80 |
81 | 82 | 83 |
84 |
85 | 86 |
87 |
88 | 89 | 90 | -------------------------------------------------------------------------------- /extensions/directus-extension-app-bundle/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist -------------------------------------------------------------------------------- /extensions/directus-extension-app-bundle/README.md: -------------------------------------------------------------------------------- 1 | # Directus Extension: App Bundle 2 | 3 | This bundle holds all the custom extensions created for this directus application. 4 | 5 | ## Adding Extensions 6 | 7 | To add an extension, run the following command in this folder and follow the prompts: 8 | 9 | ```sh 10 | npm run add 11 | ``` 12 | 13 | Any npm packages needed should be added within this folder's `package.json`. 14 | 15 | ## Building 16 | 17 | To build the extensions you can run: 18 | 19 | ```sh 20 | # npm install and build 21 | npm run install-build 22 | # or just build 23 | npm run build 24 | ``` 25 | 26 | Building is required before running the application. 27 | 28 | To watch and rebuild automatically, use: 29 | 30 | ```sh 31 | npm run dev 32 | ``` 33 | 34 | ## Adding NPM Packages 35 | 36 | Any NPM packages added to this bundle is available to all extensions within the bundle. 37 | 38 | To add a new package, use the command: 39 | 40 | ```sh 41 | npm install --save-dev package-name 42 | ``` 43 | 44 | All packages are `devDependencies` since you need to build your code to a single file to use in Directus. -------------------------------------------------------------------------------- /extensions/directus-extension-app-bundle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-app-bundle", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "directus:extension": { 6 | "host": "^10.1.4", 7 | "type": "bundle", 8 | "path": { 9 | "app": "dist/app.js", 10 | "api": "dist/api.js" 11 | }, 12 | "entries": [ 13 | { 14 | "type": "hook", 15 | "name": "auth", 16 | "source": "src/hooks/auth/index.ts" 17 | } 18 | ] 19 | }, 20 | "description": "Directus extensions used in this app", 21 | "icon": "extension", 22 | "keywords": [ 23 | "directus", 24 | "directus-extension", 25 | "directus-custom-bundle" 26 | ], 27 | "scripts": { 28 | "build": "directus-extension build", 29 | "dev": "directus-extension build -w --no-minify", 30 | "link": "directus-extension link", 31 | "add": "directus-extension add" 32 | }, 33 | "devDependencies": { 34 | "@directus/errors": "^0.0.2", 35 | "@directus/extensions-sdk": "^10.1.9", 36 | "@types/node": "^20.3.2", 37 | "typescript": "^5.1.3" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /extensions/directus-extension-app-bundle/src/hooks/auth/index.ts: -------------------------------------------------------------------------------- 1 | import { defineHook } from "@directus/extensions-sdk"; 2 | import { createError } from "@directus/errors"; 3 | 4 | // NOTE: This file is for code demo purposes and has no actual functionality 5 | 6 | // use `@directus/errors` to create custom errors 7 | const RegistrationsClosedError = createError(`REGISTRATIONS_CLOSED`, `User registrations are currently closed.`, 404); 8 | 9 | // filter is before (blocking), action is after (non-blocking) 10 | export default defineHook(({ filter, action }, context) => { 11 | const { services, env } = context; 12 | 13 | // before login 14 | filter("auth.login", async (payload, meta, context) => { 15 | // return updated `payload` to continue change 16 | }); 17 | 18 | // after login success 19 | action("auth.login", async (meta, context) => { 20 | const { payload, user } = meta; 21 | }); 22 | 23 | // before creating a user 24 | filter("users.create", async (payload, meta, context) => { 25 | // throw an error to cancel update 26 | // if (!allowRegistrations) { 27 | // throw new RegistrationsClosedError() 28 | // } 29 | 30 | // return updated `payload` to continue change 31 | }); 32 | 33 | // after creating a user 34 | action("users.create", async (meta, context) => { 35 | const { payload } = meta; 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /extensions/directus-extension-app-bundle/src/utils/config.ts: -------------------------------------------------------------------------------- 1 | /* User */ 2 | export const DEFAULT_USER_ROLE_ID = process.env.AUTH_DEFAULT_ROLE_ID || "xxxx-xxxx-xxxx-xxxx"; 3 | export const REQUIRE_VERIFIED_EMAILS = false; -------------------------------------------------------------------------------- /extensions/directus-extension-app-bundle/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "allowJs": true, 5 | "esModuleInterop": true, 6 | "target": "esnext", 7 | "module": "esnext", 8 | "moduleResolution": "node" 9 | }, 10 | "include": ["src"] 11 | } 12 | -------------------------------------------------------------------------------- /extensions/modules/generate-types/index.js: -------------------------------------------------------------------------------- 1 | // Installed from: https://github.com/maltejur/directus-extension-generate-types/releases/tag/0.5.1 2 | /** 3 | * This Source Code Form is subject to the terms of the Mozilla Public 4 | License, v. 2.0. If a copy of the MPL was not distributed with this 5 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | */ 7 | import{resolveComponent as e,openBlock as n,createBlock as t,withCtx as a,createVNode as r,createElementBlock as o,Fragment as i,renderList as s,createElementVNode as l,createTextVNode as c,toDisplayString as u,pushScopeId as d,popScopeId as p,computed as g,createCommentVNode as f}from"vue";import{useStores as h}from"@directus/extensions-sdk";import{useI18n as m}from"vue-i18n";var v={ts:{name:"TypeScript",icon:'',logo:''},py:{name:"Python",icon:'',logo:''},oas:{name:"OpenAPI",icon:'',logo:''}},b={data:()=>({languages:v,version:"0.5.1"})};const y=["innerHTML"];var x=[],w=[];function k(e,n){if(e&&"undefined"!=typeof document){var t,a=!0===n.prepend?"prepend":"append",r=!0===n.singleTag,o="string"==typeof n.container?document.querySelector(n.container):document.getElementsByTagName("head")[0];if(r){var i=x.indexOf(o);-1===i&&(i=x.push(o)-1,w[i]={}),t=w[i]&&w[i][a]?w[i][a]:w[i][a]=s()}else t=s();65279===e.charCodeAt(0)&&(e=e.substring(1)),t.styleSheet?t.styleSheet.cssText+=e:t.appendChild(document.createTextNode(e))}function s(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),n.attributes)for(var t=Object.keys(n.attributes),r=0;r[r(x,{to:"/generate-types/index",class:"version"},{default:a((()=>[r(m,null,{default:a((()=>[r(h,{name:"code"})])),_:1}),r(b,null,{default:a((()=>[r(v,{class:"version",text:`generate-types v${c.version}`},null,8,["text"])])),_:1})])),_:1}),r(w),(n(!0),o(i,null,s(Object.keys(c.languages),(e=>(n(),t(x,{key:e,to:`/generate-types/${e}`},{default:a((()=>[r(m,null,{default:a((()=>[l("div",{innerHTML:c.languages[e].icon},null,8,y)])),_:2},1024),r(b,null,{default:a((()=>[r(v,{text:c.languages[e].name},null,8,["text"])])),_:2},1024)])),_:2},1032,["to"])))),128))])),_:1})},b.__scopeId="data-v-09d1a3b8",b.__file="src/components/navigation.vue";var F={components:{NavbarComponent:b},data:()=>({version:"0.5.1"})};const A=e=>(d("data-v-580b67a6"),e=e(),p(),e),_={class:"page"},$=A((()=>l("code",null,"generate-types",-1))),C=A((()=>l("p",null," Select the language you want to generate types for on the left to start. ",-1))),S=A((()=>l("p",null,[l("a",{href:"https://github.com/maltejur/directus-extension-generate-types"},[l("svg",{viewBox:"0 0 128 128"},[l("g",{fill:"currentColor"},[l("path",{"fill-rule":"evenodd","clip-rule":"evenodd",d:"M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"}),l("path",{d:"M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"})])]),l("span",null,"GitHub")])],-1)));k("\n.page[data-v-580b67a6] {\n padding: 0 var(--content-padding) var(--content-padding-bottom);\n}\ncode[data-v-580b67a6] {\n background-color: rgba(0, 0, 0, 0.05);\n font-size: 0.9em;\n padding: 3px 5px;\n border-radius: 4px;\n}\nh4[data-v-580b67a6] {\n font-size: 1.3em;\n font-weight: 700;\n}\nh4[data-v-580b67a6],\np[data-v-580b67a6] {\n margin-bottom: 1em;\n}\nsvg[data-v-580b67a6] {\n width: 1em;\n height: 1em;\n margin-right: 5px;\n transform: translateY(1px);\n}\na[data-v-580b67a6] {\n color: var(--primary-110);\n font-weight: 500;\n text-decoration: none;\n}\na[data-v-580b67a6]:hover {\n text-decoration: underline;\n}\n",{}),F.render=function(o,i,s,d,p,g){const f=e("NavbarComponent"),h=e("v-icon"),m=e("v-button"),v=e("private-view");return n(),t(v,{title:"Generate Types"},{navigation:a((()=>[r(f)])),"title-outer:prepend":a((()=>[r(m,{class:"header-icon",rounded:"",disabled:"",icon:"",secondary:""},{default:a((()=>[r(h,{name:"code"})])),_:1})])),default:a((()=>[l("div",_,[l("h4",null,[c(" Welcome to "),$,c(" version "),l("code",null,u(p.version),1)]),C,S])])),_:1})},F.__scopeId="data-v-580b67a6",F.__file="src/routes/index.vue";var z=function(){return z=Object.assign||function(e){for(var n,t=1,a=arguments.length;t0&&r[r.length-1])||6!==o[0]&&2!==o[0])){i=0;continue}if(3===o[0]&&(!r||o[1]>r[0]&&o[1]=d.reach);F+=k.value.length,k=k.next){var A=k.value;if(n.length>e.length)return;if(!(A instanceof o)){var _,$=1;if(b){if(!(_=i(w,F,e,v))||_.index>=e.length)break;var C=_.index,S=_.index+_[0].length,z=F;for(z+=k.value.length;C>=z;)z+=(k=k.next).value.length;if(F=z-=k.value.length,k.value instanceof o)continue;for(var T=k;T!==n.tail&&(zd.reach&&(d.reach=E);var L=k.prev;if(M&&(L=c(n,L,M),F+=M.length),u(n,L,$),k=c(n,L,new o(p,m?r.tokenize(j,m):j,y,j)),P&&c(n,k,P),$>1){var H={cause:p+","+f,reach:E};s(e,n,t,k.prev,F,H),d&&H.reach>d.reach&&(d.reach=H.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function c(e,n,t){var a=n.next,r={value:t,prev:n,next:a};return n.next=r,a.prev=r,e.length++,r}function u(e,n,t){for(var a=n.next,r=0;r"+o.content+""},!e.document)return e.addEventListener?(r.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),a=t.language,o=t.code,i=t.immediateClose;e.postMessage(r.highlight(o,r.languages[a],a)),i&&e.close()}),!1),r):r;var d=r.util.currentScript();function p(){r.manual||r.highlightAll()}if(d&&(r.filename=d.src,d.hasAttribute("data-manual")&&(r.manual=!0)),!r.manual){var g=document.readyState;"loading"===g||"interactive"===g&&d&&d.defer?document.addEventListener("DOMContentLoaded",p):window.requestAnimationFrame?window.requestAnimationFrame(p):window.setTimeout(p,16)}return r}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{}); 8 | /** 9 | * Prism: Lightweight, robust, elegant syntax highlighting 10 | * 11 | * @license MIT 12 | * @author Lea Verou 13 | * @namespace 14 | * @public 15 | */e.exports&&(e.exports=n),void 0!==M&&(M.Prism=n),n.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},n.languages.markup.tag.inside["attr-value"].inside.entity=n.languages.markup.entity,n.languages.markup.doctype.inside["internal-subset"].inside=n.languages.markup,n.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(n.languages.markup.tag,"addInlined",{value:function(e,t){var a={};a["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:n.languages[t]},a.cdata=/^$/i;var r={"included-cdata":{pattern://i,inside:a}};r["language-"+t]={pattern:/[\s\S]+/,inside:n.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},n.languages.insertBefore("markup","cdata",o)}}),Object.defineProperty(n.languages.markup.tag,"addAttribute",{value:function(e,t){n.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:n.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),n.languages.html=n.languages.markup,n.languages.mathml=n.languages.markup,n.languages.svg=n.languages.markup,n.languages.xml=n.languages.extend("markup",{}),n.languages.ssml=n.languages.xml,n.languages.atom=n.languages.xml,n.languages.rss=n.languages.xml,function(e){var n=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+n.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+n.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+n.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+n.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:n,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var t=e.languages.markup;t&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(n),n.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},n.languages.javascript=n.languages.extend("clike",{"class-name":[n.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),n.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,n.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:n.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:n.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:n.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:n.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:n.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),n.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:n.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),n.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),n.languages.markup&&(n.languages.markup.tag.addInlined("script","javascript"),n.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),n.languages.js=n.languages.javascript,function(){if(void 0!==n&&"undefined"!=typeof document){Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector);var e={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},t="data-src-status",a="loading",r="loaded",o='pre[data-src]:not([data-src-status="loaded"]):not([data-src-status="loading"])';n.hooks.add("before-highlightall",(function(e){e.selector+=", "+o})),n.hooks.add("before-sanity-check",(function(i){var s=i.element;if(s.matches(o)){i.code="",s.setAttribute(t,a);var l=s.appendChild(document.createElement("CODE"));l.textContent="Loading…";var c=s.getAttribute("data-src"),u=i.language;if("none"===u){var d=(/\.(\w+)$/.exec(c)||[,"none"])[1];u=e[d]||d}n.util.setLanguage(l,u),n.util.setLanguage(s,u);var p=n.plugins.autoloader;p&&p.loadLanguages(u),function(e,n,t){var a=new XMLHttpRequest;a.open("GET",e,!0),a.onreadystatechange=function(){4==a.readyState&&(a.status<400&&a.responseText?n(a.responseText):a.status>=400?t("✖ Error "+a.status+" while fetching file: "+a.statusText):t("✖ Error: File does not exist or is empty"))},a.send(null)}(c,(function(e){s.setAttribute(t,r);var a=function(e){var n=/^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(e||"");if(n){var t=Number(n[1]),a=n[2],r=n[3];return a?r?[t,Number(r)]:[t,void 0]:[t,t]}}(s.getAttribute("data-range"));if(a){var o=e.split(/\r\n?|\n/g),i=a[0],c=null==a[1]?o.length:a[1];i<0&&(i+=o.length),i=Math.max(0,Math.min(i-1,o.length)),c<0&&(c+=o.length),c=Math.max(0,Math.min(c,o.length)),e=o.slice(i,c).join("\n"),s.hasAttribute("data-start")||s.setAttribute("data-start",String(i+1))}l.textContent=e,n.highlightElement(l)}),(function(e){s.setAttribute(t,"failed"),l.textContent=e}))}})),n.plugins.fileHighlight={highlight:function(e){for(var t,a=(e||document).querySelectorAll(o),r=0;t=a[r++];)n.highlightElement(t)}};var i=!1;n.fileHighlight=function(){i||(console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),i=!0),n.plugins.fileHighlight.highlight.apply(this,arguments)}}}()}(P);var E=P.exports;var L={props:{value:String,language:String,downloadName:String,loading:Boolean},computed:{rendered:function(){return E.highlight(this.value,E.languages[this.language],this.language)}},methods:{downloadTypes:function(){!function(e,n,t){void 0===t&&(t="text/plain");var a=new Blob([e],{type:t}),r=document.createElement("a");r.download=n,r.innerHTML="Download File",null!=window.webkitURL?r.href=window.webkitURL.createObjectURL(a):(r.href=window.URL.createObjectURL(a),r.style.display="none",document.body.appendChild(r)),r.click()}(this.value,this.downloadName,"application/json")}},setup:function(e){var n=(0,h().useNotificationsStore)(),t=m().t,a=function(){var e=m().t;return{isCopySupported:g((function(){var e;return!!(null===(e=null===navigator||void 0===navigator?void 0:navigator.clipboard)||void 0===e?void 0:e.writeText)})),isPasteSupported:g((function(){var e;return!!(null===(e=null===navigator||void 0===navigator?void 0:navigator.clipboard)||void 0===e?void 0:e.readText)})),copyToClipboard:function(n,t,a){var r,o,i;return T(this,void 0,void 0,(function(){return j(this,(function(s){switch(s.label){case 0:return s.trys.push([0,2,,3]),[4,null===(r=null===navigator||void 0===navigator?void 0:navigator.clipboard)||void 0===r?void 0:r.writeText(n)];case 1:return s.sent(),t.add({title:null!==(o=null==a?void 0:a.success)&&void 0!==o?o:e("copy_raw_value_success")}),[2,!0];case 2:return s.sent(),t.add({type:"error",title:null!==(i=null==a?void 0:a.fail)&&void 0!==i?i:e("copy_raw_value_fail")}),[2,!1];case 3:return[2]}}))}))},pasteFromClipboard:function(n,t){var a,r,o;return T(this,void 0,void 0,(function(){var i;return j(this,(function(s){switch(s.label){case 0:return s.trys.push([0,2,,3]),[4,null===(a=null===navigator||void 0===navigator?void 0:navigator.clipboard)||void 0===a?void 0:a.readText()];case 1:return i=s.sent(),n.add({title:null!==(r=null==t?void 0:t.success)&&void 0!==r?r:e("paste_raw_value_success")}),[2,i];case 2:return s.sent(),n.add({type:"error",title:null!==(o=null==t?void 0:t.fail)&&void 0!==o?o:e("paste_raw_value_fail")}),[2,null];case 3:return[2]}}))}))}}}(),r=a.isCopySupported,o=a.copyToClipboard;return{isCopySupported:r,copyValue:function(){return T(this,void 0,void 0,(function(){return j(this,(function(t){switch(t.label){case 0:return[4,o(e.value,n)];case 1:return t.sent(),[2]}}))}))},t:t}}};const H={class:"code"},O={class:"generate-types-textarea"},D=["innerHTML"],N={class:"buttonRow"};k("\n.code[data-v-c2ff9106] {\n display: flex;\n flex-direction: column;\n width: 600px;\n max-width: 100%;\n margin-top: 10px;\n margin-bottom: 25px;\n margin-right: 25px;\n}\n.generate-types-textarea[data-v-c2ff9106] {\n position: relative;\n width: 100%;\n height: auto;\n max-height: 65vh;\n padding: 15px;\n overflow: auto;\n background-color: var(--background-input);\n border: var(--border-width) solid var(--border-normal);\n border-radius: var(--border-radius);\n transition: border-color var(--fast) var(--transition);\n}\n.generate-types-textarea[data-v-c2ff9106]:hover:not(.disabled) {\n border-color: var(--border-normal-alt);\n}\n.generate-types-textarea[data-v-c2ff9106]:focus:not(.disabled),\n.generate-types-textarea[data-v-c2ff9106]:focus-within:not(.disabled) {\n border-color: var(--primary);\n}\n.buttonRow[data-v-c2ff9106] {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n margin-top: 15px;\n}\n.buttonRow > div[data-v-c2ff9106] {\n margin-left: 15px;\n}\n.inline-progress[data-v-c2ff9106] {\n --v-progress-circular-size: 1em;\n display: inline;\n /* vertical-align: sub; */\n margin: 0 5px;\n}\n",{});function I(e){console.warn("%c[directus-extension-generate-types]%c\n".concat(e),"font-weight: bold;")}function B(e){return T(this,void 0,void 0,(function(){var n,t,a,r,o;return j(this,(function(i){switch(i.label){case 0:return[4,e.get("/collections?limit=-1")];case 1:return n=i.sent(),t=n.data.data,a={},t.sort((function(e,n){return e.collection.localeCompare(n.collection)})).forEach((function(e){return a[e.collection]=z(z({},e),{fields:[]})})),[4,e.get("/fields?limit=-1")];case 2:return r=i.sent(),r.data.data.sort((function(e,n){return e.field.localeCompare(n.field)})).forEach((function(e){a[e.collection]?a[e.collection].fields.push(e):I("".concat(e.collection," not found"))})),Object.keys(a).forEach((function(e){0===a[e].fields.length&&delete a[e]})),[4,e.get("/relations?limit=-1")];case 3:return o=i.sent(),o.data.data.forEach((function(e){var n,t;if(e.meta){var r=null===(n=a[e.meta.one_collection])||void 0===n?void 0:n.fields.find((function(n){return n.field===e.meta.one_field})),o=null===(t=a[e.meta.many_collection])||void 0===t?void 0:t.fields.find((function(n){return n.field===e.meta.many_field}));r&&(r.relation={type:"many",collection:e.meta.many_collection}),o&&(o.relation={type:"one",collection:e.meta.one_collection})}else I("Relation on field '".concat(e.field,"' in collection '").concat(e.collection,"' has no meta. Maybe missing a relation inside directus_relations table."))})),[2,a]}}))}))}function R(e,n,t){return void 0===n&&(n=!1),void 0===t&&(t=!0),T(this,void 0,void 0,(function(){var a,r,o;return j(this,(function(i){switch(i.label){case 0:return[4,B(e)];case 1:return a=i.sent(),r="",o=[],Object.values(a).forEach((function(e){var a,i=e.collection,s=Z(i),l=!0===(null===(a=e.meta)||void 0===a?void 0:a.singleton);o.push(t?"".concat(i,": ").concat(s).concat(l?"":"[]"):"".concat(i,": ").concat(s)),r+="export type ".concat(s," = {\n"),e.fields.forEach((function(e){var t,a,o;(null===(a=null===(t=e.meta)||void 0===t?void 0:t.interface)||void 0===a?void 0:a.startsWith("presentation-"))||(r+=" ",r+=e.field.includes("-")?'"'.concat(e.field,'"'):e.field,(null===(o=e.schema)||void 0===o?void 0:o.is_nullable)&&(r+="?"),r+=": ",r+=function(e,n){var t,a;void 0===n&&(n=!1);a=e.relation&&"many"===e.relation.type?"any[]":["integer","bigInteger","float","decimal"].includes(e.type)?"number":["boolean"].includes(e.type)?"boolean":["json","csv"].includes(e.type)?"unknown":"string";e.relation&&(a+=n?" & ":" | ",a+=e.relation.collection?Z(e.relation.collection):"any","many"===e.relation.type&&(a+="[]"));(null===(t=e.schema)||void 0===t?void 0:t.is_nullable)&&(e.relation&&n?a="(".concat(a,") | null"):a+=" | null");return a}(e,n),r+=";\n")})),r+="};\n\n"})),r+="export type CustomDirectusTypes = {\n"+o.map((function(e){return" ".concat(e,";")})).join("\n")+"\n};",[2,r+="\n"]}}))}))}function Z(e){return e.split(" ").flatMap((function(e){return e.split("_")})).flatMap((function(e){return e.split("-")})).map((function(e){return e.charAt(0).toUpperCase()+e.slice(1)})).join("")}k("\n.generate-types-textarea,\n.generate-types-textarea * {\n user-select: text;\n}\n",{}),L.render=function(i,s,d,p,g,h){const m=e("v-progress-circular"),v=e("v-icon"),b=e("v-button");return n(),o("div",H,[l("i",null,[c(u(d.downloadName)+" ",1),d.loading&&h.rendered?(n(),t(m,{key:0,indeterminate:"",class:"inline-progress"})):f("v-if",!0)]),l("div",O,[h.rendered?(n(),o("pre",{key:0,innerHTML:h.rendered},null,8,D)):(n(),t(m,{key:1,indeterminate:""}))]),l("div",N,[p.isCopySupported?(n(),t(b,{key:0,class:"copyBtn",onClick:p.copyValue},{default:a((()=>[r(v,{name:"content_copy",style:{"margin-right":"8px"},disabled:!i.types},null,8,["disabled"]),c(" "+u(p.t("copy")),1)])),_:1},8,["onClick"])):f("v-if",!0),this.downloadName?(n(),t(b,{key:1,class:"downloadBtn",onClick:h.downloadTypes},{default:a((()=>[r(v,{name:"cloud_download",style:{"margin-right":"8px"},disabled:!i.types},null,8,["disabled"]),c(" "+u(p.t("download")),1)])),_:1},8,["onClick"])):f("v-if",!0)])])},L.__scopeId="data-v-c2ff9106",L.__file="src/components/code.vue";var U={components:{NavbarComponent:b,CodeComponent:L},inject:["api"],data:function(){var e="true"===localStorage.getItem("directus-extension-generate-types-use-intersection-types"),n="false"!==localStorage.getItem("directus-extension-generate-types-sdk11");return{types:"",languages:v,useIntersectionTypes:e,sdk11:n,loading:!1}},methods:{generateTypes:function(){var e=this;console.log(window.localStorage),localStorage.setItem("directus-extension-generate-types-use-intersection-types",this.useIntersectionTypes),localStorage.setItem("directus-extension-generate-types-sdk11",this.sdk11),R(this.api,this.useIntersectionTypes,this.sdk11).then((function(n){e.types=n,e.loading=!1}))},exampleCode:function(){return this.sdk11?'import { createDirectus } from "@directus/sdk";\nimport { rest } from "@directus/sdk/rest";\nimport { CustomDirectusTypes } from "./types";\n\nconst client = createDirectus("").with(rest());':'import { Directus } from "@directus/sdk";\nimport { CustomDirectusTypes } from "./types";\n\nconst directus = new Directus("");'}},mounted:function(){this.generateTypes()}};const V=e=>(d("data-v-3bdb8ddb"),e=e(),p(),e),G=["innerHTML"],q={class:"page"},W={class:"div"},J=V((()=>l("p",null,[c(" To use these types with the "),l("code",null,"@directus/sdk"),c(", include the "),l("code",null,"types.ts"),c(" like this: ")],-1))),Y=V((()=>l("h3",{class:"type-title"},"Options",-1))),X=V((()=>l("span",null,[c(" Use Intersection Types ("),l("code",null,"&"),c(") instead of Union Types ("),l("code",null,"|"),c(") for relational fields. "),l("a",{href:"https://github.com/maltejur/directus-extension-generate-types/pull/3#issuecomment-1037243032"}," Learn more ")],-1))),K=V((()=>l("span",null," Generate Types for Directus SDK >= v11 ",-1)));k("\n.page[data-v-3bdb8ddb] {\n padding: 0 var(--content-padding);\n display: flex;\n}\n@media (max-width: 1500px) {\n.page[data-v-3bdb8ddb] {\n flex-direction: column;\n}\n}\ncode[data-v-3bdb8ddb] {\n background-color: rgba(0, 0, 0, 0.05);\n font-size: 0.9em;\n padding: 3px;\n border-radius: 4px;\n}\n.type-title[data-v-3bdb8ddb] {\n margin: 10px 0;\n}\na[data-v-3bdb8ddb] {\n color: var(--primary-110);\n font-weight: 500;\n text-decoration: none;\n}\na[data-v-3bdb8ddb]:hover {\n text-decoration: underline;\n}\n",{}),U.render=function(o,i,s,c,u,d){const p=e("NavbarComponent"),g=e("CodeComponent"),f=e("v-checkbox"),h=e("private-view");return n(),t(h,{title:"Types for TypeScript"},{navigation:a((()=>[r(p)])),"title-outer:prepend":a((()=>[l("div",{innerHTML:u.languages.ts.logo},null,8,G)])),default:a((()=>[l("div",q,[r(g,{value:u.types,language:"typescript",downloadName:"types.ts",loading:u.loading},null,8,["value","loading"]),l("div",W,[J,r(g,{value:d.exampleCode(),language:"typescript"},null,8,["value"]),Y,r(f,{modelValue:u.useIntersectionTypes,"onUpdate:modelValue":i[0]||(i[0]=e=>u.useIntersectionTypes=e),onClick:d.generateTypes},{default:a((()=>[X])),_:1},8,["modelValue","onClick"]),r(f,{modelValue:u.sdk11,"onUpdate:modelValue":i[1]||(i[1]=e=>u.sdk11=e),onClick:d.generateTypes},{default:a((()=>[K])),_:1},8,["modelValue","onClick"])])])])),_:1})},U.__scopeId="data-v-3bdb8ddb",U.__file="src/routes/ts.vue";var Q={components:{NavbarComponent:b,CodeComponent:L},inject:["api"],data:function(){return{types:"",languages:v}},mounted:function(){var e=this;(function(e){return T(this,void 0,void 0,(function(){var n;return j(this,(function(t){switch(t.label){case 0:return[4,e.get("/server/specs/oas")];case 1:return n=t.sent(),[2,JSON.stringify(n.data,null,2)]}}))}))})(this.api).then((function(n){return e.types=n}))}};const ee=e=>(d("data-v-1c0b6b35"),e=e(),p(),e),ne=["innerHTML"],te={class:"page"},ae=ee((()=>l("p",null,[c(" You can use the OpenAPI Specification to automatically generate a Documentation for your Directus project with something like "),l("a",{href:"https://swagger.io/"},"Swagger"),c(". ")],-1)));k("\n.page[data-v-1c0b6b35] {\n padding: 0 var(--content-padding);\n display: flex;\n}\n@media (max-width: 1500px) {\n.page[data-v-1c0b6b35] {\n flex-direction: column;\n}\n}\np[data-v-1c0b6b35] {\n max-width: 600px;\n}\na[data-v-1c0b6b35] {\n color: var(--primary-110);\n font-weight: 500;\n text-decoration: none;\n}\na[data-v-1c0b6b35]:hover {\n text-decoration: underline;\n}\n",{}),Q.render=function(o,i,s,c,u,d){const p=e("NavbarComponent"),g=e("CodeComponent"),f=e("private-view");return n(),t(f,{title:"OpenAPI Specification"},{navigation:a((()=>[r(p)])),"title-outer:prepend":a((()=>[l("div",{innerHTML:u.languages.oas.logo},null,8,ne)])),default:a((()=>[l("div",te,[r(g,{value:u.types,language:"json",downloadName:"oas.json"},null,8,["value"]),ae])])),_:1})},Q.__scopeId="data-v-1c0b6b35",Q.__file="src/routes/oas.vue";var re={components:{NavbarComponent:b,CodeComponent:L},inject:["api"],data:function(){return{types:"",languages:v}},mounted:function(){var e=this;(function(e){return T(this,void 0,void 0,(function(){var n,t,a;return j(this,(function(r){switch(r.label){case 0:return[4,B(e)];case 1:return n=r.sent(),t="",a=[],t+="from typing import TypedDict\n\n",t+=Object.values(n).map((function(e){var n=e.collection,t=n.split("_").map((function(e){return e.charAt(0).toUpperCase()+e.slice(1)})).join("");return a.push("".concat(n,": ").concat(t)),"class ".concat(t,"(TypedDict):\n").concat(Object.values(e.fields).map((function(e){return" ".concat(e.field,": ").concat((n=e.type,["integer","bigInteger"].includes(n)?"int":["float","decimal"].includes(n)?"float":["boolean"].includes(n)?"bool":"str"));var n})).join("\n"))})).join("\n\n"),t+="\n\n",t+="class CustomDirectusTypes(TypedDict):\n".concat(a.map((function(e){return" ".concat(e)})).join("\n"),"\n"),[2,t+="\n"]}}))}))})(this.api).then((function(n){return e.types=n}))}};const oe=["innerHTML"],ie={class:"page"};k("\n.page[data-v-355cb865] {\n padding: 0 var(--content-padding);\n display: flex;\n}\n@media (max-width: 1500px) {\n.page[data-v-355cb865] {\n flex-direction: column;\n}\n}\ncode[data-v-355cb865] {\n background-color: rgba(0, 0, 0, 0.05);\n font-size: 0.9em;\n padding: 3px;\n border-radius: 4px;\n}\n",{}),re.render=function(o,i,s,c,u,d){const p=e("NavbarComponent"),g=e("CodeComponent"),f=e("private-view");return n(),t(f,{title:"Type Hints for Python"},{navigation:a((()=>[r(p)])),"title-outer:prepend":a((()=>[l("div",{innerHTML:u.languages.py.logo},null,8,oe)])),default:a((()=>[l("div",ie,[r(g,{value:u.types,language:"python",downloadName:"types.py"},null,8,["value"])])])),_:1})},re.__scopeId="data-v-355cb865",re.__file="src/routes/py.vue";k('/**\n * prism.js default theme for JavaScript, CSS and HTML\n * Based on dabblet (http://dabblet.com)\n * @author Lea Verou\n */\n\ncode[class*="language-"],\npre[class*="language-"] {\n\tcolor: black;\n\tbackground: none;\n\ttext-shadow: 0 1px white;\n\tfont-family: Consolas, Monaco, \'Andale Mono\', \'Ubuntu Mono\', monospace;\n\tfont-size: 1em;\n\ttext-align: left;\n\twhite-space: pre;\n\tword-spacing: normal;\n\tword-break: normal;\n\tword-wrap: normal;\n\tline-height: 1.5;\n\n\t-moz-tab-size: 4;\n\t-o-tab-size: 4;\n\ttab-size: 4;\n\n\t-webkit-hyphens: none;\n\t-moz-hyphens: none;\n\t-ms-hyphens: none;\n\thyphens: none;\n}\n\npre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,\ncode[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {\n\ttext-shadow: none;\n\tbackground: #b3d4fc;\n}\n\npre[class*="language-"]::selection, pre[class*="language-"] ::selection,\ncode[class*="language-"]::selection, code[class*="language-"] ::selection {\n\ttext-shadow: none;\n\tbackground: #b3d4fc;\n}\n\n@media print {\n\tcode[class*="language-"],\n\tpre[class*="language-"] {\n\t\ttext-shadow: none;\n\t}\n}\n\n/* Code blocks */\npre[class*="language-"] {\n\tpadding: 1em;\n\tmargin: .5em 0;\n\toverflow: auto;\n}\n\n:not(pre) > code[class*="language-"],\npre[class*="language-"] {\n\tbackground: #f5f2f0;\n}\n\n/* Inline code */\n:not(pre) > code[class*="language-"] {\n\tpadding: .1em;\n\tborder-radius: .3em;\n\twhite-space: normal;\n}\n\n.token.comment,\n.token.prolog,\n.token.doctype,\n.token.cdata {\n\tcolor: slategray;\n}\n\n.token.punctuation {\n\tcolor: #999;\n}\n\n.token.namespace {\n\topacity: .7;\n}\n\n.token.property,\n.token.tag,\n.token.boolean,\n.token.number,\n.token.constant,\n.token.symbol,\n.token.deleted {\n\tcolor: #905;\n}\n\n.token.selector,\n.token.attr-name,\n.token.string,\n.token.char,\n.token.builtin,\n.token.inserted {\n\tcolor: #690;\n}\n\n.token.operator,\n.token.entity,\n.token.url,\n.language-css .token.string,\n.style .token.string {\n\tcolor: #9a6e3a;\n\t/* This background color was intended by the author of this theme. */\n\tbackground: hsla(0, 0%, 100%, .5);\n}\n\n.token.atrule,\n.token.attr-value,\n.token.keyword {\n\tcolor: #07a;\n}\n\n.token.function,\n.token.class-name {\n\tcolor: #DD4A68;\n}\n\n.token.regex,\n.token.important,\n.token.variable {\n\tcolor: #e90;\n}\n\n.token.important,\n.token.bold {\n\tfont-weight: bold;\n}\n.token.italic {\n\tfont-style: italic;\n}\n\n.token.entity {\n\tcursor: help;\n}\n',{}),Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:Prism.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),Prism.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),Prism.languages.js=Prism.languages.javascript,Prism.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},Prism.languages.webmanifest=Prism.languages.json,function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var n=e.languages.extend("typescript",{});delete n["class-name"],e.languages.typescript["class-name"].inside=n,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:n}}}}),e.languages.ts=e.languages.typescript}(Prism),Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python;var se={id:"generate-types",name:"Generate Types",icon:"code",routes:[{path:"",redirect:"/generate-types/index"},{path:"/generate-types/index",component:F},{path:"/generate-types/ts",component:U},{path:"/generate-types/oas",component:Q},{path:"/generate-types/py",component:re}],hidden:!1,preRegisterCheck:function(e){return e.role.admin_access}};export{se as default}; 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-local", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "directus start", 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "extensions": "cd extensions/directus-extension-app-bundle/ && npm i && npm run dev", 10 | "build": "npm i && cd extensions/directus-extension-app-bundle/ && npm i && npm run build", 11 | "snapshot": "directus schema snapshot ./snapshot.yaml", 12 | "snapshot:apply": "directus schema apply ./snapshot.yaml", 13 | "snapshot:apply:dry-run": "directus schema apply --dry-run ./snapshot.yaml", 14 | "upgrade": "echo \"See notes in UPGRADE_NOTES.md and follow these docs https://docs.directus.io/self-hosted/upgrades-migrations.html\"", 15 | "backup-db": "./tasks/pg_backup_db.sh" 16 | }, 17 | "keywords": [], 18 | "author": "", 19 | "license": "ISC", 20 | "dependencies": { 21 | "@directus/extensions-sdk": "^10.1.5", 22 | "directus": "^10.6.0", 23 | "pg": "^8.11.0" 24 | }, 25 | "engines": { 26 | "node": ">=18.0.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tasks/pg_backup_db.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # extract vars from local `.env` 4 | export $(grep -v '^#' .env | xargs) 5 | 6 | filename="pg_backup_$(date "+%F").sql" 7 | postgres_db="$DB_HOST:$DB_PORT/$DB_DATABASE" 8 | postgres_url="postgresql://$DB_USER:$DB_PASSWORD@$postgres_db" 9 | 10 | if [[ $DB_SSL == "true" ]]; then 11 | postgres_url="$postgres_url?ssl=true" 12 | fi 13 | 14 | echo "Backing up postgresql://$postgres_db > $filename" 15 | 16 | pg_dump -d $postgres_url -f $filename 17 | 18 | echo -e "--- Backup of database \"$DB_DATABASE\"\n\nSET session_replication_role = replica;\n\n$(cat $filename)" > $filename 19 | 20 | echo "Complete!" -------------------------------------------------------------------------------- /tasks/pg_install_postgis.sql: -------------------------------------------------------------------------------- 1 | -- Enable PostGIS for PostgreSQL (as of 3.0 contains just geometry/geography) 2 | CREATE EXTENSION postgis; 3 | -- enable raster support (for 3+) 4 | CREATE EXTENSION postgis_raster; 5 | -- Enable Topology 6 | CREATE EXTENSION postgis_topology; 7 | -- Enable PostGIS Advanced 3D 8 | -- and other geoprocessing algorithms 9 | -- sfcgal not available with all distributions 10 | CREATE EXTENSION postgis_sfcgal; 11 | -- fuzzy matching needed for Tiger 12 | CREATE EXTENSION fuzzystrmatch; 13 | -- rule based standardizer 14 | CREATE EXTENSION address_standardizer; 15 | -- example rule data set 16 | CREATE EXTENSION address_standardizer_data_us; 17 | -- Enable US Tiger Geocoder 18 | CREATE EXTENSION postgis_tiger_geocoder; 19 | --------------------------------------------------------------------------------