mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
Merge branch 'dev' into s3
This commit is contained in:
commit
f5d66561dc
99
CLAUDE.md
99
CLAUDE.md
@ -1,31 +1,76 @@
|
||||
# Development Guidelines for Stack Auth
|
||||
# CLAUDE.md
|
||||
|
||||
## Build/Test/Lint Commands
|
||||
- Build: `pnpm build` (all), `pnpm build:packages` (packages only), `pnpm build:backend` (backend)
|
||||
- Lint: `pnpm lint` (zero warnings allowed)
|
||||
- Typecheck: `pnpm typecheck`
|
||||
- Test: `pnpm test` (all), `pnpm test:unit` (unit tests), `pnpm test:e2e` (e2e tests)
|
||||
- Run single test: `pnpm test path/to/test.test.ts` or `pnpm test -t "test name pattern"`
|
||||
- Start dependencies: `pnpm start-deps` (DB, services), `pnpm stop-deps` (shutdown)
|
||||
- Dev mode: `pnpm dev` (all services) or `pnpm dev:basic` (backend+dashboard)
|
||||
- Prisma CLI: `pnpm prisma` (use instead of the `prisma` command)
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Coding Guidelines
|
||||
- TypeScript with strict types, prefer `type` over `interface`
|
||||
- Avoid casting to `any`; Prefer making changes to the API so that `any` casts are unnecessary to access a property or method
|
||||
- 2-space indentation, spaces in braces, semicolons required
|
||||
- Return promises with `return await`, no floating promises
|
||||
- Proper error handling for async code with try/catch
|
||||
- Use helper functions: `yupXyz()` for validation, `getPublicEnvVar()` for env
|
||||
- Switch cases must use blocks
|
||||
- React Server Components preferred where applicable
|
||||
- No direct 'use' imports from React (use React.use instead)
|
||||
- Follow existing file structure and naming patterns
|
||||
## Development Commands
|
||||
|
||||
## Testing Guidelines
|
||||
- Import test utilities from `/apps/e2e/test/helpers.ts`
|
||||
- Prefer inline snapshot testing with `expect(response).toMatchInlineSnapshot(...)`
|
||||
### Essential Commands
|
||||
- **Install dependencies**: `pnpm install`
|
||||
- **Build packages**: `pnpm build:packages`
|
||||
- **Generate code**: `pnpm codegen`
|
||||
- **Start dependencies**: `pnpm restart-deps` (resets & restarts Docker containers for DB, Inbucket, etc. Usually already called by the user)
|
||||
- **Run development**: `pnpm dev` (starts all services on different ports. Usually already started by the user in the background)
|
||||
- **Run minimal dev**: `pnpm dev:basic` (only backend and dashboard for resource-limited systems)
|
||||
- **Run tests**: `pnpm test --no-watch` (uses Vitest). You can filter with `pnpm test --no-watch <file-filters>`
|
||||
- **Lint code**: `pnpm lint`
|
||||
- **Type check**: `pnpm typecheck`
|
||||
|
||||
## Monorepo Structure
|
||||
Managed with Turbo and pnpm workspaces. Core packages in `packages/`, apps in `apps/`.
|
||||
`packages/stack` is generated and will not be committed into the repository; change the files in `packages/template` instead.
|
||||
### Testing
|
||||
- **Run all tests**: `pnpm test --no-watch`
|
||||
- **Run some tests**: `pnpm test --no-watch <file-filters>`
|
||||
|
||||
### Database Commands
|
||||
- **Generate migration**: `pnpm db:migration-gen`
|
||||
- **Reset database** (rarely used): `pnpm db:reset`
|
||||
- **Seed database** (rarely used): `pnpm db:seed`
|
||||
- **Initialize database** (rarely used): `pnpm db:init`
|
||||
- **Run migrations** (rarely used): `pnpm db:migrate`
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
Stack Auth is a monorepo using Turbo for build orchestration. The main components are:
|
||||
|
||||
### Apps (`/apps`)
|
||||
- **backend** (`/apps/backend`): Next.js API backend running on port 8102
|
||||
- Main API routes in `/apps/backend/src/app/api/latest`
|
||||
- Database models using Prisma
|
||||
- **dashboard** (`/apps/dashboard`): Admin dashboard on port 8101
|
||||
- **dev-launchpad**: Development portal on port 8100
|
||||
- **e2e**: End-to-end tests
|
||||
|
||||
### Packages (`/packages`)
|
||||
- **stack** (`/packages/stack`): Main Next.js SDK
|
||||
- **stack-shared** (`/packages/stack-shared`): Shared utilities and types
|
||||
- **stack-ui** (`/packages/stack-ui`): UI components
|
||||
- **react** (`/packages/react`): React SDK
|
||||
- **js** (`/packages/js`): JavaScript SDK
|
||||
|
||||
### Key Technologies
|
||||
- **Framework**: Next.js (with App Router)
|
||||
- **Database**: PostgreSQL with Prisma ORM
|
||||
- **Testing**: Vitest
|
||||
- **Package Manager**: pnpm with workspaces
|
||||
- **Build Tool**: Turbo
|
||||
- **TypeScript**: Used throughout
|
||||
- **Styling**: Tailwind CSS
|
||||
|
||||
### API Structure
|
||||
The API follows a RESTful design with routes organized by resource type:
|
||||
- Auth endpoints: `/api/latest/auth/*`
|
||||
- User management: `/api/latest/users/*`
|
||||
- Team management: `/api/latest/teams/*`
|
||||
- OAuth providers: `/api/latest/oauth-providers/*`
|
||||
|
||||
### Development Ports
|
||||
- 8100: Dev launchpad
|
||||
- 8101: Dashboard
|
||||
- 8102: Backend API
|
||||
- 8103: Demo app
|
||||
- 8104: Documentation
|
||||
- 8105: Inbucket (email testing)
|
||||
- 8106: Prisma Studio
|
||||
|
||||
## Important Notes
|
||||
- Environment variables are pre-configured in `.env.development` files
|
||||
- Code generation (`pnpm codegen`) must be run after schema changes
|
||||
- The project uses a custom route handler system in the backend for consistent API responses
|
||||
|
||||
@ -1,5 +1,13 @@
|
||||
# @stackframe/stack-backend
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Various changes
|
||||
- Updated dependencies
|
||||
- @stackframe/stack-shared@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/stack-backend",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "rimraf src/generated && rimraf .next && rimraf node_modules",
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { overrideEnvironmentConfigOverride } from "@/lib/config";
|
||||
import { getActiveEmailTheme, renderEmailWithTemplate } from "@/lib/email-rendering";
|
||||
import { globalPrismaClient } from "@/prisma-client";
|
||||
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
|
||||
import { KnownErrors } from "@stackframe/stack-shared/dist/known-errors";
|
||||
import { adaptSchema, templateThemeIdSchema, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
||||
@ -55,7 +54,6 @@ export const PATCH = createSmartRouteHandler({
|
||||
}
|
||||
|
||||
await overrideEnvironmentConfigOverride({
|
||||
tx: globalPrismaClient,
|
||||
projectId: tenancy.project.id,
|
||||
branchId: tenancy.branchId,
|
||||
environmentConfigOverrideOverride: {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { overrideEnvironmentConfigOverride } from "@/lib/config";
|
||||
import { globalPrismaClient } from "@/prisma-client";
|
||||
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
|
||||
import { adaptSchema, templateThemeIdSchema, yupArray, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
||||
import { filterUndefined, typedEntries } from "@stackframe/stack-shared/dist/utils/objects";
|
||||
@ -94,7 +93,6 @@ export const POST = createSmartRouteHandler({
|
||||
`;
|
||||
|
||||
await overrideEnvironmentConfigOverride({
|
||||
tx: globalPrismaClient,
|
||||
projectId: tenancy.project.id,
|
||||
branchId: tenancy.branchId,
|
||||
environmentConfigOverrideOverride: {
|
||||
|
||||
@ -83,7 +83,6 @@ export const PATCH = createSmartRouteHandler({
|
||||
throw new KnownErrors.EmailRenderingError(result.error);
|
||||
}
|
||||
await overrideEnvironmentConfigOverride({
|
||||
tx: globalPrismaClient,
|
||||
projectId: tenancy.project.id,
|
||||
branchId: tenancy.branchId,
|
||||
environmentConfigOverrideOverride: {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { overrideEnvironmentConfigOverride } from "@/lib/config";
|
||||
import { globalPrismaClient } from "@/prisma-client";
|
||||
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
|
||||
import { LightEmailTheme } from "@stackframe/stack-shared/dist/helpers/emails";
|
||||
import { adaptSchema, yupArray, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
||||
@ -30,7 +29,6 @@ export const POST = createSmartRouteHandler({
|
||||
async handler({ body, auth: { tenancy } }) {
|
||||
const id = generateUuid();
|
||||
await overrideEnvironmentConfigOverride({
|
||||
tx: globalPrismaClient,
|
||||
projectId: tenancy.project.id,
|
||||
branchId: tenancy.branchId,
|
||||
environmentConfigOverrideOverride: {
|
||||
|
||||
@ -32,7 +32,13 @@ export const adminUserProjectsCrudHandlers = createLazyProxy(() => createCrudHan
|
||||
const project = await createOrUpdateProject({
|
||||
ownerIds: userIds,
|
||||
type: 'create',
|
||||
data,
|
||||
data: {
|
||||
...data,
|
||||
config: {
|
||||
allow_localhost: true,
|
||||
...data.config,
|
||||
},
|
||||
},
|
||||
});
|
||||
const tenancy = await getSoleTenancyFromProjectBranch(project.id, DEFAULT_BRANCH_ID);
|
||||
return {
|
||||
|
||||
@ -199,18 +199,17 @@ export function getOrganizationConfigOverrideQuery(options: OrganizationOptions)
|
||||
export async function overrideProjectConfigOverride(options: {
|
||||
projectId: string,
|
||||
projectConfigOverrideOverride: ProjectConfigOverrideOverride,
|
||||
tx: PrismaClientTransaction,
|
||||
}): Promise<void> {
|
||||
// set project config override on our own DB
|
||||
|
||||
// TODO put this in a serializable transaction (or a single SQL query) to prevent race conditions
|
||||
const oldConfig = await rawQuery(options.tx, getProjectConfigOverrideQuery(options));
|
||||
const oldConfig = await rawQuery(globalPrismaClient, getProjectConfigOverrideQuery(options));
|
||||
const newConfig = override(
|
||||
oldConfig,
|
||||
options.projectConfigOverrideOverride,
|
||||
);
|
||||
await assertNoConfigOverrideErrors(projectConfigSchema, newConfig);
|
||||
await options.tx.project.update({
|
||||
await globalPrismaClient.project.update({
|
||||
where: {
|
||||
id: options.projectId,
|
||||
},
|
||||
@ -224,7 +223,6 @@ export function overrideBranchConfigOverride(options: {
|
||||
projectId: string,
|
||||
branchId: string,
|
||||
branchConfigOverrideOverride: BranchConfigOverrideOverride,
|
||||
tx: PrismaClientTransaction,
|
||||
}): Promise<void> {
|
||||
// update config.json if on local emulator
|
||||
// throw error otherwise
|
||||
@ -235,18 +233,17 @@ export async function overrideEnvironmentConfigOverride(options: {
|
||||
projectId: string,
|
||||
branchId: string,
|
||||
environmentConfigOverrideOverride: EnvironmentConfigOverrideOverride,
|
||||
tx: PrismaClientTransaction,
|
||||
}): Promise<void> {
|
||||
// save environment config override on DB
|
||||
|
||||
// TODO put this in a serializable transaction (or a single SQL query) to prevent race conditions
|
||||
const oldConfig = await rawQuery(options.tx, getEnvironmentConfigOverrideQuery(options));
|
||||
const oldConfig = await rawQuery(globalPrismaClient, getEnvironmentConfigOverrideQuery(options));
|
||||
const newConfig = override(
|
||||
oldConfig,
|
||||
options.environmentConfigOverrideOverride,
|
||||
);
|
||||
await assertNoConfigOverrideErrors(environmentConfigSchema, newConfig);
|
||||
await options.tx.environmentConfigOverride.upsert({
|
||||
await globalPrismaClient.environmentConfigOverride.upsert({
|
||||
where: {
|
||||
projectId_branchId: {
|
||||
projectId: options.projectId,
|
||||
@ -269,7 +266,6 @@ export function overrideOrganizationConfigOverride(options: {
|
||||
branchId: string,
|
||||
organizationId: string | null,
|
||||
organizationConfigOverrideOverride: OrganizationConfigOverrideOverride,
|
||||
tx: PrismaClientTransaction,
|
||||
}): Promise<void> {
|
||||
// save organization config override on DB (either our own, or the source of truth one)
|
||||
throw new StackAssertionError('Not implemented');
|
||||
|
||||
@ -17,7 +17,12 @@ export class TracedFreestyleSandboxes {
|
||||
'freestyle.nodeModules.count': options?.nodeModules ? Object.keys(options.nodeModules).length.toString() : '0',
|
||||
}
|
||||
}, async () => {
|
||||
return await this.freestyle.executeScript(script, options);
|
||||
try {
|
||||
return await this.freestyle.executeScript(script, options);
|
||||
} catch (error) {
|
||||
captureError("freestyle.executeScript", error);
|
||||
throw new StackAssertionError("Error executing script with Freestyle! " + errorToNiceString(error), { cause: error });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +213,6 @@ export async function createPermissionDefinition(
|
||||
await overrideEnvironmentConfigOverride({
|
||||
branchId: options.tenancy.branchId,
|
||||
projectId: options.tenancy.project.id,
|
||||
tx: globalTx,
|
||||
environmentConfigOverrideOverride: {
|
||||
"rbac.permissions": {
|
||||
...oldConfig.rbac.permissions,
|
||||
@ -272,7 +271,6 @@ export async function updatePermissionDefinition(
|
||||
await overrideEnvironmentConfigOverride({
|
||||
branchId: options.tenancy.branchId,
|
||||
projectId: options.tenancy.project.id,
|
||||
tx: globalTx,
|
||||
environmentConfigOverrideOverride: {
|
||||
"rbac.permissions": {
|
||||
...typedFromEntries(
|
||||
@ -347,7 +345,6 @@ export async function deletePermissionDefinition(
|
||||
await overrideEnvironmentConfigOverride({
|
||||
branchId: options.tenancy.branchId,
|
||||
projectId: options.tenancy.project.id,
|
||||
tx: globalTx,
|
||||
environmentConfigOverrideOverride: {
|
||||
"rbac.permissions": typedFromEntries(
|
||||
typedEntries(oldConfig.rbac.permissions)
|
||||
|
||||
@ -122,114 +122,112 @@ export async function createOrUpdateProject(
|
||||
branchId = options.branchId;
|
||||
}
|
||||
|
||||
const translateDefaultPermissions = (permissions: { id: string }[] | undefined) => {
|
||||
return permissions ? typedFromEntries(permissions.map((permission) => [permission.id, true])) : undefined;
|
||||
};
|
||||
return [project.id, branchId];
|
||||
});
|
||||
|
||||
await overrideProjectConfigOverride({
|
||||
tx,
|
||||
projectId: project.id,
|
||||
projectConfigOverrideOverride: {
|
||||
sourceOfTruth: options.sourceOfTruth || (JSON.parse(getEnvVariable("STACK_OVERRIDE_SOURCE_OF_TRUTH", "null")) ?? undefined),
|
||||
},
|
||||
});
|
||||
// Update project config override
|
||||
await overrideProjectConfigOverride({
|
||||
projectId: projectId,
|
||||
projectConfigOverrideOverride: {
|
||||
sourceOfTruth: options.sourceOfTruth || (JSON.parse(getEnvVariable("STACK_OVERRIDE_SOURCE_OF_TRUTH", "null")) ?? undefined),
|
||||
},
|
||||
});
|
||||
|
||||
const dataOptions = options.data.config || {};
|
||||
const configOverrideOverride: EnvironmentConfigOverrideOverride = filterUndefined({
|
||||
// ======================= auth =======================
|
||||
'auth.allowSignUp': dataOptions.sign_up_enabled,
|
||||
'auth.password.allowSignIn': dataOptions.credential_enabled,
|
||||
'auth.otp.allowSignIn': dataOptions.magic_link_enabled,
|
||||
'auth.passkey.allowSignIn': dataOptions.passkey_enabled,
|
||||
'auth.oauth.accountMergeStrategy': dataOptions.oauth_account_merge_strategy,
|
||||
'auth.oauth.providers': dataOptions.oauth_providers ? typedFromEntries(dataOptions.oauth_providers
|
||||
.map((provider) => {
|
||||
return [
|
||||
provider.id,
|
||||
{
|
||||
type: provider.id,
|
||||
isShared: provider.type === "shared",
|
||||
clientId: provider.client_id,
|
||||
clientSecret: provider.client_secret,
|
||||
facebookConfigId: provider.facebook_config_id,
|
||||
microsoftTenantId: provider.microsoft_tenant_id,
|
||||
allowSignIn: true,
|
||||
allowConnectedAccounts: true,
|
||||
} satisfies OrganizationRenderedConfig['auth']['oauth']['providers'][string]
|
||||
];
|
||||
})) : undefined,
|
||||
// ======================= users =======================
|
||||
'users.allowClientUserDeletion': dataOptions.client_user_deletion_enabled,
|
||||
// ======================= teams =======================
|
||||
'teams.allowClientTeamCreation': dataOptions.client_team_creation_enabled,
|
||||
'teams.createPersonalTeamOnSignUp': dataOptions.create_team_on_sign_up,
|
||||
// ======================= domains =======================
|
||||
'domains.allowLocalhost': dataOptions.allow_localhost ?? true,
|
||||
'domains.trustedDomains': dataOptions.domains ? typedFromEntries(dataOptions.domains.map((domain) => {
|
||||
// Update environment config override
|
||||
const translateDefaultPermissions = (permissions: { id: string }[] | undefined) => {
|
||||
return permissions ? typedFromEntries(permissions.map((permission) => [permission.id, true])) : undefined;
|
||||
};
|
||||
const dataOptions = options.data.config || {};
|
||||
const configOverrideOverride: EnvironmentConfigOverrideOverride = filterUndefined({
|
||||
// ======================= auth =======================
|
||||
'auth.allowSignUp': dataOptions.sign_up_enabled,
|
||||
'auth.password.allowSignIn': dataOptions.credential_enabled,
|
||||
'auth.otp.allowSignIn': dataOptions.magic_link_enabled,
|
||||
'auth.passkey.allowSignIn': dataOptions.passkey_enabled,
|
||||
'auth.oauth.accountMergeStrategy': dataOptions.oauth_account_merge_strategy,
|
||||
'auth.oauth.providers': dataOptions.oauth_providers ? typedFromEntries(dataOptions.oauth_providers
|
||||
.map((provider) => {
|
||||
return [
|
||||
generateUuid(),
|
||||
provider.id,
|
||||
{
|
||||
baseUrl: domain.domain,
|
||||
handlerPath: domain.handler_path,
|
||||
} satisfies OrganizationRenderedConfig['domains']['trustedDomains'][string],
|
||||
type: provider.id,
|
||||
isShared: provider.type === "shared",
|
||||
clientId: provider.client_id,
|
||||
clientSecret: provider.client_secret,
|
||||
facebookConfigId: provider.facebook_config_id,
|
||||
microsoftTenantId: provider.microsoft_tenant_id,
|
||||
allowSignIn: true,
|
||||
allowConnectedAccounts: true,
|
||||
} satisfies OrganizationRenderedConfig['auth']['oauth']['providers'][string]
|
||||
];
|
||||
})) : undefined,
|
||||
// ======================= api keys =======================
|
||||
'apiKeys.enabled.user': dataOptions.allow_user_api_keys,
|
||||
'apiKeys.enabled.team': dataOptions.allow_team_api_keys,
|
||||
// ======================= emails =======================
|
||||
'emails.server': dataOptions.email_config ? {
|
||||
isShared: dataOptions.email_config.type === 'shared',
|
||||
host: dataOptions.email_config.host,
|
||||
port: dataOptions.email_config.port,
|
||||
username: dataOptions.email_config.username,
|
||||
password: dataOptions.email_config.password,
|
||||
senderName: dataOptions.email_config.sender_name,
|
||||
senderEmail: dataOptions.email_config.sender_email,
|
||||
} satisfies OrganizationRenderedConfig['emails']['server'] : undefined,
|
||||
'emails.selectedThemeId': dataOptions.email_theme,
|
||||
// ======================= rbac =======================
|
||||
'rbac.defaultPermissions.teamMember': translateDefaultPermissions(dataOptions.team_member_default_permissions),
|
||||
'rbac.defaultPermissions.teamCreator': translateDefaultPermissions(dataOptions.team_creator_default_permissions),
|
||||
'rbac.defaultPermissions.signUp': translateDefaultPermissions(dataOptions.user_default_permissions),
|
||||
});
|
||||
// ======================= users =======================
|
||||
'users.allowClientUserDeletion': dataOptions.client_user_deletion_enabled,
|
||||
// ======================= teams =======================
|
||||
'teams.allowClientTeamCreation': dataOptions.client_team_creation_enabled,
|
||||
'teams.createPersonalTeamOnSignUp': dataOptions.create_team_on_sign_up,
|
||||
// ======================= domains =======================
|
||||
'domains.allowLocalhost': dataOptions.allow_localhost,
|
||||
'domains.trustedDomains': dataOptions.domains ? typedFromEntries(dataOptions.domains.map((domain) => {
|
||||
return [
|
||||
generateUuid(),
|
||||
{
|
||||
baseUrl: domain.domain,
|
||||
handlerPath: domain.handler_path,
|
||||
} satisfies OrganizationRenderedConfig['domains']['trustedDomains'][string],
|
||||
];
|
||||
})) : undefined,
|
||||
// ======================= api keys =======================
|
||||
'apiKeys.enabled.user': dataOptions.allow_user_api_keys,
|
||||
'apiKeys.enabled.team': dataOptions.allow_team_api_keys,
|
||||
// ======================= emails =======================
|
||||
'emails.server': dataOptions.email_config ? {
|
||||
isShared: dataOptions.email_config.type === 'shared',
|
||||
host: dataOptions.email_config.host,
|
||||
port: dataOptions.email_config.port,
|
||||
username: dataOptions.email_config.username,
|
||||
password: dataOptions.email_config.password,
|
||||
senderName: dataOptions.email_config.sender_name,
|
||||
senderEmail: dataOptions.email_config.sender_email,
|
||||
} satisfies OrganizationRenderedConfig['emails']['server'] : undefined,
|
||||
'emails.selectedThemeId': dataOptions.email_theme,
|
||||
// ======================= rbac =======================
|
||||
'rbac.defaultPermissions.teamMember': translateDefaultPermissions(dataOptions.team_member_default_permissions),
|
||||
'rbac.defaultPermissions.teamCreator': translateDefaultPermissions(dataOptions.team_creator_default_permissions),
|
||||
'rbac.defaultPermissions.signUp': translateDefaultPermissions(dataOptions.user_default_permissions),
|
||||
});
|
||||
|
||||
if (options.type === "create") {
|
||||
configOverrideOverride['rbac.permissions.team_member'] ??= {
|
||||
description: "Default permission for team members",
|
||||
scope: "team",
|
||||
containedPermissionIds: {
|
||||
'$read_members': true,
|
||||
'$invite_members': true,
|
||||
},
|
||||
} satisfies OrganizationRenderedConfig['rbac']['permissions'][string];
|
||||
configOverrideOverride['rbac.permissions.team_admin'] ??= {
|
||||
description: "Default permission for team admins",
|
||||
scope: "team",
|
||||
containedPermissionIds: {
|
||||
'$update_team': true,
|
||||
'$delete_team': true,
|
||||
'$read_members': true,
|
||||
'$remove_members': true,
|
||||
'$invite_members': true,
|
||||
'$manage_api_keys': true,
|
||||
},
|
||||
} satisfies OrganizationRenderedConfig['rbac']['permissions'][string];
|
||||
if (options.type === "create") {
|
||||
configOverrideOverride['rbac.permissions.team_member'] ??= {
|
||||
description: "Default permission for team members",
|
||||
scope: "team",
|
||||
containedPermissionIds: {
|
||||
'$read_members': true,
|
||||
'$invite_members': true,
|
||||
},
|
||||
} satisfies OrganizationRenderedConfig['rbac']['permissions'][string];
|
||||
configOverrideOverride['rbac.permissions.team_admin'] ??= {
|
||||
description: "Default permission for team admins",
|
||||
scope: "team",
|
||||
containedPermissionIds: {
|
||||
'$update_team': true,
|
||||
'$delete_team': true,
|
||||
'$read_members': true,
|
||||
'$remove_members': true,
|
||||
'$invite_members': true,
|
||||
'$manage_api_keys': true,
|
||||
},
|
||||
} satisfies OrganizationRenderedConfig['rbac']['permissions'][string];
|
||||
|
||||
configOverrideOverride['rbac.defaultPermissions.teamCreator'] ??= { 'team_admin': true };
|
||||
configOverrideOverride['rbac.defaultPermissions.teamMember'] ??= { 'team_member': true };
|
||||
configOverrideOverride['rbac.defaultPermissions.teamCreator'] ??= { 'team_admin': true };
|
||||
configOverrideOverride['rbac.defaultPermissions.teamMember'] ??= { 'team_member': true };
|
||||
|
||||
configOverrideOverride['auth.password.allowSignIn'] ??= true;
|
||||
}
|
||||
|
||||
await overrideEnvironmentConfigOverride({
|
||||
tx,
|
||||
projectId: project.id,
|
||||
branchId: branchId,
|
||||
environmentConfigOverrideOverride: configOverrideOverride,
|
||||
});
|
||||
|
||||
return [project.id, branchId];
|
||||
configOverrideOverride['auth.password.allowSignIn'] ??= true;
|
||||
}
|
||||
await overrideEnvironmentConfigOverride({
|
||||
projectId: projectId,
|
||||
branchId: branchId,
|
||||
environmentConfigOverrideOverride: configOverrideOverride,
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
# @stackframe/stack-dashboard
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Various changes
|
||||
- Updated dependencies
|
||||
- @stackframe/stack-shared@2.8.27
|
||||
- @stackframe/stack@2.8.27
|
||||
- @stackframe/stack-ui@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/stack-dashboard",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "rimraf .next && rimraf node_modules",
|
||||
|
||||
@ -2,8 +2,13 @@ import { stackServerApp } from "@/stack";
|
||||
import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env";
|
||||
import { urlString } from "@stackframe/stack-shared/dist/utils/urls";
|
||||
import * as jose from "jose";
|
||||
import { Metadata } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Signing you in...",
|
||||
};
|
||||
|
||||
export default async function FeaturebaseSSO({
|
||||
searchParams,
|
||||
}: {
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
# @stackframe/dev-launchpad
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Various changes
|
||||
|
||||
## 2.8.26
|
||||
|
||||
## 2.8.25
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/dev-launchpad",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "serve -p 8100 -s public",
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
# @stackframe/e2e-tests
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Various changes
|
||||
- Updated dependencies
|
||||
- @stackframe/stack-shared@2.8.27
|
||||
- @stackframe/js@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/e2e-tests",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@ -496,6 +496,104 @@ it("verifies email_theme update persists", async ({ expect }) => {
|
||||
expect(response.body.config.email_theme).toBe("a0172b5d-cff0-463b-83bb-85124697373a"); // default-dark
|
||||
});
|
||||
|
||||
it("updates trusted domains without modifying allow_localhost", async ({ expect }) => {
|
||||
await Project.createAndSwitch();
|
||||
const response1 = await niceBackendFetch("/api/v1/internal/projects/current", {
|
||||
method: "PATCH",
|
||||
accessType: "admin",
|
||||
body: {
|
||||
config: {
|
||||
allow_localhost: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(response1).toMatchInlineSnapshot(`
|
||||
NiceResponse {
|
||||
"status": 200,
|
||||
"body": {
|
||||
"config": {
|
||||
"allow_localhost": false,
|
||||
"allow_team_api_keys": false,
|
||||
"allow_user_api_keys": false,
|
||||
"client_team_creation_enabled": false,
|
||||
"client_user_deletion_enabled": false,
|
||||
"create_team_on_sign_up": false,
|
||||
"credential_enabled": true,
|
||||
"domains": [],
|
||||
"email_config": { "type": "shared" },
|
||||
"email_theme": "<stripped UUID>",
|
||||
"enabled_oauth_providers": [],
|
||||
"magic_link_enabled": false,
|
||||
"oauth_account_merge_strategy": "link_method",
|
||||
"oauth_providers": [],
|
||||
"passkey_enabled": false,
|
||||
"sign_up_enabled": true,
|
||||
"team_creator_default_permissions": [{ "id": "team_admin" }],
|
||||
"team_member_default_permissions": [{ "id": "team_member" }],
|
||||
"user_default_permissions": [],
|
||||
},
|
||||
"created_at_millis": <stripped field 'created_at_millis'>,
|
||||
"description": "",
|
||||
"display_name": "New Project",
|
||||
"id": "<stripped UUID>",
|
||||
"is_production_mode": false,
|
||||
},
|
||||
"headers": Headers { <some fields may have been hidden> },
|
||||
}
|
||||
`);
|
||||
|
||||
const response2 = await niceBackendFetch("/api/v1/internal/projects/current", {
|
||||
method: "PATCH",
|
||||
accessType: "admin",
|
||||
body: {
|
||||
config: {
|
||||
domains: [
|
||||
{ domain: "https://example.com", handler_path: "/handler" },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(response2).toMatchInlineSnapshot(`
|
||||
NiceResponse {
|
||||
"status": 200,
|
||||
"body": {
|
||||
"config": {
|
||||
"allow_localhost": false,
|
||||
"allow_team_api_keys": false,
|
||||
"allow_user_api_keys": false,
|
||||
"client_team_creation_enabled": false,
|
||||
"client_user_deletion_enabled": false,
|
||||
"create_team_on_sign_up": false,
|
||||
"credential_enabled": true,
|
||||
"domains": [
|
||||
{
|
||||
"domain": "https://example.com",
|
||||
"handler_path": "/handler",
|
||||
},
|
||||
],
|
||||
"email_config": { "type": "shared" },
|
||||
"email_theme": "<stripped UUID>",
|
||||
"enabled_oauth_providers": [],
|
||||
"magic_link_enabled": false,
|
||||
"oauth_account_merge_strategy": "link_method",
|
||||
"oauth_providers": [],
|
||||
"passkey_enabled": false,
|
||||
"sign_up_enabled": true,
|
||||
"team_creator_default_permissions": [{ "id": "team_admin" }],
|
||||
"team_member_default_permissions": [{ "id": "team_member" }],
|
||||
"user_default_permissions": [],
|
||||
},
|
||||
"created_at_millis": <stripped field 'created_at_millis'>,
|
||||
"description": "",
|
||||
"display_name": "New Project",
|
||||
"id": "<stripped UUID>",
|
||||
"is_production_mode": false,
|
||||
},
|
||||
"headers": Headers { <some fields may have been hidden> },
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it("gives an error when updating email_theme with an invalid value", async ({ expect }) => {
|
||||
await Project.createAndSwitch();
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
# @stackframe/mock-oauth-server
|
||||
|
||||
## 2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
## 2.8.25
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/mock-oauth-server",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
# @stackframe/stack-docs
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Various changes
|
||||
- Updated dependencies
|
||||
- @stackframe/stack-shared@2.8.27
|
||||
- @stackframe/stack@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/stack-docs",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
|
||||
31
docs/src/app/js/[...path]/route.ts
Normal file
31
docs/src/app/js/[...path]/route.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { source } from 'lib/source';
|
||||
import { notFound, redirect } from 'next/navigation';
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
export function GET(request: NextRequest) {
|
||||
const pathname = new URL(request.url).pathname;
|
||||
|
||||
// Ensure we have the correct target path without double prefixes using proper URL construction
|
||||
let targetPath: string;
|
||||
if (pathname.startsWith('/docs')) {
|
||||
targetPath = pathname;
|
||||
} else {
|
||||
// Remove leading slash and use as relative path to properly construct /docs prefix
|
||||
targetPath = new URL(pathname.substring(1), 'file:///docs/').pathname;
|
||||
}
|
||||
|
||||
// Extract slug by removing any '/docs' prefix and splitting by '/'
|
||||
const cleanPath = pathname.startsWith('/docs') ? pathname.substring(5) : pathname;
|
||||
const slug = cleanPath.substring(1).split('/').filter(Boolean);
|
||||
|
||||
// Check if the target page exists
|
||||
const page = source.getPage(slug);
|
||||
|
||||
if (page) {
|
||||
// Page exists, redirect to the full path
|
||||
return redirect(targetPath);
|
||||
} else {
|
||||
// Page doesn't exist, return 404
|
||||
return notFound();
|
||||
}
|
||||
}
|
||||
31
docs/src/app/next/[...path]/route.ts
Normal file
31
docs/src/app/next/[...path]/route.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { source } from 'lib/source';
|
||||
import { notFound, redirect } from 'next/navigation';
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
export function GET(request: NextRequest) {
|
||||
const pathname = new URL(request.url).pathname;
|
||||
|
||||
// Ensure we have the correct target path without double prefixes using proper URL construction
|
||||
let targetPath: string;
|
||||
if (pathname.startsWith('/docs')) {
|
||||
targetPath = pathname;
|
||||
} else {
|
||||
// Remove leading slash and use as relative path to properly construct /docs prefix
|
||||
targetPath = new URL(pathname.substring(1), 'file:///docs/').pathname;
|
||||
}
|
||||
|
||||
// Extract slug by removing any '/docs' prefix and splitting by '/'
|
||||
const cleanPath = pathname.startsWith('/docs') ? pathname.substring(5) : pathname;
|
||||
const slug = cleanPath.substring(1).split('/').filter(Boolean);
|
||||
|
||||
// Check if the target page exists
|
||||
const page = source.getPage(slug);
|
||||
|
||||
if (page) {
|
||||
// Page exists, redirect to the full path
|
||||
return redirect(targetPath);
|
||||
} else {
|
||||
// Page doesn't exist, redirect to overview
|
||||
return notFound();
|
||||
}
|
||||
}
|
||||
11
docs/src/app/not-found.tsx
Normal file
11
docs/src/app/not-found.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import Link from "next/link";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div>
|
||||
<h2>Not Found</h2>
|
||||
<p>Could not find requested resource</p>
|
||||
<Link href="/">Return Home</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
31
docs/src/app/python/[...path]/route.ts
Normal file
31
docs/src/app/python/[...path]/route.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { source } from 'lib/source';
|
||||
import { notFound, redirect } from 'next/navigation';
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
export function GET(request: NextRequest) {
|
||||
const pathname = new URL(request.url).pathname;
|
||||
|
||||
// Ensure we have the correct target path without double prefixes using proper URL construction
|
||||
let targetPath: string;
|
||||
if (pathname.startsWith('/docs')) {
|
||||
targetPath = pathname;
|
||||
} else {
|
||||
// Remove leading slash and use as relative path to properly construct /docs prefix
|
||||
targetPath = new URL(pathname.substring(1), 'file:///docs/').pathname;
|
||||
}
|
||||
|
||||
// Extract slug by removing any '/docs' prefix and splitting by '/'
|
||||
const cleanPath = pathname.startsWith('/docs') ? pathname.substring(5) : pathname;
|
||||
const slug = cleanPath.substring(1).split('/').filter(Boolean);
|
||||
|
||||
// Check if the target page exists
|
||||
const page = source.getPage(slug);
|
||||
|
||||
if (page) {
|
||||
// Page exists, redirect to the full path
|
||||
return redirect(targetPath);
|
||||
} else {
|
||||
// Page doesn't exist, redirect to overview
|
||||
return notFound();
|
||||
}
|
||||
}
|
||||
31
docs/src/app/react/[...path]/route.ts
Normal file
31
docs/src/app/react/[...path]/route.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { source } from 'lib/source';
|
||||
import { notFound, redirect } from 'next/navigation';
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
export function GET(request: NextRequest) {
|
||||
const pathname = new URL(request.url).pathname;
|
||||
|
||||
// Ensure we have the correct target path without double prefixes using proper URL construction
|
||||
let targetPath: string;
|
||||
if (pathname.startsWith('/docs')) {
|
||||
targetPath = pathname;
|
||||
} else {
|
||||
// Remove leading slash and use as relative path to properly construct /docs prefix
|
||||
targetPath = new URL(pathname.substring(1), 'file:///docs/').pathname;
|
||||
}
|
||||
|
||||
// Extract slug by removing any '/docs' prefix and splitting by '/'
|
||||
const cleanPath = pathname.startsWith('/docs') ? pathname.substring(5) : pathname;
|
||||
const slug = cleanPath.substring(1).split('/').filter(Boolean);
|
||||
|
||||
// Check if the target page exists
|
||||
const page = source.getPage(slug);
|
||||
|
||||
if (page) {
|
||||
// Page exists, redirect to the full path
|
||||
return redirect(targetPath);
|
||||
} else {
|
||||
// Page doesn't exist, redirect to overview
|
||||
return notFound();
|
||||
}
|
||||
}
|
||||
31
docs/src/app/rest-api/[...path]/route.ts
Normal file
31
docs/src/app/rest-api/[...path]/route.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { apiSource } from 'lib/source';
|
||||
import { notFound, redirect } from 'next/navigation';
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
export function GET(request: NextRequest) {
|
||||
const pathname = new URL(request.url).pathname;
|
||||
|
||||
// For rest-api, we redirect to /api not /docs using proper URL construction
|
||||
let targetPath: string;
|
||||
if (pathname.startsWith('/api')) {
|
||||
targetPath = pathname;
|
||||
} else {
|
||||
// Remove leading slash and use as relative path to properly construct /api prefix
|
||||
targetPath = new URL(pathname.substring(1), 'file:///api/').pathname;
|
||||
}
|
||||
|
||||
// Extract slug by removing any '/api' prefix and splitting by '/'
|
||||
const cleanPath = pathname.startsWith('/api') ? pathname.substring(4) : pathname;
|
||||
const slug = cleanPath.substring(1).split('/').filter(Boolean);
|
||||
|
||||
// Check if the target page exists using apiSource for API docs
|
||||
const page = apiSource.getPage(slug);
|
||||
|
||||
if (page) {
|
||||
// Page exists, redirect to the full path
|
||||
return redirect(targetPath);
|
||||
} else {
|
||||
// Page doesn't exist, redirect to overview
|
||||
return notFound();
|
||||
}
|
||||
}
|
||||
2
docs/templates/sdk/objects/stack-app.mdx
vendored
2
docs/templates/sdk/objects/stack-app.mdx
vendored
@ -507,7 +507,7 @@ Like `StackClientApp`, but with [server permissions](../../concepts/stack-app.md
|
||||
<Info type="warning">
|
||||
Since this functionality should only be available in environments you trust (ie. your own server), it requires a [`SECRET_SERVER_KEY`](../../rest-api/overview.mdx).
|
||||
In some cases, you may want to use a [`StackServerApp`](#stackserverapp) on the client; an example for this is an internal dashboard that only your own employees have access to.
|
||||
We generally recommend against doing this unless you are aware of and protected against the (potentially severe) secutiry implications of
|
||||
We generally recommend against doing this unless you are aware of and protected against the (potentially severe) security implications of
|
||||
exposing [`SECRET_SERVER_KEY`](../../rest-api/overview.mdx) on the client.
|
||||
</Info>
|
||||
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
# @stackframe/example-cjs-test
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @stackframe/stack@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/example-cjs-test",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --port 8110",
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
# @stackframe/example-demo-app
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @stackframe/stack-shared@2.8.27
|
||||
- @stackframe/stack@2.8.27
|
||||
- @stackframe/stack-ui@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/example-demo-app",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
# @stackframe/docs-examples
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @stackframe/stack-shared@2.8.27
|
||||
- @stackframe/stack@2.8.27
|
||||
- @stackframe/stack-ui@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/docs-examples",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
# @stackframe/e-commerce-demo
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @stackframe/stack@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/e-commerce-demo",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --port 8111",
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
# @stackframe/js-example
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @stackframe/js@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/js-example",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
# @stackframe/example-middleware-demo
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @stackframe/stack@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/example-middleware-demo",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --port 8112",
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
# @stackframe/example-partial-prerendering
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @stackframe/stack@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/example-partial-prerendering",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --port 8109",
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
# react-example
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @stackframe/react@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react-example",
|
||||
"private": true,
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --force --port 8120",
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
# @stackframe/example-supabase
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @stackframe/stack@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/example-supabase",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbo --port 8115",
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
# @stackframe/init-stack
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @stackframe/stack-shared@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/init-stack",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"description": "The setup wizard for Stack. https://stack-auth.com",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY",
|
||||
"name": "@stackframe/js",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"sideEffects": false,
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY",
|
||||
"name": "@stackframe/react",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"sideEffects": false,
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
# @stackframe/stack-sc
|
||||
|
||||
## 2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
## 2.8.25
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/stack-sc",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"exports": {
|
||||
"./force-react-server": {
|
||||
"types": "./dist/index.react-server.d.ts",
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
# @stackframe/stack-shared
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Various changes
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/stack-shared",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && tsup-node",
|
||||
"typecheck": "tsc --noEmit",
|
||||
|
||||
@ -10,16 +10,18 @@ let esbuildInitializePromise: Promise<void> | null = null;
|
||||
|
||||
export async function initializeEsbuild() {
|
||||
if (!esbuildInitializePromise) {
|
||||
esbuildInitializePromise = esbuild.initialize(isBrowserLike() ? {
|
||||
wasmURL: `https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`,
|
||||
} : {
|
||||
wasmModule: (
|
||||
await fetch(`https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`)
|
||||
.then(wasm => wasm.arrayBuffer())
|
||||
.then(wasm => new WebAssembly.Module(wasm))
|
||||
),
|
||||
worker: false,
|
||||
});
|
||||
esbuildInitializePromise = (async () => {
|
||||
await esbuild.initialize(isBrowserLike() ? {
|
||||
wasmURL: `https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`,
|
||||
} : {
|
||||
wasmModule: (
|
||||
await fetch(`https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`)
|
||||
.then(wasm => wasm.arrayBuffer())
|
||||
.then(wasm => new WebAssembly.Module(wasm))
|
||||
),
|
||||
worker: false,
|
||||
});
|
||||
})();
|
||||
}
|
||||
await esbuildInitializePromise;
|
||||
}
|
||||
|
||||
@ -340,7 +340,7 @@ export function runAsynchronously(
|
||||
promiseOrFunc?.catch(error => {
|
||||
options.onError?.(error);
|
||||
const newError = new StackAssertionError(
|
||||
"Uncaught error in asynchronous function: " + error.toString(),
|
||||
"Uncaught error in asynchronous function: " + errorToNiceString(error),
|
||||
{ cause: error },
|
||||
);
|
||||
concatStacktraces(newError, duringError);
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
# @stackframe/stack-ui
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @stackframe/stack-shared@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/stack-ui",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY",
|
||||
"name": "@stackframe/stack",
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"sideEffects": false,
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
# @stackframe/stack
|
||||
|
||||
## 2.8.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Various changes
|
||||
- Updated dependencies
|
||||
- @stackframe/stack-shared@2.8.27
|
||||
- @stackframe/stack-ui@2.8.27
|
||||
- @stackframe/stack-sc@2.8.27
|
||||
|
||||
## 2.8.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
"//": "NEXT_LINE_PLATFORM template",
|
||||
"private": true,
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"sideEffects": false,
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY",
|
||||
"name": "@stackframe/template",
|
||||
"private": true,
|
||||
"version": "2.8.26",
|
||||
"version": "2.8.27",
|
||||
"sideEffects": false,
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user