diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..31ab527d --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,66 @@ +# Sample workflow for building and deploying a VitePress site to GitHub Pages +# +name: Deploy VitePress site to Pages + +on: + # Runs on pushes targeting the `main` branch. Change this to `master` if you're + # using the `master` branch as the default branch. + push: + branches: [main] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: pages + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Not needed if lastUpdated is not enabled + # - uses: pnpm/action-setup@v2 # Uncomment this if you're using pnpm + # - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm # or pnpm / yarn + - name: Setup Pages + uses: actions/configure-pages@v4 + - name: Install dependencies + run: npm ci # or pnpm install / yarn install / bun install + - name: Build with VitePress + run: | + npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build + touch docs/.vitepress/dist/.nojekyll + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs/.vitepress/dist + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + needs: build + runs-on: ubuntu-latest + name: Deploy + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index a3e3973f..8f1fbd42 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ logs dist **/node_modules *.zip -ving/drizzle/migrations \ No newline at end of file +ving/drizzle/migrations +docs/.vitepress/cache +docs/.vitepress/dist diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js new file mode 100644 index 00000000..c4531306 --- /dev/null +++ b/docs/.vitepress/config.js @@ -0,0 +1,66 @@ +import { defineConfig } from 'vitepress' + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: "Ving", + base: '/repo/', + description: "An opinionated Nuxt starter with restful API included", + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + nav: [ + { text: 'Home', link: '/' }, + { text: 'Documentation', link: '/installation' } + ], + + sidebar: [ + { + text: 'Examples', + items: [ + { text: 'Markdown Examples', link: '/markdown-examples' }, + { text: 'Runtime API Examples', link: '/api-examples' } + ] + }, + { + text: 'Basics', + items: [ + { text: 'Installation', link: '/installation' }, + { text: 'Environment Variables', link: '/env' }, + { text: 'Error Codes', link: '/error-codes' }, + { text: 'Change Log', link: '/change-log' }, + ] + }, + { + text: 'Subsystems', + items: [ + { text: 'Cache', link: '/subsystems/cache' }, + { text: 'CLI', link: '/subsystems/cli' }, + { text: 'Drizzle', link: '/subsystems/drizzle' }, + { text: 'Email', link: '/subsystems/email' }, + { text: 'Jobs', link: '/subsystems/jobs' }, + { text: 'Logging', link: '/subsystems/logging' }, + { text: 'Message Bus', link: '/subsystems/messagebus' }, + { text: 'Pulumi', link: '/subsystems/pulumi' }, + { text: 'Rest', link: '/subsystems/rest' }, + { text: 'UI', link: '/subsystems/ui' }, + { text: 'Utilities', link: '/subsystems/utils' }, + { text: 'Ving Record', link: '/subsystems/ving-record' }, + { text: 'Ving Schema', link: '/subsystems/ving-schema' }, + ] + }, + { + text: 'Rest APIs', + items: [ + { text: 'APIKey', link: '/rest/APIKey' }, + { text: 'S3File', link: '/rest/S3File' }, + { text: 'Session', link: '/rest/Session' }, + { text: 'Test', link: '/rest/Test' }, + { text: 'User', link: '/rest/User' }, + ] + }, + ], + + socialLinks: [ + { icon: 'github', link: 'https://github.com/plainblack/ving' } + ] + } +}) diff --git a/docs/APIKey.html b/docs/APIKey.html deleted file mode 100644 index ffb12238..00000000 --- a/docs/APIKey.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - APIKey.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

APIKey - -

-

Developers use an API Key to create a Session via the Rest API and perform other functions that require validation.

-

Filters - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropQueryableQualifierRange
createdAtNoNoYes
updatedAtNoNoYes
nameYesNoNo
-

Relationships - -

- - - - - - - - - - - - - - - - - -
NameRecordTypeEndpoint
userUserParent/api/apikey/:id/user
-

Endpoints - -

-

List - -

-
GET /api/apikey
-
-

Create - -

-
POST /api/apikey
-
-

Read - -

-
GET /api/apikey/:id
-
-

Update - -

-
PUT /api/apikey/:id
-
-

Delete - -

-
DELETE /api/apikey/:id
-
-

Options - -

-
GET /api/apikey/options
-
-
-
- - - - \ No newline at end of file diff --git a/docs/S3File.html b/docs/S3File.html deleted file mode 100644 index 03077104..00000000 --- a/docs/S3File.html +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - S3File.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

S3File - -

-

S3File is the file upload system of Ving.

-

The process of uploading a file happens in 3 steps:

- -

Here’s a bit more detail:

-
Browser / Your Code --> POST filename and content type to /api/s3file 
-                            * creates an S3File and sets its status to pending
-                            * generates a Presigned URL for S3
-                    <-- Return S3File description, including meta.presignedUrl
-
-                    --> PUT s3file.meta.presignedUrl
-                            * stores file in S3
-                    <-- Return nothing
-
-                    --> PUT s3file.props.id to an import API such as /api/user/:id/import-avatar
-                            * post processes the file uploaded to S3
-                            * verifies that the file conforms to the import rules
-                    <-- Return updated record such as User
-
-

Filters - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropQueryableQualifierRange
createdAtNoNoYes
updatedAtNoNoYes
filenameYesNoNo
sizeInBytesNoYesYes
extensionNoYesNo
userIdNoYesNo
-

Relationships - -

- - - - - - - - - - - - - - - - - - - - - - - -
NameRecordTypeEndpoint
userUserParent/api/s3file/:id/user
avatarUsersUserChild/api/s3file/:id/avatarusers
-

Endpoints - -

-

List - -

-
GET /api/s3file
-
-

Create - -

-
POST /api/s3file
-
-

You won’t actually post the file here. You post the filename, contentType, and sizeInBytes here and it will return a presignedUrl in the meta section.

-

Read - -

-
GET /api/s3file/:id
-
-

Update - -

-
PUT /api/s3file/:id
-
-

Delete - -

-
DELETE /api/s3file/:id
-
-

Options - -

-
GET /api/s3file/options
-
-
-
- - - - \ No newline at end of file diff --git a/docs/Session.html b/docs/Session.html deleted file mode 100644 index 6e43526a..00000000 --- a/docs/Session.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - Session.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Session - -

-

In order to access privileged data you’ll on any ving endpoint you’ll need to pass a session id via an HTTP header cookie.

-

Relationships - -

- - - - - - - - - - - - - - - - - -
NameRecordTypeEndpoint
userUserParent/api/apikey/:id/user
-

Endpoints - -

-

Login / Create - -

-
POST /api/session
-
-{
-    "apiKey" : "1b8e4f16-08ca-4829-befe-865cec37679b",
-    "privateKey" : "pk_fd17bc887c7a00a1fffcb06a97961806616e"
-}
-
-

Read - -

-
GET /api/session/:id
-Cookie: vingSessionId=xxx
-
-

Logout / Delete - -

-
DELETE /api/session/:id
-Cookie: vingSessionId=xxx
-
-

Or

-
DELETE /api/session
-Cookie: vingSessionId=xxx
-
-
-
- - - - \ No newline at end of file diff --git a/docs/Test.html b/docs/Test.html deleted file mode 100644 index 2591e7e8..00000000 --- a/docs/Test.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - Test.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Test - -

-

Use this endpoint to test that you can post query params and body params to a ving service.

-

Endpoints - -

-
GET /api/test
-
-
POST /api/test
-
-
PUT /api/test
-
-
DELETE /api/test
-
-

Query Params - -

-

Any query params you post will be returned to you in the JSON response.

-

Body Params - -

-

On POST and PUT endpoints any body params will be returned to you in the JSON response.

-

Response Example - -

-
{
-  "success": true,
-  "serverTime": "2023-05-09T00:19:35.151Z",
-  "httpMethod": "GET",
-  "query": {
-    "foo": "bar"
-  }
-}
-
-
-
- - - - \ No newline at end of file diff --git a/docs/User.html b/docs/User.html deleted file mode 100644 index 178512a3..00000000 --- a/docs/User.html +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - User.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

User - -

-

Users can own records in ving. Users have privileges to access various types of data and store login credentials.

-

Filters - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropQueryableQualifierRange
createdAtNoYesYes
updatedAtNoNoYes
usernameYesNoNo
emailYesNoNo
realNameYesNoNo
adminNoYesNo
developerNoYesNo
-

Relationships - -

- - - - - - - - - - - - - - - - - - - - - - - -
NameRecordTypeEndpoint
apikeysAPIKeyChild/api/user/:id/apikeys
avatarS3FileChild/api/user/:id/avatar
-

Endpoints - -

-

List - -

-
GET /api/user
-
-

Create - -

-
POST /api/user
-
-{
-    "username" : "adufresne",
-    "realName" : "Andy Dufresne",
-    "password" : "rock hammer",
-    "email" : "andy@shawshank.prison"
-}
-
-

Read - -

-
GET /api/user/:id
-
-

Update - -

-
PUT /api/user/:id
-
-{
-    "useAsDisplayName" : "realName"
-}
-
-

Delete - -

-
DELETE /api/user/:id
-
-

Options - -

-
GET /api/user/options
-
-

Who Am I? - -

-

Returns a user record for the currently logged in user based upon the session passed.

-
GET /api/user/whoami
-Cookie: vingSessionId=xxx
-
-

Import Avatar - -

-

Attach an uploaded S3File to this user as an avatar.

-
PUT /api/user/:id/import-avatar
-Cookie: vingSessionId=xxx
-
-{
-    "s3FileId" : "xxx",
-}
-
-
-
- - - - \ No newline at end of file diff --git a/docs/api-examples.md b/docs/api-examples.md new file mode 100644 index 00000000..6bd8bb5c --- /dev/null +++ b/docs/api-examples.md @@ -0,0 +1,49 @@ +--- +outline: deep +--- + +# Runtime API Examples + +This page demonstrates usage of some of the runtime APIs provided by VitePress. + +The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files: + +```md + + +## Results + +### Theme Data +
{{ theme }}
+ +### Page Data +
{{ page }}
+ +### Page Frontmatter +
{{ frontmatter }}
+``` + + + +## Results + +### Theme Data +
{{ theme }}
+ +### Page Data +
{{ page }}
+ +### Page Frontmatter +
{{ frontmatter }}
+ +## More + +Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata). diff --git a/docs/cache.html b/docs/cache.html deleted file mode 100644 index f5b625ee..00000000 --- a/docs/cache.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - cache.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Cache - -

-

By default ving uses an in-memory cache that goes away every time you restart your server. That’s fine for early development, but you get logged out everytime you restart your server, so you’re going to want to set up a Redis cache as soon as you can.

-

Setting Up Redis - -

-

To use a Redis cache, you must first have a Redis server. Then you simply need to add an entry in .env that points to your Redis server like so:

-
VING_REDIS="redis://@localhost:6379"
-
-

You can include a username and password in the URL like so:

-
VING_REDIS="redis://user:pass@localhost:6379"
-
-

Using the Cache - -

-

You can access the cache via to CLI, but for the most of your work you’ll want to programatically access the cache. Here’s a quick code example to show you how it works:

-
import {useCache} from '#ving/cache.mjs';
-const cache = useCache();
-await cache.set('foo', 'bar', 60 * 60 * 1000); // set `foo` in key `foo` for 1 hour
-const foo = await cache.get('foo'); // `bar` 
-await cache.delete('foo'); // delete the value associated with `foo`
-
-
-
- - - - \ No newline at end of file diff --git a/docs/change-log.html b/docs/change-log.html deleted file mode 100644 index ccb4c56f..00000000 --- a/docs/change-log.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - change-log.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Change Log - -

-

TODO: Once we start doing relases I’ll add that here.

-
-
- - - - \ No newline at end of file diff --git a/ving/docs/content/change-log.md b/docs/change-log.md similarity index 75% rename from ving/docs/content/change-log.md rename to docs/change-log.md index 579b6c96..1ef8f372 100644 --- a/ving/docs/content/change-log.md +++ b/docs/change-log.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Change Log TODO: Once we start doing relases I'll add that here. \ No newline at end of file diff --git a/docs/cli.html b/docs/cli.html deleted file mode 100644 index 56d73fca..00000000 --- a/docs/cli.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - cli.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

CLI - -

-

The CLI or Command Line Interface allows you to perform administrative and development functions quickly and easily.

-

You access it from your project root like this:

-
./ving.mjs --help
-
-

You can explore what commands are available by using the above command. It has a built-in help system to tell you how to use the commands.

-

To get help on a specific command, like user management, you can type:

-
./ving.mjs user --help
-
-
-
- - - - \ No newline at end of file diff --git a/docs/drizzle.html b/docs/drizzle.html deleted file mode 100644 index d0e51875..00000000 --- a/docs/drizzle.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - drizzle.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Drizzle - -

-

The database layer is controlled by Drizzle. Drizzle table definitions should be generated from your ving schema. Drizzle provides a convenient way to write SQL queries in Javascript. Drizzle’s table definitions keep track of changes to your database schema over time allowing it to automatically generate database change migrations.

-

Migrations - -

-

Migrations are files created to help you migrate changes from one version of your database to another. In some systems you have to manually write migrations. But in ving you don’t, thanks to our use of Drizzle.

-

Generate Database Migrations - -

-

Drizzle can automatically generate database migrations based upon changes in the Drizzle table definitions. You run that command like this:

-
./ving.mjs drizzle --prepare
-
-

Apply Database Migrations - -

-

Drizzle can automatically apply migrations to your database by running this command:

-
./ving.mjs drizzle --up
-
-

Writing Queries - -

-

Normally you shouldn’t have to write many queries as ving records should handle a lot of that for you. But if you write complex backends like we do then inevitably you’ll need to write some.

-

Writing Drizzle queries looks a lot like how you would write them with SQL, only in Javascript. You probably want to check out the official Drizzle documentation.

-

We’ve exported a list of the useful drizzle utilities into a single file called #ving/drizzle/orm.mjs. Below is an example of how you might use this:

-
import {eq} from '#ving/drizzle/orm.mjs';
-import {UsersTable} from '#ving/drizzle/schema/User.mjs';
-import {useDB} from '#ving/drizzle/db.mjs';
-
-const db = useDB()
-const result = await db.select().from(UsersTable).where(eq(UsersTable.email, 'joe@example.com'));
-
-

Or if you are using ving records then its even easier:

-
import {useKind} from '#ving/record/VingRecord.mjs';
-import {eq} from '#ving/drizzle/orm.mjs';
-
-const users = await useKind('User');
-const result = await users.select.where(eq(Users.table.email, 'joe@example.com'));
-
-

Queries Against Very Large Datasets - -

-

If you are running queries against extremely large datasets and don’t want to load all that data into memory at once, we’ve partnered with the Drizzle Team to implement an asynchronous iterator that you can use. It works like this:

-
const iterator = await db.select().from(UsersTable).iterator();
-
-for await (const row of iterator) {
-  console.log(row);
-}
-
-

This returns row results, not VingRecord instances. However, the findaAll() method in VingRecord does it with records:

-
const allUsers = await Users.findAll();
-for await (const user of allUsers) {
-  console.log(user.get('id'));
-}
-
-

Debugging - -

-

You can enable logging by adding ?log=yes to the end of your VING_MYSQL url like so:

-
VING_MYSQL="mysql://ving:vingPass@localhost:3306/ving?log=yes"
-
-

Queries will be logged at level debug in the drizzle topic.

-
-
- - - - \ No newline at end of file diff --git a/docs/email.html b/docs/email.html deleted file mode 100644 index de32a2ef..00000000 --- a/docs/email.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - email.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Email - -

-

Ving’s email system works over SMTP and is defined using templates created via Nunjucks.

-

Setup - -

-

Add the following to your .env file to be able to send mail.

-
VING_SMTP="smtp://USER:PASS@SERVER:465/?tls=no&log=no"
-
-

Replace USER and PASS and SERVER with the SMTP username, password, and server name of your SMTP server. You can also change the port from 465 to whatever you like. If it uses TLS then set tls to yes, and if you want logging enabled you can set log to yes.

-

Overriding Outbound Emails - -

-

Add an environment variable to override all outbound emails to an email address of your chosing.

-
VING_EMAIL_OVERRIDE="example@gmail.com"
-
-

Normally you’d use this in your dev environment so that all your test users email you instead of whatever made up email addresses you might be using. You can add this to your .env file.

-

Testing - -

-

You can test an email template using the CLI by typing:

-
./ving.mjs email --to=you@gmail.com
-
-

Add --preview to the end if you’d like to display the template in a browser rather than getting the email sent to you.

-

Creating an Email Template - -

-

Define a template in server/email/templates. Each set of templates will go into its own subfolder in that directory, and needs 3 files: html.njk, subject.njk, and text.njk. These can be generated via the CLI:

-
./ving.mjs email --create NotifyAboutSweepstakes
-
-

That will generate a folder with the files you can edit: server/email/templates/notify-about-sweepstakes

-

Customizing the Headers and Footers - -

-

In server/email/templates/_wrappers you will find the wrappers for HTML and Text variants of the emails. You can modify those to adjust the default headers and footers applied to all emails.

-

Sending an Email - -

-
import { sendMail } from '/ving/email/send.mjs';
-await sendMail('notify-about-sweepstakes', { // template name matches the folder name
-    options: { to: user.get('email') }, 
-    vars: {
-        foo: 'bar', // put whatever you like here
-        color: 'red'
-    }
-})
-
-
-
- - - - \ No newline at end of file diff --git a/docs/env.html b/docs/env.html deleted file mode 100644 index 3c366daf..00000000 --- a/docs/env.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - env.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Environment Variables - -

-

Everything that can be changed between various deployments of Ving from QA to Production to individual developer laptops is controlled in the .env file in the root of the ving project folder. Thus .env is excluded from git, as it should be different for each deployment. We then make use of these variables through Node’s --env-file CLI parameter.

-

There are two types of variables that can end up in .env, editable and generated variables.

-

Editable Variables - -

-

Editable Variables are variables that you, the developer or devops person, are required to provide.

-

VING_MYSQL - -

-
VING_MYSQL="mysql://ving:fdsfdsfdsdsf@localhost:3380/ving"
-
-

You can also add log=yes to the end if you would like to see all SQL queries end up in your ving.log for debugging purposes.

-
VING_MYSQL="mysql://ving:ksdksdfllsdf@localhost:3380/ving?log=yes"
-
-

VING_SMTP - -

-

The configuration URL for your SMTP server.

-
VING_SMTP="smtp://AKIAdsfadasfTZZD:BadsfsdfsdsLL@email-smtp.us-east-1.amazonaws.com:465/?tls=yes&log=yes"
-
-

The tls and log sections on the end of the URL are optional. Remove the tls section if your SMTP server doesn’t support TLS encrypted communication. And remove the log section if you don’t want to put every email outcome into your ving.log.

-

VING_EMAIL_OVERRIDE - -

-

If this exists, all outgoing emails will go to this email address instead of their intended address. This is of course great for development purposes, and should not be used in production.

-
VING_EMAIL_OVERRIDE="mytestemail@gmail.com"
-
-

VING_REDIS - -

-

A connection string to your Redis install.

-
VING_REDIS="redis://localhost:6379"
-
-

Can also include username and password like this:

-
VING_REDIS="redis://user:pass@localhost:6379"
-
-

AWS_ACCESS_KEY_ID - -

-

The access key that will be used to deploy resources and access S3.

-
AWS_ACCESS_KEY_ID="JKHHGJKLHHGKL"
-
-

AWS_SECRET_ACCESS_KEY - -

-

The secret access key for AWS that will be used to deploy resources and access S3.

-
AWS_SECRET_ACCESS_KEY="afsdlkjlkafsjdlkjasfdkjlalskfasdf"
-
-

AWS_REGION - -

-

The AWS region you want to deploy services in.

-
AWS_REGION="us-east-1"
-
-

VING_SITE_URL - -

-

The URL of this site as it should appear in generated URLs. Should not end in a /.

-
VING_SITE_URL="http://localhost:3000"
-
-

Generated Variables - -

-

Generated variables are generated by one of Ving’s subsystems, usually Pulumi, for resources that are automatically configured and then must be referenced later.

-

VING_LAMBDA_PROCESS_UPLOADS_URL - -

-

This is the location of the AWS Lambda function that post processes S3File uploads.

-
VING_LAMBDA_PROCESS_UPLOADS_URL="https://yvgmjfp5c7aasfdgf3efqhy0vbkll.lambda-url.us-east-1.on.aws/"
-
-

VING_AWS_UPLOADS_BUCKET - -

-

This is the name of the S3 bucket that will hold S3File uploads.

-
VING_AWS_UPLOADS_BUCKET="ving-dev-uploads-ea6sd53e"
-
-

VING_AWS_UPLOADS_KEY - -

-

The the IAM key that will be used to grant users access to upload a file to the VING_AWS_UPLOADS_BUCKET.

-
VING_AWS_UPLOADS_KEY="dssasdflkjadfslasfdRE7IQ"
-
-

VING_AWS_UPLOADS_SECRET - -

-

The the IAM secret that will be used to grant users access to upload a file to the VING_AWS_UPLOADS_BUCKET.

-
VING_AWS_UPLOADS_SECRET="sssljadsflkjalsdfslfNLzO"
-
-

VING_AWS_THUMBNAILS_BUCKET - -

-

This is the name of the S3 bucket that will hold S3File uploads generated thumbnails.

-
VING_AWS_THUMBNAILS_BUCKET="ving-dev-thumbnails-6dsd53cc"
-
-

ving.json - -

-

As a side note there is also a ving.json file. That is used to store configurable data that does not change between modes of deployment. Usually you’ll set this data when you set up your project, and then likely will never change it again.

-

site - -

-

This section deals with data relating to the site.

-

site.email - -

-

The email address that messages generated by the site should come from by default.

-
"email": "info@example.com",
-
-

site.name - -

-

The name of this site.

-
"name": "ving",
-
-

site.logoUrl - -

-

The relative path of a logo in your repo to display in emails and on the site.

-
"logoUrl": "/ving.svg",
-
-

site.streetAddress - -

-

An array containing the physical street address of the entity that owns the site. This is required for compliance with anti-spam laws.

-
"streetAddress": [
-    "123 Main Street",
-    "Madison, WI 53701",
-    "USA"
-]
-
-
-
- - - - \ No newline at end of file diff --git a/ving/docs/content/env.md b/docs/env.md similarity index 94% rename from ving/docs/content/env.md rename to docs/env.md index 9a2b0b50..b76ee9d5 100644 --- a/ving/docs/content/env.md +++ b/docs/env.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Environment Variables Everything that can be changed between various deployments of Ving from QA to Production to individual developer laptops is controlled in the `.env` file in the root of the ving project folder. Thus `.env` is excluded from git, as it should be different for each deployment. We then make use of these variables through Node's `--env-file` CLI parameter. @@ -67,13 +70,13 @@ VING_SITE_URL="http://localhost:3000" Generated variables are generated by one of Ving's subsystems, usually Pulumi, for resources that are automatically configured and then must be referenced later. ### VING_LAMBDA_PROCESS_UPLOADS_URL -This is the location of the AWS Lambda function that post processes [S3File](S3File.html) uploads. +This is the location of the AWS Lambda function that post processes [S3File](rest/S3File) uploads. ```bash VING_LAMBDA_PROCESS_UPLOADS_URL="https://yvgmjfp5c7aasfdgf3efqhy0vbkll.lambda-url.us-east-1.on.aws/" ``` ### VING_AWS_UPLOADS_BUCKET -This is the name of the S3 bucket that will hold [S3File](S3File.html) uploads. +This is the name of the S3 bucket that will hold [S3File](rest/S3File) uploads. ```bash VING_AWS_UPLOADS_BUCKET="ving-dev-uploads-ea6sd53e" ``` @@ -91,7 +94,7 @@ VING_AWS_UPLOADS_SECRET="sssljadsflkjalsdfslfNLzO" ``` ### VING_AWS_THUMBNAILS_BUCKET -This is the name of the S3 bucket that will hold [S3File](S3File.html) uploads generated thumbnails. +This is the name of the S3 bucket that will hold [S3File](rest/S3File) uploads generated thumbnails. ```bash VING_AWS_THUMBNAILS_BUCKET="ving-dev-thumbnails-6dsd53cc" ``` diff --git a/docs/error-codes.html b/docs/error-codes.html deleted file mode 100644 index 93648a7f..00000000 --- a/docs/error-codes.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - error-codes.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Error Codes - -

-

This document describes the error codes thrown by Ving’s REST API. They map directly onto the W3C’s standard HTTP status codes. When functioning properly the web service will always return a 200 HTTP status code.

-

NOTE: While the error codes documented here are returned as HTTP status codes, they are also returned in the JSON response of the body.

-

400 Bad Request - -

-

The server cannot process the request because the request was malformed -or a prerequisite of performing the requested action has not been met.

-

401 Unauthorized - -

-

The session you are using has expired. Request a new one before continuing.

-

402 Payment Required - -

-

For one reason or another the payment requested was declined. Usually due to typos, but could also do with credit card holds, insufficient funds, etc.

-

403 Forbidden - -

-

You do not have the privileges necessary to complete that operation.

-

404 Not Found - -

-

The object you requested doesn’t exist. This refers to an object specified in the query string, not in the path.

-

408 Request Timeout - -

-

Whatever you requested took too long and the server gave up.

-

409 Conflict - -

-

The name or resource requested is already in use by someone else, or has already moved on to a new stage of it’s life so the function you are trying to perform on it is no longer valid.

-

413 Payload Too Large - -

-

You tried to post something (perhaps upload a file) that is too large.

-

415 Unsupported Media Type - -

-

You tried to assign a file to a field that doesn’t match the field’s criteria or you tried to upload a file that the system doesn’t allow. For example you tried to assign a PDF to a field looking for images.

-

429 Too Many Requests - -

-

You have exceeded the maximum number of requests allowed per minute. This exception is telling you to slow down so you don’t denial of service the server with your requests.

-

441 Missing Required Parameter - -

-

You’re missing a required parameter.

-

442 Out Of Range - -

-

The value specified for a field was out of range. If it’s a numeric field make sure you’re above the minumum and below the maximum. If it’s an enumerated field make sure you’ve specfified an valid option.

-

454 Password Incorrect - -

-

The password you specified does not match our records.

-

499 Offline Processing - -

-

This request was going to take too long so it was handed off to be processed in the background.

-

500 Undefined Error - -

-

An unhandled exception has occurred in the server. Under normal operating procedures this should never happen, as all exceptions should be trapped within the code and returned as a defined exception. Therefore this is an untrapped exception, and is in all cases a bug.

-

501 Not Implemented - -

-

You have encountered a feature that is planned, but not yet implemented.

-

502 Bad Gateway - -

-

An external resource returned a garbage response that caused your request to fail.

-

504 Could Not Connect - -

-

Could not connect to an external resource, such as a database or web service.

-
-
- - - - \ No newline at end of file diff --git a/ving/docs/content/error-codes.md b/docs/error-codes.md similarity index 99% rename from ving/docs/content/error-codes.md rename to docs/error-codes.md index 3ecd7cd0..a38fd29f 100644 --- a/ving/docs/content/error-codes.md +++ b/docs/error-codes.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Error Codes This document describes the error codes thrown by Ving's REST API. They map directly onto the [W3C's standard HTTP status codes](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html). When functioning properly the web service will always return a 200 HTTP status code. diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 9c3a1a91..00000000 --- a/docs/index.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - index.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

About Ving - -

-

Ving is a Web and REST code generation tool and services framework. It has a heavy focus on a strong and predictable backend, while having a flexible front end. It’s feature’s include:

- -

Ving is written entirely in Javascript using Nuxt 3, Vue 3, PrimeVue, PrimeFlex and Drizzle.

-

How Ving is Constructed - -

-

Everything starts with the Ving Schema, which defines tables in a database, along with fields, privileges, and other properties. From there everything is automatically generated, but still modifyable by you. Ving will generate database schemas and migrations, server-side Javascript APIs, REST APIs, Web UIs, email templates, and more.

-

Why Rest? - -

-

You might be wondering why REST in a world with tRPC and GraphQL. It’s because REST is language agnostic, and very simple to understand. It’s still the best data presentation layer when you have an API you want the general public to consume. And Ving is all about being fast to implement and easy to maintain. When you want simplcity, you do not want GraphQL or Typescript as there’s nothing uncomplicated about either.

-

Get the Code - -

-

You can visit the GitHub repository to get the source code and start using it.

-
-
- - - - \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..b6b4d3c7 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,65 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "Ving" + text: "" + tagline: An opinionated Nuxt starter with a REST API included + actions: + - theme: brand + text: Installation + link: /installation + - theme: alt + text: Subsystems + link: /subsystems/cache + - theme: alt + text: Rest APIs + link: /rest/User + +features: + - title: Code Generation + details: Automatic code generation for all sub-systems + - title: REST API + details: Platform agnostic REST interface + - title: Granular Privileges + details: Per field privileges for view and edit + - title: Auth + details: Full session based auth system + - title: Files + details: AWS S3 based secure upload system + - title: Messaging + details: Per user message bus streamed via Server Sent Events + - title: API Keys + details: API key and privilege system with access to make requests on behalf of other users + - title: UI + details: A useful set of custom made Nuxt components and composables + - title: Admin + details: A full user interface for user management + - title: Email + details: A fully templated email sending system + - title: Jobs + details: An asynchronous background jobs system +--- + +--- +# About Ving + +Ving is a Web and REST code generation tool and services framework. It has a heavy focus on a strong and predictable backend, while having a flexible front end. + +Ving is written entirely in Javascript using [Nuxt 3](http://nuxt.com), [Vue 3](http://vuejs.org), [PrimeVue](https://primevue.org), [PrimeFlex](https://www.primefaces.org/primeflex/) and [Drizzle](https://github.com/drizzle-team/drizzle-orm). + + +## How Ving is Constructed +Everything starts with the [Ving Schema](subsytems/ving-schema), which defines tables in a database, along with fields, privileges, and other properties. From there everything is automatically generated, but still modifyable by you. Ving will generate [database schemas and migrations](subsytems/drizzle), [server-side Javascript APIs](subsytems/ving-record), [REST APIs](subsytems/rest), [Web UIs](subsytems/ui), [email templates](subsytems/email), and more. + + +## Why Rest? +You might be wondering why REST in a world with tRPC and GraphQL. It's because REST is language agnostic, and very simple to understand. It's still the best data presentation layer when you have an API you want the general public to consume. And Ving is all about being fast to implement and easy to maintain. When you want simplcity, you do not want GraphQL or Typescript as there's nothing uncomplicated about either. + + +## Get the Code +You can [visit the GitHub repository](https://github.com/plainblack/ving) to get the source code and start using it. + +## Install +[Start your installation now.](installation) \ No newline at end of file diff --git a/docs/installation.html b/docs/installation.html deleted file mode 100644 index 953e514c..00000000 --- a/docs/installation.html +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - installation.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Installation - -

-

You need to choose whether you want to be able to get updates from future versions of ving or not.

-

Requirements - -

-

Any modern computer should be able to run ving. But you will need to install a couple of things to get started.

- -

Installation Variants - -

-

If you want updates: FORK - -

-

Choose this option so you can choose to sync the changes from the main ving repo into your repository at any time in the future.

-

Fork the ving repo.

-

After forking, clone your forked repo to your computer.

-

If you don’t want updates: DOWNLOAD - -

-

Choose this option if you just want to use ving as a starter and don’t care about what happens in the future.

-

Download a zip file of the repo.

-

Then unzip it.

-

Either way: RENAME - -

-

Then feel free to rename the folder to whatever you are calling your project.

-
mv ving my-cool-project
-
-

Node Modules - -

-

Type the following:

-
cd ving
-npm install
-
-

VS code - -

-

For developement we recommend Visual Studio Code.

-

And for the best possible experience, we also recommend installing these plugins:

- -

MySQL - -

-

You’ll need to download and install a MySQL 8 database.

-
-

You could convert ving to Postgres or any other supported Drizzle database, but that’s not on our todo list.

-
-

Create the database - -

-

Log in to your MySQL database as the root user and then type the following:

-
create database ving;
-CREATE USER 'ving'@'localhost' IDENTIFIED BY 'vingPass';
-grant all privileges on ving.* to 'ving'@'localhost';
-flush privileges;
-
-
-

Obivously use your own username and password options, not the samples we provided here.

-
-

Create a .env file - -

-

Create .env in the project root and add your dev database connection string.

-
VING_MYSQL="mysql://ving:vingpass@localhost:3306/ving"
-
-
-

Obivously modify the username, password, and database name to match what you created in the previous step.

-
-

Create the initial tables - -

-

Now you can create the initial tables into your database using the CLI.

-
./ving.mjs drizzle --prepare
-./ving.mjs drizzle --up
-
-

Create First User - -

-

Also use the CLI to create a user so you can log in to the web interface.

-
./ving.mjs user --add Admin --email you@domain.com --password 123qwe --admin
-
-

Startup - -

-

Start the development server on http://localhost:3000

-
npm run dev
-
-

Cache - -

-

To use Redis as your cache, you’ll need to configure it first.

-

Email - -

-

Ving offers email sending and templating, but you need to configure an SMTP server first.

-

Configuring AWS - -

-

If you want to make use of AWS for things like storing file uploads in S3, then you’ll also want to check out our Pulumi integration.

-
-
- - - - \ No newline at end of file diff --git a/ving/docs/content/installation.md b/docs/installation.md similarity index 74% rename from ving/docs/content/installation.md rename to docs/installation.md index 5d7568df..cdbe8518 100644 --- a/ving/docs/content/installation.md +++ b/docs/installation.md @@ -1,15 +1,17 @@ +--- +outline: deep +--- # Installation -You need to choose whether you want to be able to get updates from future versions of ving or not. ## Requirements -Any modern computer should be able to run ving. But you will need to install a couple of things to get started. - - - You'll need to [download](https://nodejs.org/en) and install Node. +Any modern computer should be able to run ving, but you will need to [download and install Node.js](https://nodejs.org/en). ## Installation Variants +You need to choose whether you want to be able to get updates from future versions of ving or not. + ### If you want updates: FORK Choose this option so you can choose to [sync](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork) the changes from the main ving repo into your repository at any time in the future. @@ -75,7 +77,7 @@ grant all privileges on ving.* to 'ving'@'localhost'; flush privileges; ``` -> Obivously use your own username and password options, not the samples we provided here. +> Use your own username and password options, not the samples we provided here. ### Create a .env file @@ -85,11 +87,11 @@ Create `.env` in the project root and add your dev database connection string. VING_MYSQL="mysql://ving:vingpass@localhost:3306/ving" ``` -> Obivously modify the username, password, and database name to match what you created in the previous step. +> Modify the username, password, and database name to match what you created in the previous step. ### Create the initial tables -Now you can create the initial tables into your database using the [CLI](cli.html). +Now you can create the initial tables into your database using the [CLI](subsystems/cli). ```bash ./ving.mjs drizzle --prepare @@ -98,7 +100,7 @@ Now you can create the initial tables into your database using the [CLI](cli.htm ### Create First User -Also use the [CLI](cli.html) to create a user so you can log in to the web interface. +Also use the [CLI](subsystems/cli) to create a user so you can log in to the web interface. ```bash ./ving.mjs user --add Admin --email you@domain.com --password 123qwe --admin @@ -112,11 +114,9 @@ Start the development server on http://localhost:3000 npm run dev ``` -## Cache -To use [Redis as your cache](cache.html), you'll need to configure it first. - -## Email -Ving offers [email sending and templating](email.html), but you need to configure an SMTP server first. +## Optional Extras +To make full use of all of Ving's features, there are other things you'll need to configure: -## Configuring AWS -If you want to make use of AWS for things like storing file uploads in S3, then you'll also want to check out our [Pulumi](pulumi.html) integration. +- To use [Redis as your cache](subsystems/cache), use the [message bus](subsystems/messagebus), or the [jobs system](subsystems/jobs) you'll need to configure Redis first. +- Ving offers [email sending and templating](subsystems/email), but you need to configure an SMTP server first. +- If you want to make use of AWS for things like storing file uploads in S3, then you'll also want to check out our [Pulumi](subsystems/pulumi) integration. diff --git a/docs/jobs.html b/docs/jobs.html deleted file mode 100644 index d5886463..00000000 --- a/docs/jobs.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - jobs.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Jobs - -

-

Ving uses a jobs server called BullMQ to execute potentially long running asynchronous background jobs.

-

Setting Up Redis - -

-

To use the jobs system you must first have a Redis server. Then you simply need to add an entry in .env that points to your Redis server like so:

-
VING_REDIS="redis://@localhost:6379"
-
-

You can include a username and password in the URL like so:

-
VING_REDIS="redis://user:pass@localhost:6379"
-
-

NOTE: You must enable the setting maxmemory-policy=noeviction in your Redis server to prevent it from automatically deleting keys when memory runs low as this will cause problems with the BullMQ system.

-

Enqueueing Jobs - -

-

To enqueue a job you’d use the following code.

-
import ving from '#ving/index.mjs';
-
-ving.addJob('Test', { foo: 'bar' }, { delay: 1000 * 60 });
-
-

That would run a handler called Test with the parameter of { foo: 'bar' }, but first it would wait 60 seconds before the job would be run.

-

You can also enqueue jobs from the CLI.

-
./ving.mjs jobs --addJob Test --jobData '{ "foo": "bar" }'
-
-

Running Jobs - -

-

Jobs are run by job workers using handlers. The job worker system is run via the CLI.

-
./ving.mjs --worker --ttl 60
-
-

The above would run a worker for 60 seconds afterwhich the worker would shut down. If you want to run it indefinitely just leave the ttl off.

-

Job Handlers - -

-

At the heart of the jobs system are handlers. Handlers are custom code that knows how to process a job. You can find handlers in the #ving/jobs/handlers folder. This is what a simple handler looks like:

-
import ving from '#ving/index.mjs';
-
-export default async function (job) {
-    ving.log('jobs').debug(`Test ran with data: ${JSON.stringify(job.data)}`);
-    return true;
-}
-
-

The handler’s job is to do whatever needs to be done with job.data to complete the job. It should return true when done, or throw an ouch if it fails.

-
-
- - - - \ No newline at end of file diff --git a/docs/logging.html b/docs/logging.html deleted file mode 100644 index fa517ebb..00000000 --- a/docs/logging.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - logging.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Logging - -

-

By default Ving logs to the logs folder. It automatically rotates its own logs.

-

Ving uses Winston for logging. Winston has a lot of amazing configurability, so instead of creating a config file that cannot possibly encapsulate all of that, we leave it to you to modify server/log.mjs.

-

Writing To Logs - -

-

To write to a log you’d do something like this:

-
import ving from '#ving/index.mjs';
-ving.log('topic').error('Error message goes here.');
-
-

The parameter going into the log() function is there to set a topic (or category) for the log entry, and then the actual message to be logged would go inside one of the sub functions. Sub function are info(), error(), warn(), or debug().

-
-
- - - - \ No newline at end of file diff --git a/docs/markdown-examples.md b/docs/markdown-examples.md new file mode 100644 index 00000000..f9258a55 --- /dev/null +++ b/docs/markdown-examples.md @@ -0,0 +1,85 @@ +# Markdown Extension Examples + +This page demonstrates some of the built-in markdown extensions provided by VitePress. + +## Syntax Highlighting + +VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting: + +**Input** + +````md +```js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` +```` + +**Output** + +```js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` + +## Custom Containers + +**Input** + +```md +::: info +This is an info box. +::: + +::: tip +This is a tip. +::: + +::: warning +This is a warning. +::: + +::: danger +This is a dangerous warning. +::: + +::: details +This is a details block. +::: +``` + +**Output** + +::: info +This is an info box. +::: + +::: tip +This is a tip. +::: + +::: warning +This is a warning. +::: + +::: danger +This is a dangerous warning. +::: + +::: details +This is a details block. +::: + +## More + +Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown). diff --git a/docs/messagebus.html b/docs/messagebus.html deleted file mode 100644 index 31837228..00000000 --- a/docs/messagebus.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - messagebus.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Message Bus - -

-

Ving’s Message Bus push messages from the server to a logged in user via Server Sent Events (SSE). This can be useful for displaying a toast via the notification system, or for triggering some functionality when a background job finishes.

-

If you’d like to test it, log in to your ving site and then from the CLI type:

-
./ving.mjs messagebus -u Admin -m "Hello Admin!"
-
-

Note that this functionality requires that you’ve set up the Redis cache.

-

Extending Functionality - -

-

If you want to extend this functionality to send your own message types from the server to the browser, you’ll need to do the following 3 steps.

-

Configure a Publisher Function - -

-

In server/messagebus.mjs add and export a function that will publish the message. Let’s say we’re going to update a progress bar somewhere for some background process. We’d create a publisher function for that like:

-
export const publishSomeProgressBar = async (
-    userId, 
-    percentageComplete = 0, 
-    fullyComplete = 100
-) => {
-    return publish(
-        userId, 
-        'someProgressBar', 
-        { percentageComplete, fullyComplete }
-    );
-}
-
-

Note that you can skip this step and use use the generic publish function, but that doesn’t give you the opportunity to add defaults, an API, or error handling so we recommend creating a publish function.

-

Use The Publisher Function - -

-

Wherever in your code that you can get your event data to publish to the browser, use your newly created publisher function.

-
import {publishSomeProgressBar} from '../server/messagebus.mjs'
-
-await publishSomeProgressBar(userId, 35);
-
-

Make The Browser Handle It - -

-

You’ll need to update composables/useMessageBus.mjs to handle your someProgressBar message type. Add your new case to the switch statement there.

-
-
- - - - \ No newline at end of file diff --git a/docs/pulumi.html b/docs/pulumi.html deleted file mode 100644 index 02e80f29..00000000 --- a/docs/pulumi.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - pulumi.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Pulumi - -

-

Pulumi is an open source Infrastructure as Code (IaC) system. It allows you to automate setting up servers and services. Ving uses it to make configuring AWS faster, rather than giving you a bunch of instructions to perform and hope you get them all right, we’ve programmed Pulumi to do it for you.

-

Setup - -

-

Follow the Pulumi install instructions.

-

If you have not already set up an AWS credentials file in ~/.aws/credentials then you’ll want to do that now as pulumi will use that to log in to AWS.

-

Then edit the Pulumi.yaml file and change the name field from ving to your project name. This name will be used to prefix all the generated services in AWS so you know what we made.

-

Then type pulumi up at your command line. When it asks you about what stack you want, say dev unless you already know how to use pulumi and want to use your own stack name. And once it shows you its plan for deployment, use your arrow key to move up to yes to deploy it.

-

Using Pulumi For Your Own Needs - -

-

By editing Pulumi.mjs you can add your own infrastructure automations. And then use pulumi up to roll them out to the server. Just make sure you don’t remove or change any of the pulumi code that we have there unless you understand the implications.

-
-
- - - - \ No newline at end of file diff --git a/docs/rest.html b/docs/rest.html deleted file mode 100644 index f9070397..00000000 --- a/docs/rest.html +++ /dev/null @@ -1,590 +0,0 @@ - - - - - - rest.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Rest API - -

-

The restful web services that ving creates are not only used to drive the UI, but also are intended to be used by your fans, customers, and the general public to interact with your web site in an automated fashion. This is the core reason we generate REST endpoints rather than using something like tRPC.

-

This document will tell you about the general premise of the Rest interface.

-

Generation - -

-

Your Rest endpoints will be generated from your Ving Schema by using the CLI:

-
./ving.mjs record --rest Foo
-
-

These will be placed in the server/api/foo folder and can be modified by you after the fact.

-

Conventions - -

-

There are several conventions used in this documentation to keep things shorter. They are documented here.

-

Ellipsis - -

-

We often shorten pieces of return values with ellipsis (three dots: …) to show that there would be additional data there, but it is not directly relevent to the documentation at hand.

-

ID’s - -

-

ID’s are often represented as 3 x’s: xxx. If you see xxx anywhere that means that would be replaced by a legitimate ID and shouldn’t be interpreted literally. Also, ID’s are case-sensitive strings, so store them as such.

-

Prefix - -

-

When referencing any API herein we omit the domain for the site. So you should prefix it with whatever site you are trying to access like:

-
http://some.example.com/api/user/xxx
-
-

Requests and Responses - -

-

To make a request to a Wing web service you need nothing more than a command line tool like curl, or better yet use the VS Code Rest Client. You can of course use any network aware programming language as well. Here’s an example request using the VS Code Rest Client:

-

Create a record - -

-
POST http://ving.example.com/api/article
-Content-Type: application/json
-
-{ 
-    "title" : "Ethics in Prisons", 
-    "author" : "Andy Dufresne" 
-}
-
-

Response:

-
{
-   "props" : {
-     "id" : "xxx",
-     "author" : "Andy Dufresne",
-     "title" : "Ethics in Prisons",
-     "body" : ""
-   }
-}
-
-

Read a record - -

-
GET http://wing.example.com/api/article/xxx
-
-

Response:

-
{
-   "props" : {
-     "id" : "xxx",
-     "author" : "Andy Dufresne",
-     "title" : "Ethics in Prisons",
-     "body" : ""
-   }
-}
-
-

Update a record - -

-
PUT http://ving.example.com/api/article/xxx
-Content-Type: application/json
-
-{
-    "body" : "..."
-}
-
-

Response:

-
 {
-   "props" : {
-     "id" : "xxx",
-     "author" : "Andy Dufresne",
-     "title" : "Ethics in Prisons",
-     "body" : "..."
-   }
- }
-
-

Delete a record - -

-
DELETE http://ving.example.com/api/article/xxx?includeMeta=true
-
-

Response

-

- {
-   "props" : { 
-     "id" : "xxx",
-     "author" : "Andy Dufresne",
-     "title" : "Ethics in Prisons",
-     "body" : "..."
-   },
-   "meta" : {
-     "deleted" : true
-   }
- }
-
-

Get a list of records - -

-
GET http://ving.example.com/api/article
-
-

Response:

-
{
-    "paging": {
-        "page": 1,
-        "nextPage": 2,
-        "previousPage": 1,
-        "itemsPerPage": 10,
-        "totalItems": 43,
-        "totalPages": 5
-    },
-    "items" : [
-        {
-            "props" : {
-                "id" : "xxx",
-                "author" : "Andy Dufresne",
-                "title" : "Ethics in Prisons",
-                "body" : "..."
-            }
-        },
-        ...
-    ]
-}
-
-

Authenticated Requests - -

-

With each request you can vingSessionId cookie header if you want to get an -authenticated result. If you choose not to pass the vingSessionId, then -the result you receive will be the public result set. If you do pass the -vingSessionId then you’ll get the private result set (provided your session -has the privileges to receive the private result set). For example, if you -request information about your user account without specifying a vingSessionId -then all you’d get back is an ID and some other basic information, like this:

-
GET http://wing.example.com/api/user/xxx?includeMeta=true
-
-

Response:

-
{
-   "props" : {
-     "id" : "xxx",
-     "createdAt" : "2012-04-23T18:25:43.511Z",
-     "createdAt" : "2023-04-25T08:13:10.001Z",
-     ...
-   },
-   "meta" : {
-     "displayName" : "Andy Dufresne",
-     ...
-   },
-}
-
-

But if you request your account information with your vingSessionId, then you’d -get a result set with everything we know about you:

-
GET http://wing.example.com/api/user/xxx?includeMeta=true
-Cookie: vingSessionId="yyy"
-
-

Response:

-
{
-   "props" : {
-     "id" : "xxx",
-     "createdAt" : "2012-04-23T18:25:43.511Z",
-     "createdAt" : "2023-04-25T08:13:10.001Z",
-     "realName" : "Andy Dufresne",
-     "username" : "andy",
-     "email" : "andy@shawshank.jail",
-     "useAsDisplayName" : "realName",
-     ...
-   },
-   "meta" : {
-     "displayName" : "Andy Dufresne",
-     ...
-   },
-}
-
-

However, if I requested information about your account, and specified my own -vingSessionId, then I would only get the public data. Because I don’t have -the privileges necessary to access your private information.

-

See also Session and User.

-

Consistency - -

-

A big part of the ving specification is that you can reliably expect it to do the same thing in all circumstances. Here are a few key points of consistency.

-

Records - -

-

All record objects contain the following minimum shared set of attributes.

-

props - -

-

An object of database stored properties.

-
id - -
-

A unique id that will never change. It is a 36 character GUID (global unique id).

-
createdAt - -
-

The date this record came into existence.

-
updatedAt - -
-

The last time this record was written to the database.

- -

An object of links to API endpoints related to this record.

-
base - -
-

A link to create records of this type or list all records in the system of this type.

-
self - -
-

A link to get/delete this sepecfic record.

-

meta - -

-

An object of generated properties.

-
kind - -
-

A string representing the type of object this is in case you need to identify it in the future.

-

Dates - -

-

Dates are always returned in the format of CYYYY-MM-DDTHH:MM:SS.mmmZ (the Javascript/JSON stringified date format) and are represented as the UTC time zone.

-

Response Format - -

-

Ving will always return a JSON response in the form of an object.

-
{
-   "props" : { "success" : 1 }
-}
-
-

Success - -

-

Results will always start with a top level object, and if its a Ving Record it will at minimum have a prop object nested within it.

-
{
-    "props" : {
-      "id" : "xxx",
-      ...
-    }
-}
-
-

Success With Pagination - -

-

Paginated lists are always handled exactly the same way, and always have the same minimum set of parameters for manipulation.

-
GET /api/article?itemsPerPage=25&page=3
-
-

You can tell how many items per page to return and which page number to return. That will give you a result set like this:

-
{
-    "paging": {
-        "page": 3,
-        "nextPage": 4,
-        "previousPage": 2,
-        "itemsPerPage": 25,
-        "totalItems": 937,
-        "totalPages": 38
-    },
-    "items" : [
-        {
-            "props" : {
-                "id" : "xxx",
-                "author" : "Andy Dufresne",
-                "title" : "Ethics in Prisons",
-                "body" : "..."
-            }
-        },
-        ...
-    ]
-}
-
-
Pagination Query Params - -
- -

Exceptions - -

-

Exceptions will always start with a top level element called error and then will have an object of 3 properties: code, message, data.

-
 {
-   "error" : {
-     "code" : 500,
-     "message" : "An unknown error has occurred.",
-     "data" : null
-   }
- }
-
-

The code is always an integer and conforms to the standard list of Error Codes. These numbers are used consistently so that app developers can trap and handle specific types of exceptions more gracefully.

-

The message is a human readable message that you can display to a user.

-

The data element many times will be null, but it can have important debug information. For example, if a required field was left empty, the field name could be put in the data element so that the app could highlight the field for the user.

-

Warnings - -

-

In addition to exceptions there can be less severe issues that come up. These are handled via warnings. Warnings are just like exceptions, but they don’t cause execution to halt. As such there can be any number of warnings. And warnings are returned with the result.

-
 {
-    "warnings" : [
-        {
-            "code" : 445,
-            "message" : "Logo image is too big.",
-            "data" : "logo"
-        }
-    ],
-    ...
- }
-
-

Relationships - -

-

All objects can have relationships to each other. When you fetch an object, you can pass includeLinks=true as a parameter if you want to get the relationship data as well.

-
GET /api/article/xxx?includeLinks=true
-
-

Response:

-
 {
-   "props" : {
-     "id" : "xxx",
-     ...
-    },
-    "links" : {
-        "base" : {
-          "href": "/api/user",
-          "methods": ["GET","POST"]
-        }, 
-        "self" : {
-          "href": "/api/user/xxx",
-          "methods": ["GET","PUT","DELETE"]
-        },
-        "articles" : {
-          "href": "/user/xxx/articles",
-          "methods": ["GET"]
-        },
-     }
-   }
- }
-
-

You can then in-turn call the URI provided by each relationship to fetch the items in that list.

- -

Likewise you can request related objects (those with relationship type of parent) be included directly in the result by adding the name of the related record relationship like `includeRelated=user as a parameter:

-
GET /article/xxx?includeRelated=user&includeMeta=true
-
-

Response:

-
 {
-   "props" : {
-     "id" : "xxx",
-     "author" : "Andy Dufresne",
-     "title" : "Ethics in Prisons",
-     "body" : "...",
-     "userId" : "xxx",
-   },
-   "related" : {
-     "user" : {
-        "props" : {
-            "id" : "xxx",
-            ...
-        },
-        "meta" : {
-            "displayName" : "Andy Dufresne",
-            ...
-        }
-     }
-   }
- }
-
-

All related objects are also inherently relationships of the object. Therefore the documentation will leave them out of the list of relationships in each object, but will include them in the list of related objects.

-
-

NOTE: The only related objects that can be returned in this manner are 1:1 relationships. If the relationship is 1:N as in the case of related articles above, then those cannot not be included in the result, and must be fetched separately.

-
-

Filters - -

-

Filters allow you to modify the result set when querying a list of records.

-

Queryable - -

-

Some relationships will allow you to use a search parameter on the URL that will allow you to search the result set. The documentation will tell you when this is the case and which fields will be searched to provide you with a result set.

-
GET /api/article/xxx/related-articles?search=prison
-
-

Qualifiers - -

-

In search engines these are sometimes called facets. They are criteria that allow you to filter the result set by specific values of a specfic field. The documentation will tell you when a relationship has a qualifier. To use it you’d add a parameter of the name of the qualifier to the URL along with the value you want to search for.

-
GET /api/article/xxx/related-articles?userId=xxx
-
-

That will search for all related articles with a userId of xxx.

-

You can also modify the qualifier by prepending operators such as >, >=, <=, and <> (or !=) onto the value. For example:

-
 GET /api/article/xxx/related-articles?wordCount=>=100
-
-

Get all related articles with a word count greater than or equal to 100.

-

You can also request that a qualifier be limited to a null value.

-
GET /api/article/xxx/related-articles?userId=null
-
-

If you did this with an empty '' or undefined value rather than specifically null then this qualifier will be skipped.

-

Ranged - -

-

You can also use ranged filters to limit data that must fall between 2 values by prepending _start_ or _end_ to the name of the prop you wish to filter on range.

-
GET /api/article/xxx/related-articles \
-  ?_start_createdAt=2012-04-23T18:25:43.511Z \
-  &_end_createdAt=2023-04-25T08:13:10.001Z
-
-

Extra Includes - -

-

Some records will allow for extra includes, and will show this in the documenation. Extra includes are extra bits of data you can pull back when you request the record, that are unique to that record.

-
GET /api/article/xxx/related-articles?includeExtra=foo
-
-

The result will then have foo in an extras block like:

-
 {
-    "props" : {
-        "id" : "xxx",
-        ...
-    }
-    "extras" : {
-        "foo" : {...}
-    }
- }
-
-

Options - -

-

Sometimes a record will have fields that require you to choose an option from an enumerated list. There are two ways to see what those options are:

-

This way would be most often used when you need the list of options in order to create a record.

-
GET /api/article/options
-
-

Response:

-
{
-    "bookType" : [
-        {"label" : "Hardcover", "value" : "hard" },
-        {"label" : "Paperback", "value" : "soft" }
-    ],
-    ...
-}
-
-

This way would be most often used when you need the list of options to update an object, because you can get the properties of the object and the options in one call.

-
GET http://wing.example.com/article/xxx?includeOptions=true
-
-
 {
-   "props" : {
-     "id" : "xxx",
-     ...
-   },
-   "options" : {
-        "bookType" : [
-            {"label" : "Hardcover", "value" : "hard" },
-            {"label" : "Paperback", "value" : "soft" }
-        ],
-        ...
-    }
- }
-
-

Client Examples - -

-

useVingRecord Composable - -

-

There is a composable built into ving called useVingRecord that will allow you to access the Rest API easily for individual records.

-

useVingKind Composable - -

-

There is a composable built into ving called useVingKind that will allow you to access the Rest API easily for lists of records. It uses the useVingRecord composable underneath to give you access to the individual records within the list.

-

curl - -

-
curl -X POST -d '{"title":"Ethics in Prisons","author":"Andy Dufresne"}' \
-  -H Content-Type: application/json \
-  -H Cookie: vingSessionId=yyy http://ving.example.com/api/article
-
-

VS Code Rest Client - -

-

VS Code Rest Client

-
POST http://ving.example.com/api/article
-Content-Type: application/json
-Cookie: vingSessionId=yyy
-
-{ 
-    "title" : "Ethics in Prisons", 
-    "author" : "Andy Dufresne" 
-}
-
-

Testing - -

-

If you don’t want to use an available client, but instead write your own, there is a Test API that can help make sure your client is working before you start using the real web service.

-
-
- - - - \ No newline at end of file diff --git a/ving/docs/content/APIKey.md b/docs/rest/APIKey.md similarity index 75% rename from ving/docs/content/APIKey.md rename to docs/rest/APIKey.md index b4477dec..bb9b9689 100644 --- a/ving/docs/content/APIKey.md +++ b/docs/rest/APIKey.md @@ -1,5 +1,8 @@ +--- +outline: deep +--- # APIKey -Developers use an API Key to create a [Session](Session.html) via the Rest API and perform other functions that require validation. +Developers use an API Key to create a [Session](Session) via the Rest API and perform other functions that require validation. ## Filters @@ -13,7 +16,7 @@ Developers use an API Key to create a [Session](Session.html) via the Rest API a | Name | Record | Type | Endpoint | | --- | --- | --- | --- | -| user | [User](User.html) | Parent | /api/apikey/:id/user | +| user | [User](User) | Parent | /api/apikey/:id/user | ## Endpoints diff --git a/ving/docs/content/S3File.md b/docs/rest/S3File.md similarity index 92% rename from ving/docs/content/S3File.md rename to docs/rest/S3File.md index 680b0784..c18d6199 100644 --- a/ving/docs/content/S3File.md +++ b/docs/rest/S3File.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # S3File S3File is the file upload system of Ving. @@ -40,8 +43,8 @@ Browser / Your Code --> POST filename and content type to /api/s3file | Name | Record | Type | Endpoint | | --- | --- | --- | --- | -| user | [User](User.html) | Parent | /api/s3file/:id/user | -| avatarUsers | [User](User.html) | Child | /api/s3file/:id/avatarusers | +| user | [User](User) | Parent | /api/s3file/:id/user | +| avatarUsers | [User](User) | Child | /api/s3file/:id/avatarusers | ## Endpoints diff --git a/ving/docs/content/Session.md b/docs/rest/Session.md similarity index 88% rename from ving/docs/content/Session.md rename to docs/rest/Session.md index ccf1bdba..532ae362 100644 --- a/ving/docs/content/Session.md +++ b/docs/rest/Session.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Session In order to access privileged data you'll on any ving endpoint you'll need to pass a session id via an HTTP header cookie. @@ -5,7 +8,7 @@ In order to access privileged data you'll on any ving endpoint you'll need to pa | Name | Record | Type | Endpoint | | --- | --- | --- | --- | -| user | [User](User.html) | Parent | /api/apikey/:id/user | +| user | [User](User) | Parent | /api/session/:id/user | ## Endpoints diff --git a/ving/docs/content/Test.md b/docs/rest/Test.md similarity index 96% rename from ving/docs/content/Test.md rename to docs/rest/Test.md index aa5c1c4a..4aa1369e 100644 --- a/ving/docs/content/Test.md +++ b/docs/rest/Test.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Test Use this endpoint to test that you can post query params and body params to a ving service. diff --git a/ving/docs/content/User.md b/docs/rest/User.md similarity index 86% rename from ving/docs/content/User.md rename to docs/rest/User.md index d4963f2c..ef2106ba 100644 --- a/ving/docs/content/User.md +++ b/docs/rest/User.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # User Users can own records in ving. Users have privileges to access various types of data and store login credentials. @@ -17,8 +20,8 @@ Users can own records in ving. Users have privileges to access various types of | Name | Record | Type | Endpoint | | --- | --- | --- | --- | -| apikeys | [APIKey](APIKey.html) | Child | /api/user/:id/apikeys | -| avatar | [S3File](S3File.html) | Child | /api/user/:id/avatar | +| apikeys | [APIKey](APIKey) | Child | /api/user/:id/apikeys | +| avatar | [S3File](S3File) | Child | /api/user/:id/avatar | ## Endpoints @@ -72,7 +75,7 @@ Cookie: vingSessionId=xxx ``` ### Import Avatar -Attach an uploaded [S3File](S3File.html) to this user as an avatar. +Attach an uploaded [S3File](S3File) to this user as an avatar. ``` PUT /api/user/:id/import-avatar diff --git a/ving/docs/content/cache.md b/docs/subsystems/cache.md similarity index 56% rename from ving/docs/content/cache.md rename to docs/subsystems/cache.md index 9788f18e..a445294c 100644 --- a/ving/docs/content/cache.md +++ b/docs/subsystems/cache.md @@ -1,9 +1,12 @@ +--- +outline: deep +--- # Cache By default ving uses an in-memory cache that goes away every time you restart your server. That's fine for early development, but you get logged out everytime you restart your server, so you're going to want to set up a Redis cache as soon as you can. ## Setting Up Redis -To use a Redis cache, you must first have a Redis server. Then you simply need to add an entry in .env that points to your Redis server like so: +To use a Redis cache, you must first have a [Redis](https://redis.com) server. Then you simply need to add an entry in `.env` that points to your Redis server like so: ``` VING_REDIS="redis://@localhost:6379" @@ -16,12 +19,12 @@ VING_REDIS="redis://user:pass@localhost:6379" ``` ## Using the Cache -You can access the cache via to [CLI](cli.html), but for the most of your work you'll want to programatically access the cache. Here's a quick code example to show you how it works: +You can access the cache via the [CLI](cli), but for the most of your work you'll want to programatically access the cache. Here's a quick code example to show you how it works: ```js import {useCache} from '#ving/cache.mjs'; const cache = useCache(); -await cache.set('foo', 'bar', 60 * 60 * 1000); // set `foo` in key `foo` for 1 hour -const foo = await cache.get('foo'); // `bar` +await cache.set('foo', 'bar', 60 * 60 * 1000); // set `bar` in key `foo` for 1 hour +const foo = await cache.get('foo'); // fetch `bar` from cache await cache.delete('foo'); // delete the value associated with `foo` ``` \ No newline at end of file diff --git a/ving/docs/content/cli.md b/docs/subsystems/cli.md similarity index 95% rename from ving/docs/content/cli.md rename to docs/subsystems/cli.md index 56ea7d30..61a77b1b 100644 --- a/ving/docs/content/cli.md +++ b/docs/subsystems/cli.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # CLI The CLI or Command Line Interface allows you to perform administrative and development functions quickly and easily. diff --git a/ving/docs/content/drizzle.md b/docs/subsystems/drizzle.md similarity index 83% rename from ving/docs/content/drizzle.md rename to docs/subsystems/drizzle.md index 8ddbf6b5..cc9da432 100644 --- a/ving/docs/content/drizzle.md +++ b/docs/subsystems/drizzle.md @@ -1,5 +1,8 @@ +--- +outline: deep +--- # Drizzle -The database layer is controlled by [Drizzle](https://github.com/drizzle-team/drizzle-orm). Drizzle table definitions should be generated from your [ving schema](ving-schema.html). Drizzle provides a convenient way to write SQL queries in Javascript. Drizzle's table definitions keep track of changes to your database schema over time allowing it to automatically generate database change migrations. +The database layer is controlled by [Drizzle](https://github.com/drizzle-team/drizzle-orm). Drizzle table definitions should be generated from your [ving schema](ving-schema). Drizzle provides a convenient way to write SQL queries in Javascript. Drizzle's table definitions keep track of changes to your database schema over time allowing it to automatically generate database change migrations. ## Migrations Migrations are files created to help you migrate changes from one version of your database to another. In some systems you have to manually write migrations. But in ving you don't, thanks to our use of Drizzle. @@ -21,7 +24,7 @@ Drizzle can automatically apply migrations to your database by running this comm ``` ## Writing Queries -Normally you shouldn't have to write many queries as [ving records](ving-record.html) should handle a lot of that for you. But if you write complex backends like we do then inevitably you'll need to write some. +Normally you shouldn't have to write many queries as [ving records](ving-record) should handle a lot of that for you. But if you write complex backends like we do then inevitably you'll need to write some. Writing Drizzle queries looks a lot like how you would write them with SQL, only in Javascript. You probably want to check out the [official Drizzle documentation](https://orm.drizzle.team/docs/overview). @@ -36,7 +39,7 @@ const db = useDB() const result = await db.select().from(UsersTable).where(eq(UsersTable.email, 'joe@example.com')); ``` -Or if you are using [ving records](ving-record.html) then its even easier: +Or if you are using [ving records](ving-record) then its even easier: ```js import {useKind} from '#ving/record/VingRecord.mjs'; diff --git a/ving/docs/content/email.md b/docs/subsystems/email.md similarity index 96% rename from ving/docs/content/email.md rename to docs/subsystems/email.md index 3719b08c..7243f62d 100644 --- a/ving/docs/content/email.md +++ b/docs/subsystems/email.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Email Ving's email system works over SMTP and is defined using templates created via [Nunjucks](https://mozilla.github.io/nunjucks/). @@ -22,7 +25,7 @@ VING_EMAIL_OVERRIDE="example@gmail.com" Normally you'd use this in your dev environment so that all your test users email you instead of whatever made up email addresses you might be using. You can add this to your `.env` file. ### Testing -You can test an email template using the [CLI](cli.html) by typing: +You can test an email template using the [CLI](cli) by typing: ```bash ./ving.mjs email --to=you@gmail.com diff --git a/ving/docs/content/jobs.md b/docs/subsystems/jobs.md similarity index 93% rename from ving/docs/content/jobs.md rename to docs/subsystems/jobs.md index 82720fd3..7976d0db 100644 --- a/ving/docs/content/jobs.md +++ b/docs/subsystems/jobs.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Jobs Ving uses a jobs server called [BullMQ](http://bullmq.io) to execute potentially long running asynchronous background jobs. @@ -27,14 +30,14 @@ ving.addJob('Test', { foo: 'bar' }, { delay: 1000 * 60 }); ``` That would run a handler called `Test` with the parameter of `{ foo: 'bar' }`, but first it would wait 60 seconds before the job would be run. -You can also enqueue jobs from the [CLI](cli.html). +You can also enqueue jobs from the [CLI](cli). ```bash ./ving.mjs jobs --addJob Test --jobData '{ "foo": "bar" }' ``` ## Running Jobs -Jobs are run by job workers using handlers. The job worker system is run via the [CLI](cli.html). +Jobs are run by job workers using handlers. The job worker system is run via the [CLI](cli). ```bash ./ving.mjs --worker --ttl 60 @@ -54,5 +57,5 @@ export default async function (job) { } ``` -The handler's job is to do whatever needs to be done with `job.data` to complete the job. It should return `true` when done, or `throw` an [ouch](utils.html) if it fails. +The handler's job is to do whatever needs to be done with `job.data` to complete the job. It should return `true` when done, or `throw` an [ouch](utils) if it fails. diff --git a/ving/docs/content/logging.md b/docs/subsystems/logging.md similarity index 97% rename from ving/docs/content/logging.md rename to docs/subsystems/logging.md index 7b12e43f..306ad6bd 100644 --- a/ving/docs/content/logging.md +++ b/docs/subsystems/logging.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Logging By default Ving logs to the `logs` folder. It automatically rotates its own logs. diff --git a/ving/docs/content/messagebus.md b/docs/subsystems/messagebus.md similarity index 91% rename from ving/docs/content/messagebus.md rename to docs/subsystems/messagebus.md index cc72f1a6..d5849cc3 100644 --- a/ving/docs/content/messagebus.md +++ b/docs/subsystems/messagebus.md @@ -1,5 +1,8 @@ +--- +outline: deep +--- # Message Bus -Ving's Message Bus push messages from the server to a logged in user via [Server Sent Events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). This can be useful for displaying a toast via the [notification system](ui.html), or for triggering some functionality when a background job finishes. +Ving's Message Bus push messages from the server to a logged in user via [Server Sent Events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). This can be useful for displaying a toast via the [notification system](ui), or for triggering some functionality when a background job finishes. If you'd like to test it, log in to your ving site and then from the CLI type: @@ -7,7 +10,7 @@ If you'd like to test it, log in to your ving site and then from the CLI type: ./ving.mjs messagebus -u Admin -m "Hello Admin!" ``` -Note that this functionality requires that you've set up the [Redis cache](cache.html). +Note that this functionality requires that you've set up the [Redis cache](cache). ## Extending Functionality If you want to extend this functionality to send your own message types from the server to the browser, you'll need to do the following 3 steps. diff --git a/ving/docs/content/pulumi.md b/docs/subsystems/pulumi.md similarity index 98% rename from ving/docs/content/pulumi.md rename to docs/subsystems/pulumi.md index 92c909e0..20091cb3 100644 --- a/ving/docs/content/pulumi.md +++ b/docs/subsystems/pulumi.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Pulumi [Pulumi](https://www.pulumi.com) is an open source Infrastructure as Code (IaC) system. It allows you to automate setting up servers and services. Ving uses it to make configuring AWS faster, rather than giving you a bunch of instructions to perform and hope you get them all right, we've programmed Pulumi to do it for you. diff --git a/ving/docs/content/rest.md b/docs/subsystems/rest.md similarity index 93% rename from ving/docs/content/rest.md rename to docs/subsystems/rest.md index 4e33bf3f..8c1359c5 100644 --- a/ving/docs/content/rest.md +++ b/docs/subsystems/rest.md @@ -1,10 +1,13 @@ +--- +outline: deep +--- # Rest API The restful web services that ving creates are not only used to drive the UI, but also are intended to be used by your fans, customers, and the general public to interact with your web site in an automated fashion. This is the core reason we generate REST endpoints rather than using something like tRPC. This document will tell you about the general premise of the Rest interface. ## Generation -Your Rest endpoints will be generated from your [Ving Schema](ving-schema.html) by using the [CLI](cli.html): +Your Rest endpoints will be generated from your [Ving Schema](ving-schema) by using the [CLI](cli): ```bash ./ving.mjs record --rest Foo @@ -214,7 +217,7 @@ However, if I requested information about your account, and specified my own `vingSessionId`, then I would only get the public data. Because I don't have the privileges necessary to access your private information. -See also [Session](User.html) and [User](User.html). +See also [Session](/rest/Session) and [User](/rest/User). ## Consistency @@ -261,7 +264,7 @@ An object of generated properties. A string representing the type of object this is in case you need to identify it in the future. ### Dates -Dates are always returned in the format of C (the Javascript/JSON stringified date format) and are represented as the UTC time zone. +Dates are always returned in the format of `YYYY-MM-DDTHH:MM:SS.mmmZ` (the Javascript/JSON stringified date format) and are represented as the UTC time zone. ### Response Format @@ -275,7 +278,7 @@ Ving will always return a JSON response in the form of an object. #### Success -Results will always start with a top level object, and if its a [Ving Record](ving-record.html) it will at minimum have a `prop` object nested within it. +Results will always start with a top level object, and if its a [Ving Record](ving-record) it will at minimum have a `prop` object nested within it. ```json { @@ -342,7 +345,7 @@ Exceptions will always start with a top level element called `error` and then wi } ``` -The `code` is always an integer and conforms to the standard list of [Error Codes](error-codes.html). These numbers are used consistently so that app developers can trap and handle specific types of exceptions more gracefully. +The `code` is always an integer and conforms to the standard list of [Error Codes](/error-codes). These numbers are used consistently so that app developers can trap and handle specific types of exceptions more gracefully. The `message` is a human readable message that you can display to a user. @@ -550,10 +553,10 @@ GET http://wing.example.com/article/xxx?includeOptions=true ## Client Examples ### useVingRecord Composable -There is a composable built into ving called [useVingRecord](ui.html#usevingrecord()) that will allow you to access the Rest API easily for individual records. +There is a composable built into ving called [useVingRecord](ui#usevingrecord()) that will allow you to access the Rest API easily for individual records. ### useVingKind Composable -There is a composable built into ving called [useVingKind](ui.html#usevingkind()) that will allow you to access the Rest API easily for lists of records. It uses the useVingRecord composable underneath to give you access to the individual records within the list. +There is a composable built into ving called [useVingKind](ui#usevingkind()) that will allow you to access the Rest API easily for lists of records. It uses the useVingRecord composable underneath to give you access to the individual records within the list. ### curl ``` @@ -577,4 +580,4 @@ Cookie: vingSessionId=yyy ``` ## Testing -If you don't want to use an available client, but instead write your own, there is a [Test API](Test.html) that can help make sure your client is working before you start using the real web service. \ No newline at end of file +If you don't want to use an available client, but instead write your own, there is a [Test API](/rest/Test) that can help make sure your client is working before you start using the real web service. \ No newline at end of file diff --git a/ving/docs/content/ui.md b/docs/subsystems/ui.md similarity index 86% rename from ving/docs/content/ui.md rename to docs/subsystems/ui.md index d0e923c6..a2ad9d34 100644 --- a/ving/docs/content/ui.md +++ b/docs/subsystems/ui.md @@ -1,17 +1,20 @@ +--- +outline: deep +--- # Web UI -The web user interface of ving allows you to build out complex applications using Vue 3. It starts with [automatically generating pages](ui.html) for your ving records. We use a component library suite called [PrimeVue](https://primevue.org/) that provides all kinds of amazing functionality and a styling library called [PrimeFlex](https://www.primefaces.org/primeflex/) that gives you rich power over CSS. But we've also got a bunch of custom [components](ui.html), [composables](ui.html), and [stores](ui.html) to help you build your app. +The web user interface of ving allows you to build out complex applications using Vue 3. It starts with automatically generating pages for your ving records. We use a component library suite called [PrimeVue](https://primevue.org/) that provides all kinds of amazing functionality and a styling library called [PrimeFlex](https://www.primefaces.org/primeflex/) that gives you rich power over CSS. But we've also got a bunch of custom [components](#components) and [composables](#composables) to help you build your app. ## Pages ving is ultimately built on [Nuxt](https://nuxt.com/), so ving pages can do anything [Nuxt Pages](https://nuxt.com/docs/guide/directory-structure/pages) can do. -You can automatically generate a set of pages for interacting with [ving records](ving-record.html) through the [Rest API](/rest) by using the [CLI](cli.html) like this: +You can automatically generate a set of pages for interacting with [ving records](ving-record) through the [Rest API](rest) by using the [CLI](cli) like this: ```bash ./ving.ts record --web Foo ``` -That will give you a place to start, and then you can use the [composables](ui.html#composables), [components](ui.html#components), and [stores](ui.html#stores) we provide to build out a complex app. +That will give you a place to start, and then you can use the [composables](#composables) and [components](#components) we provide to build out a complex app. ## Components @@ -39,7 +42,7 @@ Props: ### Dropzone -Creates a user interface for uploading [S3Files](S3File.html). It handles the resizing of images on the client side, restriction of file types on the client side, requesting the presigned upload URL, uploading the file to S3. The only thing you need to do is specify via `afterUpload` what happens to the file after the user uploads it. +Creates a user interface for uploading [S3Files](/rest/S3File). It handles the resizing of images on the client side, restriction of file types on the client side, requesting the presigned upload URL, uploading the file to S3. The only thing you need to do is specify via `afterUpload` what happens to the file after the user uploads it. Note that you should always wrap this in a `` tag. @@ -162,7 +165,7 @@ Place this in your layouts so that users can receive toasts that will be trigger ``` ### Pager -Displays a pagination bar for a [useVingKind() result set](ui.html#usevingkind()). +Displays a pagination bar for a [useVingKind() result set](#usevingkind). ```html @@ -170,7 +173,7 @@ Displays a pagination bar for a [useVingKind() result set](ui.html#usevingkind() Props: -- **kind** - A [useVingKind() object](ui.html#usevingkind()). +- **kind** - A [useVingKind() object](usevingkind). ### SystemWideAlert Place this in your layouts where you would like the system wide alert to be displayed when an admin has configured one. It is triggered by the `useSystemWideAlertStore()` composable. @@ -231,7 +234,7 @@ const timeago = dt.formatTimeAgo("2012-04-23T18:25:43.511Z"); ``` ### useMessageBus() -Connects the browser to the server's [message bus](messagebus.html). It establishes a connection between your browser and the server, so it needs to be installed in an `onMounted()` handler in your layouts. +Connects the browser to the server's [message bus](messagebus). It establishes a connection between your browser and the server, so it needs to be installed in an `onMounted()` handler in your layouts. ```js onMounted(() => { useMessageBus(); @@ -287,7 +290,7 @@ You may also wish to trigger it for other background actions that are happening ### useVingKind() -A client for interacting with [server-side ving kinds](ving-record.html#kind-api) through the [Rest API](rest.html). +A client for interacting with [server-side ving kinds](ving-record#kind-api) through the [Rest API](rest). ```js const users = useVingKind({ @@ -301,7 +304,7 @@ onBeforeRouteLeave(() => users.dispose()); ``` ### useVingRecord() -A client for interacting with [server-side ving records](ving-record.html#record-api) through the [Rest API](rest.html). +A client for interacting with [server-side ving records](ving-record#record-api) through the [Rest API](rest). ```js const id = route.params.id.toString(); diff --git a/docs/subsystems/utils.md b/docs/subsystems/utils.md new file mode 100644 index 00000000..ac0dcd97 --- /dev/null +++ b/docs/subsystems/utils.md @@ -0,0 +1,5 @@ +--- +outline: deep +--- + +gotta write this \ No newline at end of file diff --git a/ving/docs/content/ving-record.md b/docs/subsystems/ving-record.md similarity index 97% rename from ving/docs/content/ving-record.md rename to docs/subsystems/ving-record.md index 53c2eaff..2f759708 100644 --- a/ving/docs/content/ving-record.md +++ b/docs/subsystems/ving-record.md @@ -1,11 +1,14 @@ +--- +outline: deep +--- # Ving Record -Records are the functional implementation of a [ving schema](ving-schema.html). They automatically generate a ton of functionality from making queries easier, to building web services, to setting up privileges and more. +Records are the functional implementation of a [ving schema](ving-schema). They automatically generate a ton of functionality from making queries easier, to building web services, to setting up privileges and more. ## Records vs Kinds A ving record is technically 2 separate classes. The first is called a "Kind", which is technically a group or list of records. In relational database terms, think of a kind as a table. The second type is the record, which is an instance of a kind, which in relational database terms is a row within a table. Both classes exist inside the record file. See `#ving/record/records/User.mjs` as an example implementation of a record, or `#ving/record/VingRecord.mjs` to see the base class that all ving records inherit from. ## Creating Records -You can use the [CLI](cli.html) to automatically generate a new record file for you from a [Drizzle table](drizzle.html). So if you've created a table called `Foo` then you could create a new record file like this: +You can use the [CLI](cli) to automatically generate a new record file for you from a [Drizzle table](drizzle). So if you've created a table called `Foo` then you could create a new record file like this: ```bash ./ving.mjs record --new Foo @@ -254,7 +257,7 @@ Once you have a record you can use the following methods to manipulate it. ### Reading Data #### describe -Formats everything known about a record into an object that is easily serializable and sanitized for privileges. This is used by the [Rest API](/rest) to format a record for public consumption. +Formats everything known about a record into an object that is easily serializable and sanitized for privileges. This is used by the [Rest API](rest) to format a record for public consumption. ```js const description = await record.describe(params) diff --git a/ving/docs/content/ving-schema.md b/docs/subsystems/ving-schema.md similarity index 95% rename from ving/docs/content/ving-schema.md rename to docs/subsystems/ving-schema.md index 776d2589..6af29ab2 100644 --- a/ving/docs/content/ving-schema.md +++ b/docs/subsystems/ving-schema.md @@ -1,3 +1,6 @@ +--- +outline: deep +--- # Ving Schema You'll find the schemas in `#ving/schema/schemas`. A schema looks like this: @@ -26,7 +29,7 @@ You'll find the schemas in `#ving/schema/schemas`. A schema looks like this: ## Creating a New Schema -Use the [CLI](cli.html) to generate a new schema skeleton to work from. +Use the [CLI](cli) to generate a new schema skeleton to work from. ```bash ./ving.mjs schema --new=Foo @@ -45,7 +48,7 @@ An array containing the method for determining who owns this object. Owners can The owner can be any field that contains a User ID, so in the case of the `User` schema, it can use its own id by specifying `$id`, but in another table it might be `$userId`. -It can also contain any number of roles. By default there are 3 roles: `admin`, `developer`, `verifiedEmail`, but you could add more. Roles can be defined inside the `User` schema (`#ving/schema/schemas/User.mjs`). They have to be added as a [boolean prop type](boolean-props), and then also added to the `RoleOptions` at the bottom of the file. +It can also contain any number of roles. By default there are 3 roles: `admin`, `developer`, `verifiedEmail`, but you could add more. Roles can be defined inside the `User` schema (`#ving/schema/schemas/User.mjs`). They have to be added as a [boolean prop type](#boolean-props), and then also added to the `RoleOptions` at the bottom of the file. It can also defer to a parent object. So let's say you had a record called Invoice and another called LineItem. Each LineItem would have a parent relation to the Invoice called `invoice`. So you could then use `^invoice` (notice the carat) to indicate that you'd like to ask the Invoice if the User owns it, and if the answer is yes, then the LineItem will be considered to also be owned by that user. The carat means "look for a parent relation in the schema" and whatever comes after the carat is the name of that relation. @@ -170,7 +173,7 @@ These are used to add a child relationship. They are virtual because they make n ## Generate Drizzle Tables from Ving Schema -Now that you've created or updated your schema, you can generate [Drizzle](drizzle.html) tables from with this command: +Now that you've created or updated your schema, you can generate [Drizzle](drizzle) tables from with this command: ```bash ./ving.mjs schema --tables diff --git a/docs/ui.html b/docs/ui.html deleted file mode 100644 index f07aa2bc..00000000 --- a/docs/ui.html +++ /dev/null @@ -1,382 +0,0 @@ - - - - - - ui.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Web UI - -

-

The web user interface of ving allows you to build out complex applications using Vue 3. It starts with automatically generating pages for your ving records. We use a component library suite called PrimeVue that provides all kinds of amazing functionality and a styling library called PrimeFlex that gives you rich power over CSS. But we’ve also got a bunch of custom components, composables, and stores to help you build your app.

-

Pages - -

-

ving is ultimately built on Nuxt, so ving pages can do anything Nuxt Pages can do.

-

You can automatically generate a set of pages for interacting with ving records through the Rest API by using the CLI like this:

-
./ving.ts record --web Foo
-
-

That will give you a place to start, and then you can use the composables, components, and stores we provide to build out a complex app.

-

Components - -

-

AdminNav - -

-

Displays the site-wide administrative navigation.

-
<AdminNav :crumbs="breadcrumbs" />
-
-

See Crumbtrail for more info about the crumbs prop.

-

Crumbtrail - -

-

Displays a crumbtrail navigation.

-
<Crumbtrail :crumbs="breadcrumbs" />
-
-

Props:

-
    -
  • crumbs - An array of objects containing: -
      -
    • label - A string for the page name.
    • -
    • to - A string of the page to navigate to.
    • -
    -
  • -
-

Dropzone - -

-

Creates a user interface for uploading S3Files. It handles the resizing of images on the client side, restriction of file types on the client side, requesting the presigned upload URL, uploading the file to S3. The only thing you need to do is specify via afterUpload what happens to the file after the user uploads it.

-

Note that you should always wrap this in a <client-only> tag.

-
<client-only>
-    <Dropzone :acceptedFiles="['.pdf','.zip']" :afterUpload="doThisFunc"></Dropzone>
-</client-only>
-
-

Props:

-
    -
  • acceptedFiles - An array of file extensions that S3File should accept. Note that these should be prepended with a . like .jpg not jpg. Defaults to ['.png','.jpg'].
  • -
  • afterUpload - Required. A function that will be executed after upload. This function should then call the appropriate import endpoint to post process and verify the file.
  • -
  • info - A string that will be displayed inside the dropzone box. Useful to give the user some insights about the nature of the files you will allow such as size or dimension contstraints.
  • -
  • maxFiles - An integer of the maximum number of files the user is allowed to select for upload. Defaults to unlimited.
  • -
  • maxFilesize - An integer of the maximum file size in bytes that the user is allowed to upload. Defaults to 100000000.
  • -
  • resizeHeight - The height in pixels to resize the uploaded image to. Defaults to leaving the size as it is.
  • -
  • resizeMethod - How should a resize of an uploaded image happen? The first option is contain, which is the default, and that means that the image will retain its aspect ratio, but will not exceed the bounds of resizeWidth and resizeHeight. The second option is crop which will crop the middle portion of the image to the bounds of resizeWidth and resizeHeight and discard anything outside those bounds.
  • -
  • resizeQuality - A float representing a percentage of quality that should be applied when resizing jpg and webp images during upload. 0.6 would represent 60% quality. Defaults to 1.
  • -
  • resizeWidth - The width in pixels to resize the uploaded image to. Defaults to leaving the size as it is.
  • -
-

FieldsetItem - -

-

A fieldset element within a FieldsetNav.

-
<FieldsetItem name="Foo">
-Forms go here...
-</FieldsetItem>
-
-

Props:

-
    -
  • name - The name of the field set.
  • -
-

FieldsetNav - -

-

An inline page nav for a large scrollable form to be divided up into sections using FieldsetItem.

-
<FieldsetNav>
-    <FieldsetItem name="Content">...</FieldsetItem>
-    <FieldsetItem name="Taxonomy">...</FieldsetItem>
-    <FieldsetItem name="Privileges">...</FieldsetItem>
-</FieldsetNav>
-
-

Form - -

-

A form element to allow coordination of validation of inputs.

-
<Form :send="someFunc()">...</Form>
-
-

Props:

-
    -
  • send - A function that should be executed once the form is sumbmitted and fields have been validated.
  • -
-

FormInput - -

-

Generate the appropritate form field based upon input types.

-
<FormInput name="username" v-model="user.username" />
-
-

Props:

-
    -
  • label - A form label for proper ARIA compliance.
  • -
  • type - Defaults to text but can also be textarea, password, number, or email.
  • -
  • name - The field name for the form input. Required.
  • -
  • id - Defaults to whatever the name field is set to, but can be any string.
  • -
  • append - Appends an input group to the end of the field. Example: .00
  • -
  • prepend - Prepends an input group to the front of the field. Example $
  • -
  • autocomplete - Sets the browser’s autocomplete settings for password fillers and whatnot. Defaults to off.
  • -
  • v-model - What Vue reactive variable should this be connected to? Required.
  • -
  • placeholder - Text to be displayed if the input is empty.
  • -
  • required - A boolean that defaults to false, but if true will not allow the form to be sent if empty.
  • -
  • step - An amount to increment a number type field. Defaults to 1.
  • -
  • mustMatch - An object containing: -
      -
    • field - A label for a field or some other attribute such as Password.
    • -
    • value - The value that this field must match.
    • -
    -
  • -
  • class - A CSS class that should be applied to the field.
  • -
-

FormLabel - -

-

An ARIA compliant label for a form field.

-
<FormLabel id="foo" label="Foo" />
-
-

Props:

-
    -
  • label - The text to display to the user.
  • -
  • id - The unique id of the form field this label refers to.
  • -
-

FormSelect - -

-

A form select list.

-
<FormSelect>
-
-

Props:

-
    -
  • label - The text label to display to the user.
  • -
  • id - The unique id of the form field. Defaults to whatever is in the name field.
  • -
  • v-model - What Vue reactive variable should this be connected to? Required.
  • -
  • name - The field name for the form input. Required.
  • -
  • options - An array of objects: -
      -
    • label - The human readable label for the value.
    • -
    • value - The value to select. Can be string, number, or boolean.
    • -
    -
  • -
-

Notify - -

-

Place this in your layouts so that users can receive toasts that will be triggered via the useNotifyStore() composable.

-
<client-only>
-    <Notify/>
-</client-only>
-
-

Pager - -

-

Displays a pagination bar for a useVingKind() result set.

-
<Pager :kind="users" />
-
-

Props:

- -

SystemWideAlert - -

-

Place this in your layouts where you would like the system wide alert to be displayed when an admin has configured one. It is triggered by the useSystemWideAlertStore() composable.

-
<client-only>
-    <SystemWideAlert/>
-</client-only>
-
-

Throbber - -

-

Place this in your layouts so the user has an indication that there are some background activites such as rest calls happening. It is triggered by the useThrobberStore() composable.

-
<client-only>
-    <Throbber />
-</client-only>
-
-

UserSettingsNav - -

-

Navigation for user settings.

-
<UserSettingsNav />
-
-

Composables - -

-

Each of these also has documentation of how to use them in the form of JSDocs in the source code.

-

useCurrentUserStore() - -

-

Gets you the currently logged in user.

-
const user = useCurrentUserStore();
-if (await user.isAuthenticated()) {
-    // do logged in user stuff
-}
-
-

It also triggers 2 window events for when the user logs in or out.

-
    window.addEventListener('ving-login', (event) => {
-        // do something after login
-    });
-    window.addEventListener('ving-logout', (event) => {
-        // do something after logout
-    });
-
-

useDateTime() - -

-

Date formatting tools based upon date-fns.

-
const dt = useDateTime()
-const date = dt.determineDate("2012-04-23T18:25:43.511Z");
-const formattedDateTime = dt.formateDateTime(new Date());
-const formattedDate = dt.formateDate(new Date());
-const timeago = dt.formatTimeAgo("2012-04-23T18:25:43.511Z");
-
-

useMessageBus() - -

-

Connects the browser to the server’s message bus. It establishes a connection between your browser and the server, so it needs to be installed in an onMounted() handler in your layouts.

-
onMounted(() => {
-    useMessageBus();
-})
-
-

useNotifyStore() - -

-

Allows you to notify the user via toasts.

-
    const notify = useNotifyStore();
-    notify.info('Just wanted to let you know');
-    notify.warn('You might want to get concerned');
-    notify.error('Be afraid');
-    notify.success('Totally did it');
-    notify.notify('info', 'Hello');
-
-

You would then use the Notify Component in your layout.

-
<client-only>
-    <Notify />
-</client-only>
-
-

useRest() - -

-

A wrapper around the Nuxt composable $fetch() that allows for streamlined fetches, but integrate’s with ving’s subsystems.

-
const response = useFetch('/api/user');
-
-

useSystemWideAlertStore() - -

-

Generally not something you’d need to use, but you will interact with it through the admin UI for the system wide alert, but it is used by the SystemWideAlert component.

-
const swa = useSystemWideAlertStore();
-onMounted(async () => {
-    swa.check();
-}
-
-

useThrobberStore() - -

-

Whenever there is an interaction with the API via the useRest() composable it will update the throbber store. It is then used by the Throbber component.

-

You may also wish to trigger it for other background actions that are happening so that your user knows something is going on at the moment. Maybe if you’re processing a file for export, or if you have some heavy calculations going on, or if you’re waiting on a web worker.

-
    const throbber = useThrobberStore();
-    throbber.working();
-    throbber.done();
-
-

useVingKind() - -

-

A client for interacting with server-side ving kinds through the Rest API.

-
const users = useVingKind({
-    listApi : '/api/user',
-    createApi : '/api/user',
-    query: { includeMeta: true, sortBy: 'username', sortOrder: 'asc' },
-    newDefaults: { username: '', realName: '', email: '' },
-});
-await users.search();
-onBeforeRouteLeave(() => users.dispose());
-
-

useVingRecord() - -

-

A client for interacting with server-side ving records through the Rest API.

-
const id = route.params.id.toString();
-const user = useVingRecord<'User'>({
-    id,
-    fetchApi: '/api/user/' + id,
-    createApi: '/api/user',
-    query: { includeMeta: true, includeOptions: true },
-    onUpdate() {
-        notify.success('Updated user.');
-    },
-    async onDelete() {
-        await navigateTo('/user/admin');
-    },
-});
-await user.fetch()
-onBeforeRouteLeave(() => user.dispose());
-
-
-
- - - - \ No newline at end of file diff --git a/docs/ving-record.html b/docs/ving-record.html deleted file mode 100644 index 0dc76b6a..00000000 --- a/docs/ving-record.html +++ /dev/null @@ -1,506 +0,0 @@ - - - - - - ving-record.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Ving Record - -

-

Records are the functional implementation of a ving schema. They automatically generate a ton of functionality from making queries easier, to building web services, to setting up privileges and more.

-

Records vs Kinds - -

-

A ving record is technically 2 separate classes. The first is called a “Kind”, which is technically a group or list of records. In relational database terms, think of a kind as a table. The second type is the record, which is an instance of a kind, which in relational database terms is a row within a table. Both classes exist inside the record file. See #ving/record/records/User.mjs as an example implementation of a record, or #ving/record/VingRecord.mjs to see the base class that all ving records inherit from.

-

Creating Records - -

-

You can use the CLI to automatically generate a new record file for you from a Drizzle table. So if you’ve created a table called Foo then you could create a new record file like this:

-
./ving.mjs record --new Foo
-
-

That will generate the file #ving/record/records/Foo.mjs. And in there you could add any custom functionality you may need. Or if you don’t need any custom functionality, then it may work just as it is.

-

Once you’re done adding functionality you can then generate a Rest API for it by invoing the CLI again like this:

-
./ving.mjs record --rest Foo
-
-

Those files will be placed in server/api/foo and you can modify them as needed, but they should work without modification. And you can access them at http://localhost:3000/api/foo.

-

And if you want to build a user interface for your services, you can generate that too by invoking the CLI once more.

-
./ving.mjs record --web Foo
-
-

Those files will be placed in pages/foo and you can modify them as needed as well. And you can access them at http://localhost:3000/foo.

-

Kind API - -

-

The Kind is akin to a relational database table. To start with you need to get a reference to it:

-
import {useKind} from '#ving/record/VingKind.mjs';
-const users = await useKind('User');
-
-

Creating Records - -

-

You can create records many different ways. In all three methods you’ll pass in a list of props which is an object containing the values (or columns) to set on the record.

-

copy - -

-

Creates an in-memory copy of an existing record, but with a new id. You’d later have to call insert() (from the Record API) on the record to insert it into the database. This is essentially the same as passing the properties of an exsiting record to the mint() method.

-
const copyOfRecord = Users.copy(existingRecord);
-
-

create - -

-

Creates a new record in the database, but doesn’t validate the inputs according to the ving schema. That doesn’t mean it will get inserted. If you haven’t given enough information to pass the database table’s own schema, then it will fail. You are just bypassing the extra validation provided by ving’s schema. In general, you shouldn’t use this unless you know what you are doing.

-
const record = await Users.create({username: 'Fred'});
-
-

createAndVerify - -

-

Creates a new record in memory, validates it against ving’s schema, and then inserts it into the database. This is almost always what you want.

-
const record = await Users.createAndVerify({username: 'Fred'});
-
-

insert - -

-

Use this to write your own custom insert statement. Also see the insert() method on the Record API.

-
const result = await Users.insert.values({username:'Fred'});
-
-

mint - -

-

Creates a record in memory. You’d later have to call insert() (from the Record API) on the record to insert it into the database.

-
const record = Users.mint({username: 'Fred'});
-
-

Reading Records - -

-

There are many different ways to find a record or list of records in ving.

-

describeList - -

-

Instead of returning records like the rest of this list, describeList() returns an array of objects that is suitable for using in web services. You can use it like this:

-
const list = await Users.describeList(params, where)
-
-

Result - -

-
{
-    paging: {
-        page: 1,
-        nextPage: 2,
-        previousPage: 1,
-        itemsPerPage: 10,
-        totalItems: 43,
-        totalPages: 5
-    },
-    items: [ 
-        { // same as the describe() method from a Record
-            props : { id: 'xxx', ... }, // database properties
-            meta : { displayName : 'Freddy', ... }, // calculated properties
-            links: { 
-                self : { 
-                    href : "/api/user/xxx", 
-                    methods: ['GET','PUT','DELETE'] 
-                }, 
-                ... 
-            }, // urls for various web services 
-            options : { useAsDisplayName : [
-                { label : 'Username', value : 'username' },
-                ...
-            ]}, // options for enumerated / boolean fields
-            related: { }, // records with a parent/sibling relationship to this record
-        },
-        ...
-    ]
-}
-
-

Parameters - -

-
    -
  • params - An object to modify the output. -
      -
    • itemsPerPage - An integer between 1 and 100 that defaults to 10 and represents how many items should be included per page.
    • -
    • page - An integer between 1 and 1000000 that defaults to 1 and represents the current page number of the result set.
    • -
    • sortBy - A string that represents a valid prop of the record and defaults to createdAt.
    • -
    • sortOrder - A string that defaults to asc but could also be desc if you want the order of the records to be sorted in descending order.
    • -
    • maxItems - An integer between 1 and 100000000000 that defaults to 100000000000 that limits the total number of items that can ever be paginated through.
    • -
    • objectParams - See the params of the describe() method in the Record API.
    • -
    -
  • -
  • where - A drizzle where clause like you would use with the findMany() method below.
  • -
-

find - -

-

Locates and returns a single record by it’s id or undefined if no record is found.

-
const record = await Users.find('xxx');
-
-

findMany - -

-

Locates and returns a list of records by a drizzle where clause or an empty array if no records are found.

-
const listOfFredRecords = await Users.findMany(like(Users.realName, 'Fred%'));
-
-

findOne - -

-

Locates and returns a single record by a drizzle where clause or undefined if no record is found.

-
const fredRecord = await Users.findOne(eq(Users.username, 'Fred'));
-
-

findOrDie - -

-

Locates and returns a single record by it’s id or throws a 404 error if no record is found.

-
const record = await Users.findOrDie('xxx');
-
-

select - -

-

Write your own custom select function. Returns a drizzle result set, not a list of records.

-
const results = await Users.select.where(like(Users.realName, 'Fred%'));
-
-

Updating Records - -

-

Updating existing records.

-

update - -

-

Update records already in the database without first selecting them by writing your own custom query.

-
const results = await Users.update.set({admin: false}).where(like(Users.realName, 'Fred%'))
-
-
-

Note that this where clause is raw. To use it safeley you should wrap the like(Users.realName, 'Fred%') portion in the calcWhere() method below.

-
-

See also the update() method in the Record API for updating a record you’ve already fetched.

-

Deleting Records - -

-

delete - -

-

Delete records by writing your own custom query.

-
const results = await Users.delete.where(like(Users.realName, 'Fred%'));
-
-
-

Note that this where clause is raw. To use it safeley you should wrap the like(Users.realName, 'Fred%') portion in the calcWhere() method below.

-
-

See also the delete() method in the Record API for deleting a record you’ve already fetched.

-

deleteMany - -

-

A safer version of delete above as it uses calcWhere().

-
await Users.deleteMany(like(Users.realName, 'Fred%'));
-
-

Utility Methods - -

-

calcWhere - -

-

Adds propDefaults (if any) into a where clause to limit the scope of affected records. As long as you’re using the built in queries you don’t need to use this method. But you might want to use it if you’re using create, select, update, or delete directly.

-
const results = await Users.delete.where(Users.calcWhere(like(Users.realName, 'Fred%')));
-
-

count - -

-

Returns an integer representing how many records match a given where clause.

-
const usersNamedFred = await Users.count(like(Users.realName, 'Fred%'));
-
-

Properties - -

-

propDefaults - -

-

An array of objects containing a list of properties used in building relationships between this record and another. For example the User record uses it like this to establish related APIKey records:

-
apikeys.propDefaults.push({
-    prop: 'userId',
-    field: apikeys.table.userId,
-    value: this.get('id')
-});
-
-

It is then used with calcWhere() to limit the scope of a where clause to related records. So for this example it would limite the list of APIKeys to the ones related to the current User.

-

Record API - -

-

The Record is akin to a relational database table row. You’ll get a record via the Kind API, perhaps like this:

-
import {useKind} from '#ving/record/VingRecord.mjs';
-const users = await useKind('User');
-const record = users.findOrDie('xxx');
-
-

Once you have a record you can use the following methods to manipulate it.

-

Reading Data - -

-

describe - -

-

Formats everything known about a record into an object that is easily serializable and sanitized for privileges. This is used by the Rest API to format a record for public consumption.

-
const description = await record.describe(params)
-
-

Result - -

-
{
-    props : { id: 'xxx', ... }, // database properties
-    meta : { displayName : 'Freddy', ... }, // calculated properties
-    links: { self : { 
-        href : "/api/user/xxx", 
-        methods: ['GET','PUT','DELETE'] 
-        }, 
-        ... 
-    }, // urls for various web services 
-    options : { useAsDisplayName : [
-        { label : 'Username', value : 'username' },
-        ...
-    ]}, // options for enumerated / boolean fields
-    related: { }, // records with a parent/sibling relationship to this record
-    extra : {}, // an object that include literally anything special defined by the object
-}
-
-

Parameters - -

-
    -
  • currentUser - Either a User record or a Session object can be used to determine what data should be included in the description based upon user privileges.
  • -
  • include - An object to modify the output. -
      -
    • options - A boolean that if true will add list of enumerated options for props on this record.
    • -
    • related - An array that can contain the names of parent relationships to this object that should be included in the description.
    • -
    • extra - An array that include the names of special extras that will be included the description.
    • -
    • meta - A boolean that if true will include calculated properties.
    • -
    • links - A boolean that if true will include a list of API links.
    • -
    • private - A boolean that if true will ignore the privileges of the currentUser passed in and include all private information.
    • -
    -
  • -
-

get - -

-

Returns the value of a single prop on this record using the name of the prop.

-
const value = record.get('id');
-
-

getAll - -

-

Returns an object containing key value pairs of all the props stored in the database for this record.

-
const props = record.getAll();
-
-

refresh - -

-

Refetches the data from the database for this record.

-
await record.refresh();
-
-

Writing Data - -

-

createAndVerify - -

-

Calls testCreationProps(), setPostedProps() and insert() in a single method call.

-
await record.createAndVerify({foo: 'bar', one: 1}, currentUserOrSession);
-
-

delete - -

-

Delete the current record from the database.

-
await record.delete();
-
-

insert - -

-

Insert the current record into the database. Can only be called if it hasn’t already been inserted.

-
await record.insert();
-
-

set - -

-

Set the value of a prop on this record. Returns the value set or throws an error if there is a validation problem, which then throws an error. Updates the in memory prop, but doesn’t write it to the database; call update() or insert() for that.

-
user.set('admin', true);
-
-

setAll - -

-

Set the values of multiple props on this record at the same time. Returns an object containing all the props unless there is a validation problem, which then throws an error. Updates the in memory props, but doesn’t write it to the database; call update() or insert() for that.

-
record.set({foo: 'bar', one: 1});
-
-

setPostedProps - -

-

Sets props on the current record from an untrusted source, and thus checks whether a specific user has the privileges to set the prop. Returns true if everything sets properly, or throws an error if there are privilege problems. Updates the in memory props, but doesn’t write it to the database; call update() or insert() for that.

-
await record.setPostedProps({foo: 'bar', one: 1}, currentUserOrSession);
-
-

update - -

-

Updates the current record in the database.

-

updateAndVerify - -

-

Calls setPostedProps() and update() in a single method call.

-
await record.updateAndVerify({foo: 'bar', one: 1}, currentUserOrSession);
-
-

Privileges - -

-

canEdit - -

-

Returns true if the current user has edit rights on this record or throws a 403 error if not.

-
record.canEdit(currentUserOrSession);
-
-

isOwner - -

-

Returns true if the current user or session is defined as the owner of this record, or returns false if not.

-
if (record.isOwner(currentUserOrSession) {
-    console.log('they own it!')
-}
-else {
-    console.log('they do NOT own it!')
-}
-
-

Utility Methods - -

-

addWarning - -

-

Add a warning to the list of warnings so that the user can be notified in the UI.

-
record.addWarning({
-        code : 418,
-        message : "I'm a little teapot."
-    });
-
-

isInserted - -

-

Returns true if this record has been inserted into the database, or false if not.

-

parent - -

-

Returns a parent relationship record by name.

-
const user = apikey.parent('user');
-
-

propOptions - -

-

Returns a list of enumeration options for this record.

-
const options = await user.propOptions(params, false);
-
-

Result - -

-
{ 
-    useAsDisplayName : [
-        { label : 'Username', value : 'username' },
-        ...
-    ],
-    ...
-}
-
-

Parameters - -

-
    -
  • params - an object of all the same paramters as the describe() method.
  • -
  • includeAll - A boolean, that if true, will return all the options regardless of privileges.
  • -
-

testCreationProps - -

-

Tests the properties trying to be set on a new object, and if all the required values are present and valid then it returns true, otherwise it throws a 441 error.

-
await record.testCreationProps({foo:'bar'});
-
-

Properties - -

-

warnings - -

-

An array of warnings for this record that have been added by addWarnings() since this record was instanciated.

-
[
-    {
-        code : 418,
-        message : "I'm a little teapot."
-    },
-    ...
-]
-
-
-
- - - - \ No newline at end of file diff --git a/docs/ving-schema.html b/docs/ving-schema.html deleted file mode 100644 index 5c955725..00000000 --- a/docs/ving-schema.html +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - ving-schema.md - - - - - - - -
-
-
-
Ving Docs
-

Basics

- -

Subsystems

- -

Rest APIs

- - -
-
-
-

Ving Schema - -

-

You’ll find the schemas in #ving/schema/schemas. A schema looks like this:

-
{
-    kind: 'User',
-    tableName: 'users',
-    owner: ['$id', 'admin'],
-    props: [
-        ...baseSchemaProps,
-        {
-            type: "string",
-            name: "username",
-            required: true,
-            unique: true,
-            length: 60,
-            default: '',
-            db: (prop) => dbString(prop),
-            zod: (prop) => zodString(prop),
-            view: [],
-            edit: ['owner'],
-        },
-    ],
-}
-
-

Creating a New Schema - -

-

Use the CLI to generate a new schema skeleton to work from.

-
./ving.mjs schema --new=Foo
-
-

Attributes - -

-

kind - -

-

A string that represents the unique name of the schema and everything generated from it.

-

tableName - -

-

A string that is name of the MySQL database table it will be stored in.

-

owner - -

-

An array containing the method for determining who owns this object. Owners can be assigned special rights on props.

-

The owner can be any field that contains a User ID, so in the case of the User schema, it can use its own id by specifying $id, but in another table it might be $userId.

-

It can also contain any number of roles. By default there are 3 roles: admin, developer, verifiedEmail, but you could add more. Roles can be defined inside the User schema (#ving/schema/schemas/User.mjs). They have to be added as a boolean prop type, and then also added to the RoleOptions at the bottom of the file.

-

It can also defer to a parent object. So let’s say you had a record called Invoice and another called LineItem. Each LineItem would have a parent relation to the Invoice called invoice. So you could then use ^invoice (notice the carat) to indicate that you’d like to ask the Invoice if the User owns it, and if the answer is yes, then the LineItem will be considered to also be owned by that user. The carat means “look for a parent relation in the schema” and whatever comes after the carat is the name of that relation.

-

props - -

-

All schemas should have the base props of id, createdAt, and updatedAt by using ...baseSchemaProps. After that it’s up to you to add your own props to the list. There are many different types of props for different field types.

-

Props all have the fields type, name, required, default, db, zod, view, and edit, but can have more or less fields from there.

-

Prop Privileges - -

-

The view and edit props are arrays that can:

-
    -
  • Be empty, if no one should be able to view or edit that prop
  • -
  • Contain the special keyword public, if everyone should be able to view or edit that prop
  • -
  • Contain any role (such as admin)
  • -
  • Contain the special keyword owner, so that whoever was defined as the owner in the attributes of the schema can view or edit that prop
  • -
-

If a user can edit a prop it can automatically view a prop.

-

Prop Types - -

-
Boolean Props - -
-
{
-    type: "boolean",
-    name: 'admin',
-    required: true,
-    default: false,
-    db: (prop) => dbBoolean(prop),
-    enums: [false, true],
-    enumLabels: ['Not Admin', 'Admin'],
-    view: ['owner'],
-    edit: ['admin'],
-},
-
-
Date Props - -
-
{
-    type: "date",
-    name: "startAt",
-    required: true,
-    autoUpdate: true,
-    default: () => new Date(),
-    db: (prop) => dbDateTime(prop),
-    view: ['public'],
-    edit: [],
-},
-
-
Enum Props - -
-
{
-    type: "enum",
-    name: 'useAsDisplayName',
-    required: true,
-    length: 20,
-    default: 'username',
-    db: (prop) => dbEnum(prop),
-    enums: ['username', 'email', 'realName'],
-    enumLabels: ['Username', 'Email Address', 'Real Name'],
-    view: [],
-    edit: ['owner'],
-},
-
-
Id Props - -
-

These are used to add a parent relationship.

-
{
-    type: "id",
-    name: 'userId',
-    required: true,
-    length: 36,
-    db: (prop) => dbRelation(prop),
-    relation: {
-        type: 'parent',
-        name: 'user',
-        kind: 'User',
-    },
-    default: undefined,
-    view: ['public'],
-    edit: ['owner'],
-},
-
-
String Props - -
-
{
-    type: "string",
-    name: "email",
-    required: true,
-    unique: true,
-    length: 256,
-    default: '',
-    db: (prop) => dbString(prop),
-    zod: (prop) => zodString(prop).email(),
-    view: [],
-    edit: ['owner'],
-},
-
-
-
Virtual Props - -
-

These are used to add a child relationship. They are virtual because they make no modification to the database table they represent.

-
{
-    type: "virtual",
-    name: 'userId',
-    required: false,
-    view: ['public'],
-    edit: [],
-    relation: {
-        type: 'child',
-        name: 'apikeys',
-        kind: 'APIKey',
-    },
-},
-
-

Generate Drizzle Tables from Ving Schema - -

-

Now that you’ve created or updated your schema, you can generate Drizzle tables from with this command:

-
./ving.mjs schema --tables
-
-
-

Note that you shouldn’t ever need to modify these table files directly. If you need to change them, update the ving schema and run the above command again.

-
-
-
- - - - \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8e96ee04..49fa4bec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,11 +15,9 @@ "bullmq": "^5.3.0", "citty": "^0.1.5", "date-fns": "^2.30.0", - "dotenv": "^16.4.1", "drizzle-orm": "^0.29.3", "dropzone": "^6.0.0-beta.2", "email-templates": "^11.1.1", - "glob": "^10.3.10", "ioredis": "^5.3.2", "keyv": "^4.5.4", "lodash": "^4.17.21", @@ -57,9 +55,184 @@ "nuxt-primevue": "^0.2.2", "nuxt-security": "^1.1.0", "typescript": "^4.9.5", + "vitepress": "^1.0.0-rc.44", "vitest": "^0.28.5" } }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", + "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", + "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", + "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", + "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "dev": true, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/cache-browser-local-storage": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.22.1.tgz", + "integrity": "sha512-Sw6IAmOCvvP6QNgY9j+Hv09mvkvEIDKjYW8ow0UDDAxSXy664RBNQk3i/0nt7gvceOJ6jGmOTimaZoY1THmU7g==", + "dev": true, + "dependencies": { + "@algolia/cache-common": "4.22.1" + } + }, + "node_modules/@algolia/cache-common": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.22.1.tgz", + "integrity": "sha512-TJMBKqZNKYB9TptRRjSUtevJeQVXRmg6rk9qgFKWvOy8jhCPdyNZV1nB3SKGufzvTVbomAukFR8guu/8NRKBTA==", + "dev": true + }, + "node_modules/@algolia/cache-in-memory": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.22.1.tgz", + "integrity": "sha512-ve+6Ac2LhwpufuWavM/aHjLoNz/Z/sYSgNIXsinGofWOysPilQZPUetqLj8vbvi+DHZZaYSEP9H5SRVXnpsNNw==", + "dev": true, + "dependencies": { + "@algolia/cache-common": "4.22.1" + } + }, + "node_modules/@algolia/client-account": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.22.1.tgz", + "integrity": "sha512-k8m+oegM2zlns/TwZyi4YgCtyToackkOpE+xCaKCYfBfDtdGOaVZCM5YvGPtK+HGaJMIN/DoTL8asbM3NzHonw==", + "dev": true, + "dependencies": { + "@algolia/client-common": "4.22.1", + "@algolia/client-search": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.22.1.tgz", + "integrity": "sha512-1ssi9pyxyQNN4a7Ji9R50nSdISIumMFDwKNuwZipB6TkauJ8J7ha/uO60sPJFqQyqvvI+px7RSNRQT3Zrvzieg==", + "dev": true, + "dependencies": { + "@algolia/client-common": "4.22.1", + "@algolia/client-search": "4.22.1", + "@algolia/requester-common": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "node_modules/@algolia/client-common": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.22.1.tgz", + "integrity": "sha512-IvaL5v9mZtm4k4QHbBGDmU3wa/mKokmqNBqPj0K7lcR8ZDKzUorhcGp/u8PkPC/e0zoHSTvRh7TRkGX3Lm7iOQ==", + "dev": true, + "dependencies": { + "@algolia/requester-common": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.22.1.tgz", + "integrity": "sha512-sl+/klQJ93+4yaqZ7ezOttMQ/nczly/3GmgZXJ1xmoewP5jmdP/X/nV5U7EHHH3hCUEHeN7X1nsIhGPVt9E1cQ==", + "dev": true, + "dependencies": { + "@algolia/client-common": "4.22.1", + "@algolia/requester-common": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "node_modules/@algolia/client-search": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.22.1.tgz", + "integrity": "sha512-yb05NA4tNaOgx3+rOxAmFztgMTtGBi97X7PC3jyNeGiwkAjOZc2QrdZBYyIdcDLoI09N0gjtpClcackoTN0gPA==", + "dev": true, + "dependencies": { + "@algolia/client-common": "4.22.1", + "@algolia/requester-common": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "node_modules/@algolia/logger-common": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.22.1.tgz", + "integrity": "sha512-OnTFymd2odHSO39r4DSWRFETkBufnY2iGUZNrMXpIhF5cmFE8pGoINNPzwg02QLBlGSaLqdKy0bM8S0GyqPLBg==", + "dev": true + }, + "node_modules/@algolia/logger-console": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.22.1.tgz", + "integrity": "sha512-O99rcqpVPKN1RlpgD6H3khUWylU24OXlzkavUAMy6QZd1776QAcauE3oP8CmD43nbaTjBexZj2nGsBH9Tc0FVA==", + "dev": true, + "dependencies": { + "@algolia/logger-common": "4.22.1" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.22.1.tgz", + "integrity": "sha512-dtQGYIg6MteqT1Uay3J/0NDqD+UciHy3QgRbk7bNddOJu+p3hzjTRYESqEnoX/DpEkaNYdRHUKNylsqMpgwaEw==", + "dev": true, + "dependencies": { + "@algolia/requester-common": "4.22.1" + } + }, + "node_modules/@algolia/requester-common": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.22.1.tgz", + "integrity": "sha512-dgvhSAtg2MJnR+BxrIFqlLtkLlVVhas9HgYKMk2Uxiy5m6/8HZBL40JVAMb2LovoPFs9I/EWIoFVjOrFwzn5Qg==", + "dev": true + }, + "node_modules/@algolia/requester-node-http": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.22.1.tgz", + "integrity": "sha512-JfmZ3MVFQkAU+zug8H3s8rZ6h0ahHZL/SpMaSasTCGYR5EEJsCc8SI5UZ6raPN2tjxa5bxS13BRpGSBUens7EA==", + "dev": true, + "dependencies": { + "@algolia/requester-common": "4.22.1" + } + }, + "node_modules/@algolia/transporter": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.22.1.tgz", + "integrity": "sha512-kzWgc2c9IdxMa3YqA6TN0NW5VrKYYW/BELIn7vnLyn+U/RFdZ4lxxt9/8yq3DKV5snvoDzzO4ClyejZRdV3lMQ==", + "dev": true, + "dependencies": { + "@algolia/cache-common": "4.22.1", + "@algolia/logger-common": "4.22.1", + "@algolia/requester-common": "4.22.1" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -1891,6 +2064,54 @@ "kuler": "^2.0.0" } }, + "node_modules/@docsearch/css": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.5.2.tgz", + "integrity": "sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==", + "dev": true + }, + "node_modules/@docsearch/js": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.5.2.tgz", + "integrity": "sha512-p1YFTCDflk8ieHgFJYfmyHBki1D61+U9idwrLh+GQQMrBSP3DLGKpy0XUJtPjAOPltcVbqsTjiPFfH7JImjUNg==", + "dev": true, + "dependencies": { + "@docsearch/react": "3.5.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.5.2.tgz", + "integrity": "sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-core": "1.9.3", + "@algolia/autocomplete-preset-algolia": "1.9.3", + "@docsearch/css": "3.5.2", + "algoliasearch": "^4.19.1" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, "node_modules/@drizzle-team/studio": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.39.tgz", @@ -2873,6 +3094,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -2889,6 +3111,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, "engines": { "node": ">=12" }, @@ -2900,6 +3123,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "engines": { "node": ">=12" }, @@ -2910,12 +3134,14 @@ "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -2932,6 +3158,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2946,6 +3173,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -4751,6 +4979,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "optional": true, "engines": { "node": ">=14" @@ -5401,6 +5630,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "android" @@ -5413,6 +5643,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "android" @@ -5425,6 +5656,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -5437,6 +5669,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -5449,6 +5682,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5461,6 +5695,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5473,6 +5708,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5485,6 +5721,7 @@ "cpu": [ "riscv64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5497,6 +5734,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5509,6 +5747,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5521,6 +5760,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -5533,6 +5773,7 @@ "cpu": [ "ia32" ], + "dev": true, "optional": true, "os": [ "win32" @@ -5545,6 +5786,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -5562,6 +5804,21 @@ "url": "https://ko-fi.com/killymxi" } }, + "node_modules/@shikijs/core": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.1.7.tgz", + "integrity": "sha512-gTYLUIuD1UbZp/11qozD3fWpUTuMqPSf3svDMMrL0UmlGU7D9dPw/V1FonwAorCUJBltaaESxq90jrSjQyGixg==", + "dev": true + }, + "node_modules/@shikijs/transformers": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.1.7.tgz", + "integrity": "sha512-lXz011ao4+rvweps/9h3CchBfzb1U5OtP5D51Tqc9lQYdLblWMIxQxH6Ybe1GeGINcEVM4goMyPrI0JvlIp4UQ==", + "dev": true, + "dependencies": { + "shiki": "1.1.7" + } + }, "node_modules/@sigstore/bundle": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.1.tgz", @@ -6437,15 +6694,13 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/@types/markdown-it": { "version": "13.0.7", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-13.0.7.tgz", "integrity": "sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==", "dev": true, - "peer": true, "dependencies": { "@types/linkify-it": "*", "@types/mdurl": "*" @@ -6455,8 +6710,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/@types/minimatch": { "version": "3.0.5", @@ -6513,6 +6767,12 @@ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "dev": true + }, "node_modules/@unhead/dom": { "version": "1.8.10", "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.8.10.tgz", @@ -6663,9 +6923,9 @@ } }, "node_modules/@vitejs/plugin-vue": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.3.tgz", - "integrity": "sha512-b8S5dVS40rgHdDrw+DQi/xOM9ed+kSRZzfm1T74bMmBDCd8XO87NKlFYInzCtwvtWwXZvo1QxE2OSspTATWrbA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz", + "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==", "dev": true, "engines": { "node": "^18.0.0 || >=20.0.0" @@ -6824,49 +7084,49 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.15.tgz", - "integrity": "sha512-XcJQVOaxTKCnth1vCxEChteGuwG6wqnUHxAm1DO3gCz0+uXKaJNx8/digSz4dLALCy8n2lKq24jSUs8segoqIw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz", + "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==", "dependencies": { - "@babel/parser": "^7.23.6", - "@vue/shared": "3.4.15", + "@babel/parser": "^7.23.9", + "@vue/shared": "3.4.21", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.15.tgz", - "integrity": "sha512-wox0aasVV74zoXyblarOM3AZQz/Z+OunYcIHe1OsGclCHt8RsRm04DObjefaI82u6XDzv+qGWZ24tIsRAIi5MQ==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz", + "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==", "dependencies": { - "@vue/compiler-core": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.15.tgz", - "integrity": "sha512-LCn5M6QpkpFsh3GQvs2mJUOAlBQcCco8D60Bcqmf3O3w5a+KWS5GvYbrrJBkgvL1BDnTp+e8q0lXCLgHhKguBA==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz", + "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==", "dependencies": { - "@babel/parser": "^7.23.6", - "@vue/compiler-core": "3.4.15", - "@vue/compiler-dom": "3.4.15", - "@vue/compiler-ssr": "3.4.15", - "@vue/shared": "3.4.15", + "@babel/parser": "^7.23.9", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21", "estree-walker": "^2.0.2", - "magic-string": "^0.30.5", - "postcss": "^8.4.33", + "magic-string": "^0.30.7", + "postcss": "^8.4.35", "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.15.tgz", - "integrity": "sha512-1jdeQyiGznr8gjFDadVmOJqZiLNSsMa5ZgqavkPZ8O2wjHv0tVuAEsw5hTdUoUW4232vpBbL/wJhzVW/JwY1Uw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz", + "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==", "dependencies": { - "@vue/compiler-dom": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/compiler-dom": "3.4.21", + "@vue/shared": "3.4.21" } }, "node_modules/@vue/devtools-api": { @@ -6874,49 +7134,260 @@ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==" }, + "node_modules/@vue/devtools-kit": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.0.15.tgz", + "integrity": "sha512-dT7OeCe1LUCIhHIb/yRR6Hn+XHh73r1o78onqCrxEKHdoZwBItiIeVnmJZPEUDFstIxfs+tJL231mySk3laTow==", + "dev": true, + "dependencies": { + "@vue/devtools-shared": "^7.0.15", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vue/devtools-kit/node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true + }, + "node_modules/@vue/devtools-shared": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.0.15.tgz", + "integrity": "sha512-fpfvMVvS7aDgO7x2JPFiTQ1MHcCc63/bE7yTgs278gMBybuO9b3hdiZ/k0Pw1rN+RefaU9yQiFA+5CCFc1D+6w==", + "dev": true, + "dependencies": { + "rfdc": "^1.3.1" + } + }, "node_modules/@vue/reactivity": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.15.tgz", - "integrity": "sha512-55yJh2bsff20K5O84MxSvXKPHHt17I2EomHznvFiJCAZpJTNW8IuLj1xZWMLELRhBK3kkFV/1ErZGHJfah7i7w==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz", + "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==", "dependencies": { - "@vue/shared": "3.4.15" + "@vue/shared": "3.4.21" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.15.tgz", - "integrity": "sha512-6E3by5m6v1AkW0McCeAyhHTw+3y17YCOKG0U0HDKDscV4Hs0kgNT5G+GCHak16jKgcCDHpI9xe5NKb8sdLCLdw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz", + "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==", "dependencies": { - "@vue/reactivity": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/reactivity": "3.4.21", + "@vue/shared": "3.4.21" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.15.tgz", - "integrity": "sha512-EVW8D6vfFVq3V/yDKNPBFkZKGMFSvZrUQmx196o/v2tHKdwWdiZjYUBS+0Ez3+ohRyF8Njwy/6FH5gYJ75liUw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz", + "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==", "dependencies": { - "@vue/runtime-core": "3.4.15", - "@vue/shared": "3.4.15", + "@vue/runtime-core": "3.4.21", + "@vue/shared": "3.4.21", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.15.tgz", - "integrity": "sha512-3HYzaidu9cHjrT+qGUuDhFYvF/j643bHC6uUN9BgM11DVy+pM6ATsG6uPBLnkwOgs7BpJABReLmpL3ZPAsUaqw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz", + "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==", "dependencies": { - "@vue/compiler-ssr": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21" }, "peerDependencies": { - "vue": "3.4.15" + "vue": "3.4.21" } }, "node_modules/@vue/shared": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz", - "integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==" + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", + "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==" + }, + "node_modules/@vueuse/core": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz", + "integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==", + "dev": true, + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "10.9.0", + "@vueuse/shared": "10.9.0", + "vue-demi": ">=0.14.7" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/integrations": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-10.9.0.tgz", + "integrity": "sha512-acK+A01AYdWSvL4BZmCoJAcyHJ6EqhmkQEXbQLwev1MY7NBnS+hcEMx/BzVoR9zKI+UqEPMD9u6PsyAuiTRT4Q==", + "dev": true, + "dependencies": { + "@vueuse/core": "10.9.0", + "@vueuse/shared": "10.9.0", + "vue-demi": ">=0.14.7" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "*", + "axios": "*", + "change-case": "*", + "drauu": "*", + "focus-trap": "*", + "fuse.js": "*", + "idb-keyval": "*", + "jwt-decode": "*", + "nprogress": "*", + "qrcode": "*", + "sortablejs": "*", + "universal-cookie": "*" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/integrations/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz", + "integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz", + "integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==", + "dev": true, + "dependencies": { + "vue-demi": ">=0.14.7" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } }, "node_modules/a-sync-waterfall": { "version": "1.0.1", @@ -6986,6 +7457,28 @@ "node": ">=0.8.0" } }, + "node_modules/algoliasearch": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.22.1.tgz", + "integrity": "sha512-jwydKFQJKIx9kIZ8Jm44SdpigFwRGPESaxZBaHSV0XWN2yBJAOT4mT7ppvlrpA4UGzz92pqFnVKr/kaZXrcreg==", + "dev": true, + "dependencies": { + "@algolia/cache-browser-local-storage": "4.22.1", + "@algolia/cache-common": "4.22.1", + "@algolia/cache-in-memory": "4.22.1", + "@algolia/client-account": "4.22.1", + "@algolia/client-analytics": "4.22.1", + "@algolia/client-common": "4.22.1", + "@algolia/client-personalization": "4.22.1", + "@algolia/client-search": "4.22.1", + "@algolia/logger-common": "4.22.1", + "@algolia/logger-console": "4.22.1", + "@algolia/requester-browser-xhr": "4.22.1", + "@algolia/requester-common": "4.22.1", + "@algolia/requester-node-http": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -7013,6 +7506,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -9271,7 +9765,8 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true }, "node_modules/ee-first": { "version": "1.1.1", @@ -9305,7 +9800,8 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/enabled": { "version": "2.0.0", @@ -10282,6 +10778,15 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, + "node_modules/focus-trap": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", + "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==", + "dev": true, + "dependencies": { + "tabbable": "^6.2.0" + } + }, "node_modules/follow-redirects": { "version": "1.15.5", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", @@ -10315,6 +10820,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -10637,6 +11143,7 @@ "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", @@ -10669,6 +11176,7 @@ "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -11475,6 +11983,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -11808,6 +12317,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -12319,9 +12829,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.6", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.6.tgz", - "integrity": "sha512-n62qCLbPjNjyo+owKtveQxZFZTBm+Ms6YoGD23Wew6Vw337PElFNifQpknPruVRQV57kVShPnLGo9vWxVhpPvA==", + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", + "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, @@ -12476,6 +12986,12 @@ "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-7.3.0.tgz", "integrity": "sha512-/K3BC0KIsO+WK2i94LkMPv3wslMrazrQhfi5We9fMbLlLjzoOSJWr7TAdupLlDWaJcWxwoNosBkhFDejiu5VDw==" }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true + }, "node_modules/markdown-it": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.0.0.tgz", @@ -12651,6 +13167,7 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -12778,6 +13295,12 @@ "node": ">=8" } }, + "node_modules/minisearch": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-6.3.0.tgz", + "integrity": "sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==", + "dev": true + }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -12801,6 +13324,12 @@ "node": ">=8" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -14290,6 +14819,7 @@ "version": "1.10.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, "dependencies": { "lru-cache": "^9.1.1 || ^10.0.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -14305,6 +14835,7 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, "engines": { "node": "14 || >=16.14" } @@ -14447,9 +14978,9 @@ } }, "node_modules/postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "funding": [ { "type": "opencollective", @@ -14916,6 +15447,16 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/preact": { + "version": "10.19.6", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.6.tgz", + "integrity": "sha512-gympg+T2Z1fG1unB8NH29yHJwnEaCH37Z32diPDku316OTnRPeMbiRV9kTrfZpocXjdfnWuFUl/Mj4BHaf6gnw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, "node_modules/pretty-bytes": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", @@ -15728,6 +16269,12 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -16136,6 +16683,13 @@ "resolved": "https://registry.npmjs.org/scule/-/scule-1.2.0.tgz", "integrity": "sha512-CRCmi5zHQnSoeCik9565PONMg0kfkvYmcSqrbOJY4txFfy1wvVULV4FDaiXhUblUgahdqz3F2NwHZ8i4eBTwUw==" }, + "node_modules/search-insights": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.13.0.tgz", + "integrity": "sha512-Orrsjf9trHHxFRuo9/rzm0KIWmgzE8RMlZMzuhZOJ01Rnz3D0YBAe+V6473t6/H6c7irs6Lt48brULAiRWb3Vw==", + "dev": true, + "peer": true + }, "node_modules/selderee": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", @@ -16325,6 +16879,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shiki": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.1.7.tgz", + "integrity": "sha512-9kUTMjZtcPH3i7vHunA6EraTPpPOITYTdA5uMrvsJRexktqP0s7P3s9HVK80b4pP42FRVe03D7fT3NmJv2yYhw==", + "dev": true, + "dependencies": { + "@shikijs/core": "1.1.7" + } + }, "node_modules/shimmer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", @@ -16604,6 +17167,15 @@ "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", "dev": true }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -16685,6 +17257,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -16699,6 +17272,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -16757,6 +17331,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -16769,6 +17344,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -16928,6 +17504,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "dev": true + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -18153,6 +18735,108 @@ "vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0" } }, + "node_modules/vitepress": { + "version": "1.0.0-rc.44", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.0.0-rc.44.tgz", + "integrity": "sha512-tO5taxGI7fSpBK1D8zrZTyJJERlyU9nnt0jHSt3fywfq3VKn977Hg0wUuTkEmwXlFYwuW26+6+3xorf4nD3XvA==", + "dev": true, + "dependencies": { + "@docsearch/css": "^3.5.2", + "@docsearch/js": "^3.5.2", + "@shikijs/core": "^1.1.5", + "@shikijs/transformers": "^1.1.5", + "@types/markdown-it": "^13.0.7", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/devtools-api": "^7.0.14", + "@vueuse/core": "^10.7.2", + "@vueuse/integrations": "^10.7.2", + "focus-trap": "^7.5.4", + "mark.js": "8.11.1", + "minisearch": "^6.3.0", + "shiki": "^1.1.5", + "vite": "^5.1.3", + "vue": "^3.4.19" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4.3.2", + "postcss": "^8.4.35" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vitepress/node_modules/@vue/devtools-api": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.0.15.tgz", + "integrity": "sha512-kgEYWosDyWpS1vFSuJNNWUnHkP+VkL3Y+9mw+rf7ex41SwbYL/WdC3KXqAtjiSrEs7r/FrHmUTh0BkINJPFkbA==", + "dev": true, + "dependencies": { + "@vue/devtools-kit": "^7.0.15" + } + }, + "node_modules/vitepress/node_modules/vite": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", + "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==", + "dev": true, + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, "node_modules/vitest": { "version": "0.28.5", "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.28.5.tgz", @@ -18830,15 +19514,15 @@ "dev": true }, "node_modules/vue": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.15.tgz", - "integrity": "sha512-jC0GH4KkWLWJOEQjOpkqU1bQsBwf4R1rsFtw5GQJbjHVKWDzO6P0nWWBTmjp1xSemAioDFj1jdaK1qa3DnMQoQ==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", + "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==", "dependencies": { - "@vue/compiler-dom": "3.4.15", - "@vue/compiler-sfc": "3.4.15", - "@vue/runtime-dom": "3.4.15", - "@vue/server-renderer": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/runtime-dom": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21" }, "peerDependencies": { "typescript": "*" @@ -19207,6 +19891,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -19393,6 +20078,170 @@ } }, "dependencies": { + "@algolia/autocomplete-core": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", + "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", + "dev": true, + "requires": { + "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", + "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", + "dev": true, + "requires": { + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "@algolia/autocomplete-preset-algolia": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", + "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", + "dev": true, + "requires": { + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "@algolia/autocomplete-shared": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", + "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "dev": true, + "requires": {} + }, + "@algolia/cache-browser-local-storage": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.22.1.tgz", + "integrity": "sha512-Sw6IAmOCvvP6QNgY9j+Hv09mvkvEIDKjYW8ow0UDDAxSXy664RBNQk3i/0nt7gvceOJ6jGmOTimaZoY1THmU7g==", + "dev": true, + "requires": { + "@algolia/cache-common": "4.22.1" + } + }, + "@algolia/cache-common": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.22.1.tgz", + "integrity": "sha512-TJMBKqZNKYB9TptRRjSUtevJeQVXRmg6rk9qgFKWvOy8jhCPdyNZV1nB3SKGufzvTVbomAukFR8guu/8NRKBTA==", + "dev": true + }, + "@algolia/cache-in-memory": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.22.1.tgz", + "integrity": "sha512-ve+6Ac2LhwpufuWavM/aHjLoNz/Z/sYSgNIXsinGofWOysPilQZPUetqLj8vbvi+DHZZaYSEP9H5SRVXnpsNNw==", + "dev": true, + "requires": { + "@algolia/cache-common": "4.22.1" + } + }, + "@algolia/client-account": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.22.1.tgz", + "integrity": "sha512-k8m+oegM2zlns/TwZyi4YgCtyToackkOpE+xCaKCYfBfDtdGOaVZCM5YvGPtK+HGaJMIN/DoTL8asbM3NzHonw==", + "dev": true, + "requires": { + "@algolia/client-common": "4.22.1", + "@algolia/client-search": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "@algolia/client-analytics": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.22.1.tgz", + "integrity": "sha512-1ssi9pyxyQNN4a7Ji9R50nSdISIumMFDwKNuwZipB6TkauJ8J7ha/uO60sPJFqQyqvvI+px7RSNRQT3Zrvzieg==", + "dev": true, + "requires": { + "@algolia/client-common": "4.22.1", + "@algolia/client-search": "4.22.1", + "@algolia/requester-common": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "@algolia/client-common": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.22.1.tgz", + "integrity": "sha512-IvaL5v9mZtm4k4QHbBGDmU3wa/mKokmqNBqPj0K7lcR8ZDKzUorhcGp/u8PkPC/e0zoHSTvRh7TRkGX3Lm7iOQ==", + "dev": true, + "requires": { + "@algolia/requester-common": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "@algolia/client-personalization": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.22.1.tgz", + "integrity": "sha512-sl+/klQJ93+4yaqZ7ezOttMQ/nczly/3GmgZXJ1xmoewP5jmdP/X/nV5U7EHHH3hCUEHeN7X1nsIhGPVt9E1cQ==", + "dev": true, + "requires": { + "@algolia/client-common": "4.22.1", + "@algolia/requester-common": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "@algolia/client-search": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.22.1.tgz", + "integrity": "sha512-yb05NA4tNaOgx3+rOxAmFztgMTtGBi97X7PC3jyNeGiwkAjOZc2QrdZBYyIdcDLoI09N0gjtpClcackoTN0gPA==", + "dev": true, + "requires": { + "@algolia/client-common": "4.22.1", + "@algolia/requester-common": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, + "@algolia/logger-common": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.22.1.tgz", + "integrity": "sha512-OnTFymd2odHSO39r4DSWRFETkBufnY2iGUZNrMXpIhF5cmFE8pGoINNPzwg02QLBlGSaLqdKy0bM8S0GyqPLBg==", + "dev": true + }, + "@algolia/logger-console": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.22.1.tgz", + "integrity": "sha512-O99rcqpVPKN1RlpgD6H3khUWylU24OXlzkavUAMy6QZd1776QAcauE3oP8CmD43nbaTjBexZj2nGsBH9Tc0FVA==", + "dev": true, + "requires": { + "@algolia/logger-common": "4.22.1" + } + }, + "@algolia/requester-browser-xhr": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.22.1.tgz", + "integrity": "sha512-dtQGYIg6MteqT1Uay3J/0NDqD+UciHy3QgRbk7bNddOJu+p3hzjTRYESqEnoX/DpEkaNYdRHUKNylsqMpgwaEw==", + "dev": true, + "requires": { + "@algolia/requester-common": "4.22.1" + } + }, + "@algolia/requester-common": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.22.1.tgz", + "integrity": "sha512-dgvhSAtg2MJnR+BxrIFqlLtkLlVVhas9HgYKMk2Uxiy5m6/8HZBL40JVAMb2LovoPFs9I/EWIoFVjOrFwzn5Qg==", + "dev": true + }, + "@algolia/requester-node-http": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.22.1.tgz", + "integrity": "sha512-JfmZ3MVFQkAU+zug8H3s8rZ6h0ahHZL/SpMaSasTCGYR5EEJsCc8SI5UZ6raPN2tjxa5bxS13BRpGSBUens7EA==", + "dev": true, + "requires": { + "@algolia/requester-common": "4.22.1" + } + }, + "@algolia/transporter": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.22.1.tgz", + "integrity": "sha512-kzWgc2c9IdxMa3YqA6TN0NW5VrKYYW/BELIn7vnLyn+U/RFdZ4lxxt9/8yq3DKV5snvoDzzO4ClyejZRdV3lMQ==", + "dev": true, + "requires": { + "@algolia/cache-common": "4.22.1", + "@algolia/logger-common": "4.22.1", + "@algolia/requester-common": "4.22.1" + } + }, "@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -20913,6 +21762,34 @@ "kuler": "^2.0.0" } }, + "@docsearch/css": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.5.2.tgz", + "integrity": "sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==", + "dev": true + }, + "@docsearch/js": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.5.2.tgz", + "integrity": "sha512-p1YFTCDflk8ieHgFJYfmyHBki1D61+U9idwrLh+GQQMrBSP3DLGKpy0XUJtPjAOPltcVbqsTjiPFfH7JImjUNg==", + "dev": true, + "requires": { + "@docsearch/react": "3.5.2", + "preact": "^10.0.0" + } + }, + "@docsearch/react": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.5.2.tgz", + "integrity": "sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==", + "dev": true, + "requires": { + "@algolia/autocomplete-core": "1.9.3", + "@algolia/autocomplete-preset-algolia": "1.9.3", + "@docsearch/css": "3.5.2", + "algoliasearch": "^4.19.1" + } + }, "@drizzle-team/studio": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.39.tgz", @@ -21440,6 +22317,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "requires": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -21452,22 +22330,26 @@ "ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true }, "ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "requires": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -21478,6 +22360,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "requires": { "ansi-regex": "^6.0.1" } @@ -21486,6 +22369,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "requires": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -22600,6 +23484,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "optional": true }, "@polka/url": { @@ -23057,78 +23942,91 @@ "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz", "integrity": "sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==", + "dev": true, "optional": true }, "@rollup/rollup-android-arm64": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz", "integrity": "sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==", + "dev": true, "optional": true }, "@rollup/rollup-darwin-arm64": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz", "integrity": "sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==", + "dev": true, "optional": true }, "@rollup/rollup-darwin-x64": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz", "integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==", + "dev": true, "optional": true }, "@rollup/rollup-linux-arm-gnueabihf": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz", "integrity": "sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==", + "dev": true, "optional": true }, "@rollup/rollup-linux-arm64-gnu": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz", "integrity": "sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==", + "dev": true, "optional": true }, "@rollup/rollup-linux-arm64-musl": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz", "integrity": "sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==", + "dev": true, "optional": true }, "@rollup/rollup-linux-riscv64-gnu": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz", "integrity": "sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==", + "dev": true, "optional": true }, "@rollup/rollup-linux-x64-gnu": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz", "integrity": "sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==", + "dev": true, "optional": true }, "@rollup/rollup-linux-x64-musl": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz", "integrity": "sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==", + "dev": true, "optional": true }, "@rollup/rollup-win32-arm64-msvc": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz", "integrity": "sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==", + "dev": true, "optional": true }, "@rollup/rollup-win32-ia32-msvc": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz", "integrity": "sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==", + "dev": true, "optional": true }, "@rollup/rollup-win32-x64-msvc": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz", "integrity": "sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==", + "dev": true, "optional": true }, "@selderee/plugin-htmlparser2": { @@ -23140,6 +24038,21 @@ "selderee": "^0.11.0" } }, + "@shikijs/core": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.1.7.tgz", + "integrity": "sha512-gTYLUIuD1UbZp/11qozD3fWpUTuMqPSf3svDMMrL0UmlGU7D9dPw/V1FonwAorCUJBltaaESxq90jrSjQyGixg==", + "dev": true + }, + "@shikijs/transformers": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.1.7.tgz", + "integrity": "sha512-lXz011ao4+rvweps/9h3CchBfzb1U5OtP5D51Tqc9lQYdLblWMIxQxH6Ybe1GeGINcEVM4goMyPrI0JvlIp4UQ==", + "dev": true, + "requires": { + "shiki": "1.1.7" + } + }, "@sigstore/bundle": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.1.tgz", @@ -23845,15 +24758,13 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", - "dev": true, - "peer": true + "dev": true }, "@types/markdown-it": { "version": "13.0.7", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-13.0.7.tgz", "integrity": "sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==", "dev": true, - "peer": true, "requires": { "@types/linkify-it": "*", "@types/mdurl": "*" @@ -23863,8 +24774,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", - "dev": true, - "peer": true + "dev": true }, "@types/minimatch": { "version": "3.0.5", @@ -23921,6 +24831,12 @@ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" }, + "@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "dev": true + }, "@unhead/dom": { "version": "1.8.10", "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.8.10.tgz", @@ -24037,9 +24953,9 @@ } }, "@vitejs/plugin-vue": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.3.tgz", - "integrity": "sha512-b8S5dVS40rgHdDrw+DQi/xOM9ed+kSRZzfm1T74bMmBDCd8XO87NKlFYInzCtwvtWwXZvo1QxE2OSspTATWrbA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz", + "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==", "dev": true, "requires": {} }, @@ -24159,49 +25075,49 @@ } }, "@vue/compiler-core": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.15.tgz", - "integrity": "sha512-XcJQVOaxTKCnth1vCxEChteGuwG6wqnUHxAm1DO3gCz0+uXKaJNx8/digSz4dLALCy8n2lKq24jSUs8segoqIw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz", + "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==", "requires": { - "@babel/parser": "^7.23.6", - "@vue/shared": "3.4.15", + "@babel/parser": "^7.23.9", + "@vue/shared": "3.4.21", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.0.2" } }, "@vue/compiler-dom": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.15.tgz", - "integrity": "sha512-wox0aasVV74zoXyblarOM3AZQz/Z+OunYcIHe1OsGclCHt8RsRm04DObjefaI82u6XDzv+qGWZ24tIsRAIi5MQ==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz", + "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==", "requires": { - "@vue/compiler-core": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" } }, "@vue/compiler-sfc": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.15.tgz", - "integrity": "sha512-LCn5M6QpkpFsh3GQvs2mJUOAlBQcCco8D60Bcqmf3O3w5a+KWS5GvYbrrJBkgvL1BDnTp+e8q0lXCLgHhKguBA==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz", + "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==", "requires": { - "@babel/parser": "^7.23.6", - "@vue/compiler-core": "3.4.15", - "@vue/compiler-dom": "3.4.15", - "@vue/compiler-ssr": "3.4.15", - "@vue/shared": "3.4.15", + "@babel/parser": "^7.23.9", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21", "estree-walker": "^2.0.2", - "magic-string": "^0.30.5", - "postcss": "^8.4.33", + "magic-string": "^0.30.7", + "postcss": "^8.4.35", "source-map-js": "^1.0.2" } }, "@vue/compiler-ssr": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.15.tgz", - "integrity": "sha512-1jdeQyiGznr8gjFDadVmOJqZiLNSsMa5ZgqavkPZ8O2wjHv0tVuAEsw5hTdUoUW4232vpBbL/wJhzVW/JwY1Uw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz", + "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==", "requires": { - "@vue/compiler-dom": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/compiler-dom": "3.4.21", + "@vue/shared": "3.4.21" } }, "@vue/devtools-api": { @@ -24209,46 +25125,141 @@ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==" }, + "@vue/devtools-kit": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.0.15.tgz", + "integrity": "sha512-dT7OeCe1LUCIhHIb/yRR6Hn+XHh73r1o78onqCrxEKHdoZwBItiIeVnmJZPEUDFstIxfs+tJL231mySk3laTow==", + "dev": true, + "requires": { + "@vue/devtools-shared": "^7.0.15", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1" + }, + "dependencies": { + "perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true + } + } + }, + "@vue/devtools-shared": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.0.15.tgz", + "integrity": "sha512-fpfvMVvS7aDgO7x2JPFiTQ1MHcCc63/bE7yTgs278gMBybuO9b3hdiZ/k0Pw1rN+RefaU9yQiFA+5CCFc1D+6w==", + "dev": true, + "requires": { + "rfdc": "^1.3.1" + } + }, "@vue/reactivity": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.15.tgz", - "integrity": "sha512-55yJh2bsff20K5O84MxSvXKPHHt17I2EomHznvFiJCAZpJTNW8IuLj1xZWMLELRhBK3kkFV/1ErZGHJfah7i7w==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz", + "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==", "requires": { - "@vue/shared": "3.4.15" + "@vue/shared": "3.4.21" } }, "@vue/runtime-core": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.15.tgz", - "integrity": "sha512-6E3by5m6v1AkW0McCeAyhHTw+3y17YCOKG0U0HDKDscV4Hs0kgNT5G+GCHak16jKgcCDHpI9xe5NKb8sdLCLdw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz", + "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==", "requires": { - "@vue/reactivity": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/reactivity": "3.4.21", + "@vue/shared": "3.4.21" } }, "@vue/runtime-dom": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.15.tgz", - "integrity": "sha512-EVW8D6vfFVq3V/yDKNPBFkZKGMFSvZrUQmx196o/v2tHKdwWdiZjYUBS+0Ez3+ohRyF8Njwy/6FH5gYJ75liUw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz", + "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==", "requires": { - "@vue/runtime-core": "3.4.15", - "@vue/shared": "3.4.15", + "@vue/runtime-core": "3.4.21", + "@vue/shared": "3.4.21", "csstype": "^3.1.3" } }, "@vue/server-renderer": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.15.tgz", - "integrity": "sha512-3HYzaidu9cHjrT+qGUuDhFYvF/j643bHC6uUN9BgM11DVy+pM6ATsG6uPBLnkwOgs7BpJABReLmpL3ZPAsUaqw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz", + "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==", "requires": { - "@vue/compiler-ssr": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21" } }, "@vue/shared": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz", - "integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==" + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", + "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==" + }, + "@vueuse/core": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz", + "integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==", + "dev": true, + "requires": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "10.9.0", + "@vueuse/shared": "10.9.0", + "vue-demi": ">=0.14.7" + }, + "dependencies": { + "vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "requires": {} + } + } + }, + "@vueuse/integrations": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-10.9.0.tgz", + "integrity": "sha512-acK+A01AYdWSvL4BZmCoJAcyHJ6EqhmkQEXbQLwev1MY7NBnS+hcEMx/BzVoR9zKI+UqEPMD9u6PsyAuiTRT4Q==", + "dev": true, + "requires": { + "@vueuse/core": "10.9.0", + "@vueuse/shared": "10.9.0", + "vue-demi": ">=0.14.7" + }, + "dependencies": { + "vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "requires": {} + } + } + }, + "@vueuse/metadata": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz", + "integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==", + "dev": true + }, + "@vueuse/shared": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz", + "integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==", + "dev": true, + "requires": { + "vue-demi": ">=0.14.7" + }, + "dependencies": { + "vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "requires": {} + } + } }, "a-sync-waterfall": { "version": "1.0.1", @@ -24300,6 +25311,28 @@ "estraverse": "^1.5.0" } }, + "algoliasearch": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.22.1.tgz", + "integrity": "sha512-jwydKFQJKIx9kIZ8Jm44SdpigFwRGPESaxZBaHSV0XWN2yBJAOT4mT7ppvlrpA4UGzz92pqFnVKr/kaZXrcreg==", + "dev": true, + "requires": { + "@algolia/cache-browser-local-storage": "4.22.1", + "@algolia/cache-common": "4.22.1", + "@algolia/cache-in-memory": "4.22.1", + "@algolia/client-account": "4.22.1", + "@algolia/client-analytics": "4.22.1", + "@algolia/client-common": "4.22.1", + "@algolia/client-personalization": "4.22.1", + "@algolia/client-search": "4.22.1", + "@algolia/logger-common": "4.22.1", + "@algolia/logger-console": "4.22.1", + "@algolia/requester-browser-xhr": "4.22.1", + "@algolia/requester-common": "4.22.1", + "@algolia/requester-node-http": "4.22.1", + "@algolia/transporter": "4.22.1" + } + }, "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -24317,7 +25350,8 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true }, "ansi-styles": { "version": "4.3.0", @@ -25904,7 +26938,8 @@ "eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true }, "ee-first": { "version": "1.1.1", @@ -25935,7 +26970,8 @@ "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "enabled": { "version": "2.0.0", @@ -26592,6 +27628,15 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, + "focus-trap": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", + "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==", + "dev": true, + "requires": { + "tabbable": "^6.2.0" + } + }, "follow-redirects": { "version": "1.15.5", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", @@ -26611,6 +27656,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, "requires": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -26843,6 +27889,7 @@ "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, "requires": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", @@ -26855,6 +27902,7 @@ "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, "requires": { "brace-expansion": "^2.0.1" } @@ -27438,7 +28486,8 @@ "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true }, "is-generator-function": { "version": "1.0.10", @@ -27658,6 +28707,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, "requires": { "@isaacs/cliui": "^8.0.2", "@pkgjs/parseargs": "^0.11.0" @@ -28071,9 +29121,9 @@ "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==" }, "magic-string": { - "version": "0.30.6", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.6.tgz", - "integrity": "sha512-n62qCLbPjNjyo+owKtveQxZFZTBm+Ms6YoGD23Wew6Vw337PElFNifQpknPruVRQV57kVShPnLGo9vWxVhpPvA==", + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", + "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", "requires": { "@jridgewell/sourcemap-codec": "^1.4.15" } @@ -28207,6 +29257,12 @@ "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-7.3.0.tgz", "integrity": "sha512-/K3BC0KIsO+WK2i94LkMPv3wslMrazrQhfi5We9fMbLlLjzoOSJWr7TAdupLlDWaJcWxwoNosBkhFDejiu5VDw==" }, + "mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true + }, "markdown-it": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.0.0.tgz", @@ -28339,7 +29395,8 @@ "minipass": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==" + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true }, "minipass-collect": { "version": "2.0.1", @@ -28443,6 +29500,12 @@ } } }, + "minisearch": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-6.3.0.tgz", + "integrity": "sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==", + "dev": true + }, "minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -28462,6 +29525,12 @@ } } }, + "mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -29555,6 +30624,7 @@ "version": "1.10.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, "requires": { "lru-cache": "^9.1.1 || ^10.0.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -29563,7 +30633,8 @@ "lru-cache": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==" + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true } } }, @@ -29645,9 +30716,9 @@ } }, "postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "requires": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", @@ -29927,6 +30998,12 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "preact": { + "version": "10.19.6", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.6.tgz", + "integrity": "sha512-gympg+T2Z1fG1unB8NH29yHJwnEaCH37Z32diPDku316OTnRPeMbiRV9kTrfZpocXjdfnWuFUl/Mj4BHaf6gnw==", + "dev": true + }, "pretty-bytes": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", @@ -30586,6 +31663,12 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, + "rfdc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -30870,6 +31953,13 @@ "resolved": "https://registry.npmjs.org/scule/-/scule-1.2.0.tgz", "integrity": "sha512-CRCmi5zHQnSoeCik9565PONMg0kfkvYmcSqrbOJY4txFfy1wvVULV4FDaiXhUblUgahdqz3F2NwHZ8i4eBTwUw==" }, + "search-insights": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.13.0.tgz", + "integrity": "sha512-Orrsjf9trHHxFRuo9/rzm0KIWmgzE8RMlZMzuhZOJ01Rnz3D0YBAe+V6473t6/H6c7irs6Lt48brULAiRWb3Vw==", + "dev": true, + "peer": true + }, "selderee": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", @@ -31027,6 +32117,15 @@ "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true }, + "shiki": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.1.7.tgz", + "integrity": "sha512-9kUTMjZtcPH3i7vHunA6EraTPpPOITYTdA5uMrvsJRexktqP0s7P3s9HVK80b4pP42FRVe03D7fT3NmJv2yYhw==", + "dev": true, + "requires": { + "@shikijs/core": "1.1.7" + } + }, "shimmer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", @@ -31243,6 +32342,12 @@ "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", "dev": true }, + "speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -31312,6 +32417,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -31322,6 +32428,7 @@ "version": "npm:string-width@4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -31365,6 +32472,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -31373,6 +32481,7 @@ "version": "npm:strip-ansi@6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -31481,6 +32590,12 @@ "integrity": "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==", "dev": true }, + "tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "dev": true + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -32323,6 +33438,52 @@ "magic-string": "^0.30.4" } }, + "vitepress": { + "version": "1.0.0-rc.44", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.0.0-rc.44.tgz", + "integrity": "sha512-tO5taxGI7fSpBK1D8zrZTyJJERlyU9nnt0jHSt3fywfq3VKn977Hg0wUuTkEmwXlFYwuW26+6+3xorf4nD3XvA==", + "dev": true, + "requires": { + "@docsearch/css": "^3.5.2", + "@docsearch/js": "^3.5.2", + "@shikijs/core": "^1.1.5", + "@shikijs/transformers": "^1.1.5", + "@types/markdown-it": "^13.0.7", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/devtools-api": "^7.0.14", + "@vueuse/core": "^10.7.2", + "@vueuse/integrations": "^10.7.2", + "focus-trap": "^7.5.4", + "mark.js": "8.11.1", + "minisearch": "^6.3.0", + "shiki": "^1.1.5", + "vite": "^5.1.3", + "vue": "^3.4.19" + }, + "dependencies": { + "@vue/devtools-api": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.0.15.tgz", + "integrity": "sha512-kgEYWosDyWpS1vFSuJNNWUnHkP+VkL3Y+9mw+rf7ex41SwbYL/WdC3KXqAtjiSrEs7r/FrHmUTh0BkINJPFkbA==", + "dev": true, + "requires": { + "@vue/devtools-kit": "^7.0.15" + } + }, + "vite": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", + "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==", + "dev": true, + "requires": { + "esbuild": "^0.19.3", + "fsevents": "~2.3.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + } + } + } + }, "vitest": { "version": "0.28.5", "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.28.5.tgz", @@ -32680,15 +33841,15 @@ "dev": true }, "vue": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.15.tgz", - "integrity": "sha512-jC0GH4KkWLWJOEQjOpkqU1bQsBwf4R1rsFtw5GQJbjHVKWDzO6P0nWWBTmjp1xSemAioDFj1jdaK1qa3DnMQoQ==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", + "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==", "requires": { - "@vue/compiler-dom": "3.4.15", - "@vue/compiler-sfc": "3.4.15", - "@vue/runtime-dom": "3.4.15", - "@vue/server-renderer": "3.4.15", - "@vue/shared": "3.4.15" + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/runtime-dom": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21" } }, "vue-bundle-renderer": { @@ -32963,6 +34124,7 @@ "version": "npm:wrap-ansi@7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", diff --git a/package.json b/package.json index 34b8e02c..c8d5f0a3 100644 --- a/package.json +++ b/package.json @@ -1,68 +1,69 @@ { - "name": "ving", - "description": "An opinionated web services starter for Nuxt3 that provides REST and per-field privileges out of the box.", - "private": true, - "type": "module", - "imports": { - "#ving/*": "./ving/*" - }, - "scripts": { - "build": "nuxt build", - "dev": "nuxt dev --host", - "generate": "nuxt generate", - "preview": "nuxt preview", - "postinstall": "nuxt prepare", - "tests": "export $(cat .env | xargs)&& vitest" - }, - "devDependencies": { - "@featherscloud/pinion": "^0.5.3", - "@marknotton/env": "^2.0.0", - "@pulumi/aws": "^6.0.0", - "@pulumi/awsx": "^2.0.2", - "@pulumi/command": "^0.9.2", - "@pulumi/pulumi": "^3.0.0", - "axios": "^1.6.7", - "drizzle-kit": "^0.20.13", - "env-file-rw": "^1.0.0", - "markdown-it": "^14.0.0", - "markdown-it-anchor": "^8.6.7", - "markdown-it-toc-done-right": "^4.2.0", - "nuxt": "^3.10.0", - "nuxt-icon": "^0.3.3", - "nuxt-primevue": "^0.2.2", - "nuxt-security": "^1.1.0", - "typescript": "^4.9.5", - "vitest": "^0.28.5" - }, - "dependencies": { - "@aws-sdk/client-s3": "^3.504.0", - "@aws-sdk/s3-request-presigner": "^3.504.0", - "@keyv/redis": "^2.8.4", - "@pinia/nuxt": "^0.4.11", - "bcryptjs": "^2.4.3", - "bullmq": "^5.3.0", - "citty": "^0.1.5", - "date-fns": "^2.30.0", - "drizzle-orm": "^0.29.3", - "dropzone": "^6.0.0-beta.2", - "email-templates": "^11.1.1", - "ioredis": "^5.3.2", - "keyv": "^4.5.4", - "lodash": "^4.17.21", - "mysql2": "^2.3.3", - "nodemailer": "^6.9.8", - "nunjucks": "^3.2.4", - "perfect-debounce": "^0.1.3", - "pinia": "^2.1.7", - "primeflex": "^3.3.1", - "primeicons": "^6.0.1", - "primevue": "^3.47.2", - "sanitize-filename": "^1.6.3", - "scule": "^1.2.0", - "ua-parser-js": "^1.0.37", - "uuid": "^9.0.1", - "winston": "^3.11.0", - "winston-daily-rotate-file": "^5.0.0", - "zod": "^3.22.4" - } + "name": "ving", + "description": "An opinionated web services starter for Nuxt3 that provides REST and per-field privileges out of the box.", + "private": true, + "type": "module", + "imports": { + "#ving/*": "./ving/*" + }, + "scripts": { + "build": "nuxt build", + "dev": "nuxt dev --host", + "generate": "nuxt generate", + "preview": "nuxt preview", + "postinstall": "nuxt prepare", + "tests": "export $(cat .env | xargs)&& vitest", + "docs:dev": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" + }, + "devDependencies": { + "@featherscloud/pinion": "^0.5.3", + "@marknotton/env": "^2.0.0", + "@pulumi/aws": "^6.0.0", + "@pulumi/awsx": "^2.0.2", + "@pulumi/command": "^0.9.2", + "@pulumi/pulumi": "^3.0.0", + "axios": "^1.6.7", + "drizzle-kit": "^0.20.13", + "env-file-rw": "^1.0.0", + "nuxt": "^3.10.0", + "nuxt-icon": "^0.3.3", + "nuxt-primevue": "^0.2.2", + "nuxt-security": "^1.1.0", + "typescript": "^4.9.5", + "vitepress": "^1.0.0-rc.44", + "vitest": "^0.28.5" + }, + "dependencies": { + "@aws-sdk/client-s3": "^3.504.0", + "@aws-sdk/s3-request-presigner": "^3.504.0", + "@keyv/redis": "^2.8.4", + "@pinia/nuxt": "^0.4.11", + "bcryptjs": "^2.4.3", + "bullmq": "^5.3.0", + "citty": "^0.1.5", + "date-fns": "^2.30.0", + "drizzle-orm": "^0.29.3", + "dropzone": "^6.0.0-beta.2", + "email-templates": "^11.1.1", + "ioredis": "^5.3.2", + "keyv": "^4.5.4", + "lodash": "^4.17.21", + "mysql2": "^2.3.3", + "nodemailer": "^6.9.8", + "nunjucks": "^3.2.4", + "perfect-debounce": "^0.1.3", + "pinia": "^2.1.7", + "primeflex": "^3.3.1", + "primeicons": "^6.0.1", + "primevue": "^3.47.2", + "sanitize-filename": "^1.6.3", + "scule": "^1.2.0", + "ua-parser-js": "^1.0.37", + "uuid": "^9.0.1", + "winston": "^3.11.0", + "winston-daily-rotate-file": "^5.0.0", + "zod": "^3.22.4" + } } \ No newline at end of file diff --git a/ving/docs/build.mjs b/ving/docs/build.mjs deleted file mode 100755 index 9e496b89..00000000 --- a/ving/docs/build.mjs +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env node -import markdownit from 'markdown-it'; -import markdownitanchor from 'markdown-it-anchor'; -import markdownittocdoneright from 'markdown-it-toc-done-right'; -import fs from 'fs'; - -const sourcePath = "content/"; -const destinationPath = "../../docs/"; - -const md = markdownit({ - html: true, - linkify: true, - typographer: true, - xhtmlOut: true, -}).use(markdownitanchor, { - permalink: markdownitanchor.permalink.linkInsideHeader({ - symbol: ` - - `, - placement: 'after' - }) -}) - .use(markdownittocdoneright); - -const wrapperTemplate = (name, content, nav) => ` - - - - - ${name} - - - - - - - -
-
-
-
Ving Docs
- ${nav} -
-
- ${content} -
- - - -`; - -if (fs.existsSync(destinationPath)) - fs.rmSync(destinationPath, { recursive: true, force: true }); -fs.mkdirSync(destinationPath); - -const navMd = fs.readFileSync(`nav.md`, { encoding: 'utf8' }); -const navHtml = md.render(navMd); - -fs.readdir(sourcePath, (err, files) => { - files.forEach(file => { - fs.readFile(`${sourcePath}${file}`, { encoding: 'utf8' }, (err, contents) => { - const html = md.render(`
- -[[toc]] - -
- -${contents} - -
`); - const htmlFile = `${destinationPath}${file.replace(/\.md$/g, '.html')}`; - fs.writeFile(htmlFile, wrapperTemplate(file, html, navHtml), { encoding: 'utf8' }, (err) => { - if (err) - console.error(err); - }) - }); - }); -}); - -console.log('done'); diff --git a/ving/docs/content/index.md b/ving/docs/content/index.md deleted file mode 100644 index 8e7d8355..00000000 --- a/ving/docs/content/index.md +++ /dev/null @@ -1,28 +0,0 @@ -# About Ving - -Ving is a Web and REST code generation tool and services framework. It has a heavy focus on a strong and predictable backend, while having a flexible front end. It's feature's include: - - - Automatic code generation for all sub-systems - - Platform agnostic REST interface - - Per field privileges for view and edit - - Full session based auth system - - AWS S3 based secure upload system - - Per user message bus streamed via Server Sent Events - - API key and privilege system with access to make requests on behalf of other users - - A useful set of custom made client components and composables - - A full user interface for user management - - Email subsystem - -Ving is written entirely in Javascript using [Nuxt 3](http://nuxt.com), [Vue 3](http://vuejs.org), [PrimeVue](https://primevue.org), [PrimeFlex](https://www.primefaces.org/primeflex/) and [Drizzle](https://github.com/drizzle-team/drizzle-orm). - - -## How Ving is Constructed -Everything starts with the [Ving Schema](ving-schema.html), which defines tables in a database, along with fields, privileges, and other properties. From there everything is automatically generated, but still modifyable by you. Ving will generate [database schemas and migrations](drizzle.html), [server-side Javascript APIs](ving-record.html), [REST APIs](rest.html), [Web UIs](ui.html), [email templates](email.html), and more. - - -## Why Rest? -You might be wondering why REST in a world with tRPC and GraphQL. It's because REST is language agnostic, and very simple to understand. It's still the best data presentation layer when you have an API you want the general public to consume. And Ving is all about being fast to implement and easy to maintain. When you want simplcity, you do not want GraphQL or Typescript as there's nothing uncomplicated about either. - - -## Get the Code -You can [visit the GitHub repository](https://github.com/plainblack/ving) to get the source code and start using it. \ No newline at end of file diff --git a/ving/docs/nav.md b/ving/docs/nav.md deleted file mode 100644 index 2a970f19..00000000 --- a/ving/docs/nav.md +++ /dev/null @@ -1,26 +0,0 @@ -Basics - - [About](index.html) - - [Installation](installation.html) - - [Error Codes](error-codes.html) - - [Change Log](change-log.html) - -Subsystems - - [Cache](cache.html) - - [CLI](cli.html) - - [Database](drizzle.html) - - [Email](email.html) - - [Env Vars](env.html) - - [Logging](logging.html) - - [Message Bus](messagebus.html) - - [Pulumi](pulumi.html) - - [Rest](rest.html) - - [UI](ui.html) - - [Ving Record](ving-record.html) - - [Ving Schema](ving-schema.html) - -Rest APIs - - [API Key](APIKey.html) - - [S3File](S3File.html) - - [Session](Session.html) - - [Test](Test.html) - - [User](User.html) \ No newline at end of file