diff --git a/.github/workflows/docker-server-build.yaml b/.github/workflows/docker-server-build.yaml index 7e477eae1..09d2a5ec8 100644 --- a/.github/workflows/docker-server-build.yaml +++ b/.github/workflows/docker-server-build.yaml @@ -13,7 +13,7 @@ concurrency: jobs: build-server: name: Docker Build and Push Server - runs-on: ubuntu-latest + runs-on: ubicloud-standard-8 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/docs/public/stack-auth-cli-template.py b/docs/public/stack-auth-cli-template.py new file mode 100644 index 000000000..126d19b35 --- /dev/null +++ b/docs/public/stack-auth-cli-template.py @@ -0,0 +1,56 @@ +import time +import requests +import webbrowser +import urllib.parse + +def prompt_cli_login( + *, + base_url: str = "https://api.stack-auth.com", + app_url: str, + project_id: str, + publishable_client_key: str, +): + if not app_url: + raise Exception("app_url is required and must be set to the URL of the app you're authenticating with") + if not project_id: + raise Exception("project_id is required") + if not publishable_client_key: + raise Exception("publishable_client_key is required") + + def post(endpoint, json): + return requests.request( + 'POST', + f'{base_url}{endpoint}', + headers={ + 'Content-Type': 'application/json', + 'x-stack-project-id': project_id, + 'x-stack-access-type': 'client', + 'x-stack-publishable-client-key': publishable_client_key, + }, + json=json, + ) + + # Step 1: Initiate the CLI auth process + init = post('/api/v1/auth/cli', { + 'expires_in_millis': 10 * 60 * 1000, + }) + if init.status_code != 200: + raise Exception(f"Failed to initiate CLI auth: {init.status_code} {init.text}") + polling_code = init.json()['polling_code'] + login_code = init.json()['login_code'] + + # Step 2: Open the browser for the user to authenticate + url = f'{app_url}/handler/cli-auth-confirm?login_code={urllib.parse.quote(login_code)}' + print(f"Opening browser to authenticate. If it doesn't open automatically, please visit:\n{url}") + webbrowser.open(url) + + # Step 3: Retrieve the token + while True: + status = post('/api/v1/auth/cli/poll', { + 'polling_code': polling_code, + }) + if status.status_code != 200 and status.status_code != 201: + raise Exception(f"Failed to get CLI auth status: {status.status_code} {status.text}") + if status.json()['status'] == 'success': + return status.json()['refresh_token'] + time.sleep(2) diff --git a/docs/src/components/layouts/api/api-sidebar.tsx b/docs/src/components/layouts/api/api-sidebar.tsx index d2c21fddd..4d06a6f22 100644 --- a/docs/src/components/layouts/api/api-sidebar.tsx +++ b/docs/src/components/layouts/api/api-sidebar.tsx @@ -247,56 +247,74 @@ export function ApiSidebarContent({ pages = [] }: { pages?: PageData[] }) { Overview - {Object.entries(organizedPages).map(([sectionKey, section]) => ( -
- {section.title} + {Object.entries(organizedPages) + .filter(([sectionKey]) => sectionKey !== 'admin') // Hide admin section from sidebar + .sort(([aKey], [bKey]) => { + // Define the desired order of sections + const sectionOrder = ['client', 'server', 'webhooks']; + const aIndex = sectionOrder.indexOf(aKey); + const bIndex = sectionOrder.indexOf(bKey); + // If both sections are in our defined order, sort by that order + if (aIndex !== -1 && bIndex !== -1) { + return aIndex - bIndex; + } + // If only one is in our defined order, prioritize it + if (aIndex !== -1) return -1; + if (bIndex !== -1) return 1; + // If neither is in our defined order, sort alphabetically + //eslint-disable-next-line + return aKey.localeCompare(bKey); + }) + .map(([sectionKey, section]) => ( +
+ {section.title} - {/* Section-level pages */} - {section.pages.length > 0 && section.pages.map((page: PageData) => ( - - {page.data.title || formatTitle(page.slugs[page.slugs.length - 1])} - - ))} + {/* Section-level pages */} + {section.pages.length > 0 && section.pages.map((page: PageData) => ( + + {page.data.title || formatTitle(page.slugs[page.slugs.length - 1])} + + ))} - {/* Grouped pages */} - {Object.entries(section.groups).map(([groupKey, group]: [string, OrganizedGroup]) => ( - - {group.pages.map((page: PageData) => { - const method = getHttpMethod(page); - const title = page.data.title || formatTitle(page.slugs[page.slugs.length - 1]); + {/* Grouped pages */} + {Object.entries(section.groups).map(([groupKey, group]: [string, OrganizedGroup]) => ( + + {group.pages.map((page: PageData) => { + const method = getHttpMethod(page); + const title = page.data.title || formatTitle(page.slugs[page.slugs.length - 1]); + + // Special handling for webhooks (EVENT badge instead of HTTP method) + if (sectionKey === 'webhooks') { + return ( + +
+ + EVENT + + {title} +
+
+ ); + } - // Special handling for webhooks (EVENT badge instead of HTTP method) - if (sectionKey === 'webhooks') { return ( - -
- - EVENT - - {title} -
+ + {title} ); - } - - return ( - - {title} - - ); - })} -
- ))} -
- ))} + })} + + ))} +
+ ))} diff --git a/docs/templates/others/cli-authentication.mdx b/docs/templates/others/cli-authentication.mdx index a671df140..e95632713 100644 --- a/docs/templates/others/cli-authentication.mdx +++ b/docs/templates/others/cli-authentication.mdx @@ -5,7 +5,7 @@ description: How to authenticate a command line application using Stack Auth If you're building a command line application that runs in a terminal, you can use Stack Auth to let your users log in to their accounts. -To do so, we provide a Python template that you can use as a starting point. [Download it here](https://github.com/stack-auth/stack-auth/tree/main/docs/examples/stack_auth_cli_template.py) and copy it into your project, for example: +To do so, we provide a Python template that you can use as a starting point. [Download it here](https://github.com/stack-auth/stack-auth/tree/main/docs/public/stack_auth_cli_template.py) and copy it into your project, for example: ```py └─ my-python-app