mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-19 21:00:40 +08:00
- Added support for `@opentelemetry/sdk-node` in the backend. - Updated various dependencies including AWS SDK and OpenTelemetry packages. - Implemented graceful shutdown handling for non-Vercel runtimes in `prisma-client.tsx`. - Enhanced AWS credentials retrieval to support GCP Workload Identity Federation. - Introduced a Dockerfile for Cloud Run deployment, optimizing the backend build process. - Updated `.gitignore` to include Terraform runtime files and secrets. This commit improves the backend's observability and deployment flexibility, particularly for Cloud Run environments. <!-- Make sure you've read the CONTRIBUTING.md guidelines: https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * OpenTelemetry observability with dynamic provider selection per deployment. * Cloud Run trusted-proxy support for accurate client IP handling. * Graceful shutdown that waits for in-flight background work. * New background-task handling to improve async webhook/email delivery reliability. * AWS credential providers added (Vercel OIDC & GCP Workload Identity Federation). * Dockerized backend image for Cloud Run / self-host deployments. * **Chores** * Updated dependencies for OpenTelemetry and AWS SDK support. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Konstantin Wohlwend <n2d4xc@gmail.com>
110 lines
3.6 KiB
TypeScript
110 lines
3.6 KiB
TypeScript
import type { StackClientAppConstructorOptions, StackServerAppConstructorOptions } from '@stackframe/js';
|
|
import { AdminProjectCreateOptions, StackAdminApp, StackClientApp, StackServerApp } from '@stackframe/js';
|
|
import { throwErr } from '@stackframe/stack-shared/dist/utils/errors';
|
|
import { Result } from '@stackframe/stack-shared/dist/utils/results';
|
|
import { STACK_BACKEND_BASE_URL, STACK_INTERNAL_PROJECT_ADMIN_KEY, STACK_INTERNAL_PROJECT_CLIENT_KEY, STACK_INTERNAL_PROJECT_SERVER_KEY } from '../helpers';
|
|
|
|
const testExtraRequestHeaders = {
|
|
"x-stack-disable-artificial-development-delay": "yes",
|
|
};
|
|
|
|
// When STACK_TEST_SDK_FALLBACK is set, omit explicit baseUrl so the SDK resolves
|
|
// from NEXT_PUBLIC_STACK_API_URL and exercises its fallback logic
|
|
const sdkBaseUrl = process.env.STACK_TEST_SDK_FALLBACK ? undefined : STACK_BACKEND_BASE_URL;
|
|
|
|
export async function scaffoldProject(body?: Omit<AdminProjectCreateOptions, 'displayName' | 'teamId'> & { displayName?: string }) {
|
|
const internalApp = new StackAdminApp({
|
|
projectId: 'internal',
|
|
baseUrl: sdkBaseUrl,
|
|
publishableClientKey: STACK_INTERNAL_PROJECT_CLIENT_KEY,
|
|
secretServerKey: STACK_INTERNAL_PROJECT_SERVER_KEY,
|
|
superSecretAdminKey: STACK_INTERNAL_PROJECT_ADMIN_KEY,
|
|
tokenStore: "memory",
|
|
redirectMethod: "none",
|
|
extraRequestHeaders: testExtraRequestHeaders,
|
|
});
|
|
|
|
const fakeEmail = `${crypto.randomUUID()}@stack-js-test.example.com`;
|
|
|
|
Result.orThrow(await internalApp.signUpWithCredential({
|
|
email: fakeEmail,
|
|
password: "password",
|
|
verificationCallbackUrl: "http://localhost:3000",
|
|
}));
|
|
const adminUser = await internalApp.getUser({
|
|
or: 'throw',
|
|
});
|
|
const teamId = adminUser.selectedTeam?.id ?? throwErr("No team selected");
|
|
|
|
const project = await adminUser.createProject({
|
|
displayName: body?.displayName || 'New Project',
|
|
teamId,
|
|
...body,
|
|
});
|
|
|
|
return {
|
|
project,
|
|
adminUser,
|
|
};
|
|
}
|
|
|
|
export async function createApp(
|
|
body?: Parameters<typeof scaffoldProject>[0],
|
|
appOverrides?: {
|
|
client?: Partial<StackClientAppConstructorOptions<true, string>>,
|
|
server?: Partial<StackServerAppConstructorOptions<true, string>>,
|
|
},
|
|
) {
|
|
const { project, adminUser } = await scaffoldProject(body);
|
|
const adminApp = new StackAdminApp({
|
|
projectId: project.id,
|
|
baseUrl: sdkBaseUrl,
|
|
projectOwnerSession: adminUser._internalSession,
|
|
tokenStore: "memory",
|
|
redirectMethod: "none",
|
|
extraRequestHeaders: testExtraRequestHeaders,
|
|
});
|
|
|
|
const apiKey = await adminApp.createInternalApiKey({
|
|
description: 'test',
|
|
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
|
|
hasPublishableClientKey: true,
|
|
hasSecretServerKey: true,
|
|
hasSuperSecretAdminKey: false,
|
|
});
|
|
if (!apiKey.secretServerKey) {
|
|
throw new Error("createInternalApiKey did not return a secretServerKey");
|
|
}
|
|
const secretServerKey = apiKey.secretServerKey;
|
|
|
|
const serverApp = new StackServerApp({
|
|
baseUrl: sdkBaseUrl,
|
|
projectId: project.id,
|
|
publishableClientKey: apiKey.publishableClientKey,
|
|
secretServerKey,
|
|
tokenStore: "memory",
|
|
redirectMethod: "none",
|
|
extraRequestHeaders: testExtraRequestHeaders,
|
|
...(appOverrides?.server ?? {}),
|
|
});
|
|
|
|
const clientApp = new StackClientApp({
|
|
baseUrl: sdkBaseUrl,
|
|
projectId: project.id,
|
|
publishableClientKey: apiKey.publishableClientKey,
|
|
tokenStore: "memory",
|
|
redirectMethod: "none",
|
|
extraRequestHeaders: testExtraRequestHeaders,
|
|
...(appOverrides?.client ?? {}),
|
|
});
|
|
|
|
return {
|
|
serverApp,
|
|
clientApp,
|
|
adminApp,
|
|
apiKey,
|
|
project,
|
|
secretServerKey,
|
|
};
|
|
}
|