+
+ {getCorrectTitle(currentStepItem, 1)}
+
+
+
-
+
{#if prevStep}
@@ -135,6 +193,7 @@
-
{#each tutorials as tutorial, index}
{@const isCurrentStep = currentStep === tutorial.step}
+ {@const absoluteToc = toc.slice(1)}
-
{index === 0 ? 'Introduction' : tutorial.title}
- {#if isCurrentStep && toc.length}
+ {#if isCurrentStep && absoluteToc.length}
-
- {#each toc.slice(1) as parent}
+ {#each absoluteToc as parent, innerIndex}
-
+ scrollToItem(parent, innerIndex)}
class="web-references-menu-link is-inner"
class:tutorial-scroll-indicator={parent.selected}
class:is-selected={parent.selected}
@@ -208,4 +269,49 @@
background: unset;
padding-inline-start: unset;
}
+
+ .u-margin-block-start-16 {
+ margin-block-start: 1rem;
+ }
+
+ .u-margin-inline-start-32 {
+ margin-inline-start: 2rem;
+ }
+
+ .web-references-menu-item:has(.is-selected)::before {
+ /* maintains the distance correctly for the children items */
+ inset-inline-start: -3.55rem;
+ }
+
+ /* Static slider: default slider for each selected link */
+ .web-references-menu-list > .web-references-menu-item > .is-selected::before {
+ content: ' ';
+ position: absolute;
+ inset-block-start: 0;
+ block-size: 1.375rem;
+ inline-size: 0.0625rem;
+ inset-inline-start: -1.3125rem;
+ background-color: hsl(var(--p-references-menu-link-color-text));
+ }
+
+ /* Hide static slider if any child menu item is selected */
+ .web-references-menu-list
+ > .web-references-menu-item:has(.web-references-menu-list .is-selected)
+ > .is-selected::before {
+ background-color: transparent;
+ }
+
+ /* Transparent slider for selected child items because we use parent level */
+ .web-references-menu-list
+ > .web-references-menu-item
+ > .web-references-menu-list
+ > .web-references-menu-item
+ > .is-selected::before {
+ content: '';
+ background-color: transparent;
+ }
+
+ :global(.tutorial-heading h2) {
+ margin-bottom: unset;
+ }
diff --git a/src/markdoc/nodes/Fence.svelte b/src/markdoc/nodes/Fence.svelte
index 28b0a234b0..dec92c5997 100644
--- a/src/markdoc/nodes/Fence.svelte
+++ b/src/markdoc/nodes/Fence.svelte
@@ -7,6 +7,7 @@
import { copy } from '$lib/utils/copy';
import type { CodeContext } from '../tags/MultiCode.svelte';
import { melt } from '@melt-ui/svelte';
+ import { isInTutorialDocs } from '$lib/layouts/Docs.svelte';
export let content: string;
export let toCopy: string | undefined = undefined;
@@ -15,6 +16,7 @@
export let withLineNumbers = true;
export let badge: string | null = null;
+ const inTutorialDocs = isInTutorialDocs();
const insideMultiCode = hasContext('multi-code');
const selected = insideMultiCode ? getContext
('multi-code').selected : null; @@ -61,7 +63,11 @@ {@html result} {/if} {:else} - + {#if badgeValue} @@ -98,3 +104,9 @@diff --git a/src/partials/auth-security.md b/src/partials/auth-security.md index 5bd9363eeb..3b18080d12 100644 --- a/src/partials/auth-security.md +++ b/src/partials/auth-security.md @@ -1,3 +1,31 @@ +# Persistence {% #persistence %} + +Appwrite handles the persistence of the session in a consistent way across SDKs. After authenticating with an SDK, the SDK will persist the session so that the user will not need to log in again the next time they open the app. The mechanism for persistence depends on the SDK. + +{% info title="Best Practice" %} +Only keep user sessions active as long as needed and maintain exactly **one** instance of the Client SDK in your app to avoid conflicting session data. +{% /info %} + +| {% width=70 %} | Framework {% width=120 %} | Storage method | +| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------: | :--------------------------------------------------------------------------------------------------: | +| {% only_dark %}{% icon_image src="/images/platforms/dark/javascript.svg" alt="Javascript logo" size="m" /%}{% /only_dark %}{% only_light %}{% icon_image src="/images/platforms/javascript.svg" alt="Javascript logo" size="m" /%}{% /only_light %} | Web | Uses a secure session cookie and falls back to local storage when a session cookie is not available. | +| {% only_dark %}{% icon_image src="/images/platforms/dark/flutter.svg" alt="Javascript logo" size="m" /%}{% /only_dark %}{% only_light %}{% icon_image src="/images/platforms/flutter.svg" alt="Javascript logo" size="m" /%}{% /only_light %} | Flutter | Uses a session cookie stored in Application Documents through the **path_provider** package. | +| {% only_dark %}{% icon_image src="/images/platforms/dark/apple.svg" alt="Javascript logo" size="m" /%}{% /only_dark %}{% only_light %}{% icon_image src="/images/platforms/apple.svg" alt="Javascript logo" size="m" /%}{% /only_light %} | Apple | Uses a session cookie stored in **UserDefaults**. | +| {% only_dark %}{% icon_image src="/images/platforms/dark/android.svg" alt="Javascript logo" size="m" /%}{% /only_dark %}{% only_light %}{% icon_image src="/images/platforms/android.svg" alt="Javascript logo" size="m" /%}{% /only_light %} | Android | Uses a session cookie stored in **SharedPreferences**. | + +# Session limits {% #session-limits %} + +In Appwrite versions 1.2 and above, you can limit the number of active sessions created per user to prevent the accumulation of unused but active sessions. New sessions created by the same user past the session limit delete the oldest session. + +You can change the session limit in the **Security** tab of the Auth Service in your Appwrite Console. The default session limit is 10 with a maximum configurable limit of 100. + +# Permissions {% #permissions %} + +Security is very important to protect users' data and privacy. +Appwrite uses a [permissions model](/docs/advanced/platform/permissions) coupled with user sessions to ensure users need correct permissions to access resources. +With all Appwrite services, including databases and storage, access is granted at the collection, bucket, document, or file level. +These permissions are enforced for client SDKs and server SDKs when using JWT, but are ignored when using a server SDK with an API key. + # Password history {% #password-history %} Password history prevents users from reusing recent passwords. This protects user accounts from security risks by enforcing a new password every time it's changed. @@ -37,10 +65,16 @@ To toggle session alerts, navigate to **Auth** > **Security** > **Session alerts # Memberships privacy {% #memberships-privacy %} -In certain use cases, your app may not need to share members’ personal information with others. You can safeguard privacy by marking specific membership details as private. To configure this setting, navigate to **Auth** > **Security** > **Memberships privacy** +In certain use cases, your app may not need to share members' personal information with others. You can safeguard privacy by marking specific membership details as private. To configure this setting, navigate to **Auth** > **Security** > **Memberships privacy** These details can be made private: -- `userName` - The member's name -- `userEmail` - The member's email address -- `mfa` - Whether the member has enabled multi-factor authentication +- `userName` - The member's name +- `userEmail` - The member's email address +- `mfa` - Whether the member has enabled multi-factor authentication + +# Mock phone numbers {% #mock-phone-numbers %} + +Creating and using mock phone numbers allows users to test SMS authentication without needing an actual phone number. This can be useful for testing edge cases where a user doesn't have a phone number but needs to sign in to your application using SMS. + +To create a mock phone number, navigate to **Auth** > **Security** > Mock Phone Numbers. After defining a mock phone number, you need to define a specific OTP code that will be used for SMS sign-in instead of the SMS secret code sent to a real phone number. diff --git a/src/routes/community/+page.server.ts b/src/routes/community/+page.server.ts index 4dfb93f577..5d4769801d 100644 --- a/src/routes/community/+page.server.ts +++ b/src/routes/community/+page.server.ts @@ -44,8 +44,8 @@ export const load = async () => { // return { issues: mockIssues }; // } - // fetch issues from github, appwrite/appwrite repo - const response = await fetch('https://api.github.com/repos/appwrite/appwrite/issues'); + // fetch issues from GitHub, appwrite/appwrite repo + const response = await fetch('https://api.github.com/repos/appwrite/appwrite/issues?state=open'); const issues = await response.json(); if (issues?.message?.includes('API rate limit exceeded')) { return { issues: mockIssues }; diff --git a/src/routes/docs/advanced/security/authentication/+page.markdoc b/src/routes/docs/advanced/security/authentication/+page.markdoc index e6e90772b7..7e6d18320f 100644 --- a/src/routes/docs/advanced/security/authentication/+page.markdoc +++ b/src/routes/docs/advanced/security/authentication/+page.markdoc @@ -4,7 +4,7 @@ title: Authentication description: Learn how Appwrite protects your passwords and helps users pick better passwords. --- -Appwrite helps you implement secure authentication in your applications by using advanced password hashing to protect passwords in storage. +Appwrite helps you implement secure authentication in your applications by using password hashing to protect passwords in storage. Appwrite also provides tools to help users pick better passwords, making them harder to break. {% partial file="auth-security.md" /%} \ No newline at end of file diff --git a/src/routes/docs/products/auth/security/+page.markdoc b/src/routes/docs/products/auth/security/+page.markdoc index ccbea04675..f0094f37b3 100644 --- a/src/routes/docs/products/auth/security/+page.markdoc +++ b/src/routes/docs/products/auth/security/+page.markdoc @@ -6,37 +6,4 @@ description: Prioritize security in your applications with Appwrite. Discover be Appwrite provides many security features to keep both your Appwrite project and your user's information secure. -# Persistence {% #persistence %} - -Appwrite handles the persistence of the session in a consistent way across SDKs. After authenticating with an SDK, the SDK will persist the session so that the user will not need to log in again the next time they open the app. The mechanism for persistence depends on the SDK. - -{% info title="Best Practice" %} -Only keep user sessions active as long as needed and maintain exactly **one** instance of the Client SDK in your app to avoid conflicting session data. -{% /info %} - -| {% width=70 %} | Framework {% width=120 %} | Storage method | -|:----------------------------------------------------------------------------------------------------:|:---:|:----------------------------------------------------------------------------------------------------------------------:| -| {% only_dark %}{% icon_image src="/images/platforms/dark/javascript.svg" alt="Javascript logo" size="m" /%}{% /only_dark %}{% only_light %}{% icon_image src="/images/platforms/javascript.svg" alt="Javascript logo" size="m" /%}{% /only_light %} | Web | Uses a secure session cookie and falls back to local storage when a session cookie is not available. | -| {% only_dark %}{% icon_image src="/images/platforms/dark/flutter.svg" alt="Javascript logo" size="m" /%}{% /only_dark %}{% only_light %}{% icon_image src="/images/platforms/flutter.svg" alt="Javascript logo" size="m" /%}{% /only_light %} | Flutter | Uses a session cookie stored in Application Documents through the **path_provider** package. | -| {% only_dark %}{% icon_image src="/images/platforms/dark/apple.svg" alt="Javascript logo" size="m" /%}{% /only_dark %}{% only_light %}{% icon_image src="/images/platforms/apple.svg" alt="Javascript logo" size="m" /%}{% /only_light %} | Apple | Uses a session cookie stored in **UserDefaults**. | -| {% only_dark %}{% icon_image src="/images/platforms/dark/android.svg" alt="Javascript logo" size="m" /%}{% /only_dark %}{% only_light %}{% icon_image src="/images/platforms/android.svg" alt="Javascript logo" size="m" /%}{% /only_light %} | Android | Uses a session cookie stored in **SharedPreferences**. | - -# Session limits {% #session-limits %} -In Appwrite versions 1.2 and above, you can limit the number of active sessions created per user to prevent the accumulation of unused but active sessions. New sessions created by the same user past the session limit delete the oldest session. - -You can change the session limit in the **Security** tab of the Auth Service in your Appwrite Console. The default session limit is 10 with a maximum configurable limit of 100. - -# Permissions {% #permissions %} - -Security is very important to protect users' data and privacy. -Appwrite uses a [permissions model](/docs/advanced/platform/permissions) coupled with user sessions to ensure users need correct permissions to access resources. -With all Appwrite services, including databases and storage, access is granted at the collection, bucket, document, or file level. -These permissions are enforced for client SDKs and server SDKs when using JWT, but are ignored when using a server SDK with an API key. - {% partial file="auth-security.md" /%} - -# Mock phone numbers {% #mock-phone-numbers %} - -Creating and using mock phone numbers allows users to test SMS authentication without needing an actual phone number. This can be useful for testing edge cases where a user doesn't have a phone number but needs to sign in to your application using SMS. - -To create a mock phone number, navigate to **Auth** > **Security** > Mock Phone Numbers. After defining a mock phone number, you need to define a specific OTP code that will be used for SMS sign-in instead of the SMS secret code sent to a real phone number. diff --git a/src/routes/products/storage/ProjectCard.svelte b/src/routes/products/storage/ProjectCard.svelte index ead1c524ff..661f684ecc 100644 --- a/src/routes/products/storage/ProjectCard.svelte +++ b/src/routes/products/storage/ProjectCard.svelte @@ -18,6 +18,7 @@ export let image: $$Props['image']; export let href: $$Props['href']; +
-
+ scrollToItem(parent, innerIndex)}
class="web-references-menu-link is-inner"
class:tutorial-scroll-indicator={parent.selected}
class:is-selected={parent.selected}
@@ -208,4 +269,49 @@
background: unset;
padding-inline-start: unset;
}
+
+ .u-margin-block-start-16 {
+ margin-block-start: 1rem;
+ }
+
+ .u-margin-inline-start-32 {
+ margin-inline-start: 2rem;
+ }
+
+ .web-references-menu-item:has(.is-selected)::before {
+ /* maintains the distance correctly for the children items */
+ inset-inline-start: -3.55rem;
+ }
+
+ /* Static slider: default slider for each selected link */
+ .web-references-menu-list > .web-references-menu-item > .is-selected::before {
+ content: ' ';
+ position: absolute;
+ inset-block-start: 0;
+ block-size: 1.375rem;
+ inline-size: 0.0625rem;
+ inset-inline-start: -1.3125rem;
+ background-color: hsl(var(--p-references-menu-link-color-text));
+ }
+
+ /* Hide static slider if any child menu item is selected */
+ .web-references-menu-list
+ > .web-references-menu-item:has(.web-references-menu-list .is-selected)
+ > .is-selected::before {
+ background-color: transparent;
+ }
+
+ /* Transparent slider for selected child items because we use parent level */
+ .web-references-menu-list
+ > .web-references-menu-item
+ > .web-references-menu-list
+ > .web-references-menu-item
+ > .is-selected::before {
+ content: '';
+ background-color: transparent;
+ }
+
+ :global(.tutorial-heading h2) {
+ margin-bottom: unset;
+ }
diff --git a/src/markdoc/nodes/Fence.svelte b/src/markdoc/nodes/Fence.svelte
index 28b0a234b0..dec92c5997 100644
--- a/src/markdoc/nodes/Fence.svelte
+++ b/src/markdoc/nodes/Fence.svelte
@@ -7,6 +7,7 @@
import { copy } from '$lib/utils/copy';
import type { CodeContext } from '../tags/MultiCode.svelte';
import { melt } from '@melt-ui/svelte';
+ import { isInTutorialDocs } from '$lib/layouts/Docs.svelte';
export let content: string;
export let toCopy: string | undefined = undefined;
@@ -15,6 +16,7 @@
export let withLineNumbers = true;
export let badge: string | null = null;
+ const inTutorialDocs = isInTutorialDocs();
const insideMultiCode = hasContext('multi-code');
const selected = insideMultiCode ? getContext