mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
client sdk local emulator
This commit is contained in:
parent
612cb71a28
commit
01ca85027c
@ -141,7 +141,7 @@ async function getOrCreateCredentials(projectId: string) {
|
||||
},
|
||||
});
|
||||
|
||||
if (!keySet.secretServerKey || !keySet.superSecretAdminKey) {
|
||||
if (!keySet.publishableClientKey || !keySet.secretServerKey || !keySet.superSecretAdminKey) {
|
||||
throw new StackAssertionError("Local emulator key set is missing required keys.", {
|
||||
projectId,
|
||||
keySetId: keySet.id,
|
||||
@ -149,6 +149,7 @@ async function getOrCreateCredentials(projectId: string) {
|
||||
}
|
||||
|
||||
return {
|
||||
publishableClientKey: keySet.publishableClientKey,
|
||||
secretServerKey: keySet.secretServerKey,
|
||||
superSecretAdminKey: keySet.superSecretAdminKey,
|
||||
};
|
||||
@ -178,6 +179,7 @@ export const POST = createSmartRouteHandler({
|
||||
bodyType: yupString().oneOf(["json"]).defined(),
|
||||
body: yupObject({
|
||||
project_id: yupString().defined(),
|
||||
publishable_client_key: yupString().defined(),
|
||||
secret_server_key: yupString().defined(),
|
||||
super_secret_admin_key: yupString().defined(),
|
||||
branch_config_override_string: yupString().defined(),
|
||||
@ -222,6 +224,7 @@ export const POST = createSmartRouteHandler({
|
||||
bodyType: "json" as const,
|
||||
body: {
|
||||
project_id: projectId,
|
||||
publishable_client_key: credentials.publishableClientKey,
|
||||
secret_server_key: credentials.secretServerKey,
|
||||
super_secret_admin_key: credentials.superSecretAdminKey,
|
||||
branch_config_override_string: JSON.stringify(fileConfig),
|
||||
|
||||
@ -6,6 +6,10 @@ import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env";
|
||||
import { StatusError } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
import { globalPrismaClient } from "@/prisma-client";
|
||||
|
||||
export const LOCAL_EMULATOR_INTERNAL_PUBLISHABLE_CLIENT_KEY = "local-emulator-publishable-client-key";
|
||||
export const LOCAL_EMULATOR_INTERNAL_SECRET_SERVER_KEY = "local-emulator-secret-server-key";
|
||||
export const LOCAL_EMULATOR_INTERNAL_SUPER_SECRET_ADMIN_KEY = "local-emulator-super-secret-admin-key";
|
||||
|
||||
export const LOCAL_EMULATOR_ADMIN_USER_ID = "63abbc96-5329-454a-ba56-e0460173c6c1";
|
||||
export const LOCAL_EMULATOR_OWNER_TEAM_ID = "5a0c858b-d9e9-49d4-9943-8ce385d86428";
|
||||
export const LOCAL_EMULATOR_ADMIN_EMAIL = "local-emulator@stack-auth.com";
|
||||
|
||||
@ -11,9 +11,15 @@ fi
|
||||
|
||||
# ============= ENV VARS =============
|
||||
|
||||
export STACK_SEED_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY=${STACK_SEED_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY:-$(openssl rand -base64 32)}
|
||||
export STACK_SEED_INTERNAL_PROJECT_SECRET_SERVER_KEY=${STACK_SEED_INTERNAL_PROJECT_SECRET_SERVER_KEY:-$(openssl rand -base64 32)}
|
||||
export STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY=${STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY:-$(openssl rand -base64 32)}
|
||||
if [ "$NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR" = "true" ]; then
|
||||
export STACK_SEED_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY=${STACK_SEED_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY:-local-emulator-publishable-client-key}
|
||||
export STACK_SEED_INTERNAL_PROJECT_SECRET_SERVER_KEY=${STACK_SEED_INTERNAL_PROJECT_SECRET_SERVER_KEY:-local-emulator-secret-server-key}
|
||||
export STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY=${STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY:-local-emulator-super-secret-admin-key}
|
||||
else
|
||||
export STACK_SEED_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY=${STACK_SEED_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY:-$(openssl rand -base64 32)}
|
||||
export STACK_SEED_INTERNAL_PROJECT_SECRET_SERVER_KEY=${STACK_SEED_INTERNAL_PROJECT_SECRET_SERVER_KEY:-$(openssl rand -base64 32)}
|
||||
export STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY=${STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY:-$(openssl rand -base64 32)}
|
||||
fi
|
||||
|
||||
export NEXT_PUBLIC_STACK_PROJECT_ID=internal
|
||||
export NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=${STACK_SEED_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY}
|
||||
|
||||
@ -57,17 +57,26 @@ export type InternalApiKeyCreateCrudResponse = InternalApiKeysCrud["Admin"]["Rea
|
||||
|
||||
|
||||
export class StackAdminInterface extends StackServerInterface {
|
||||
protected _superSecretAdminKeyOverride?: string;
|
||||
|
||||
constructor(public readonly options: AdminAuthApplicationOptions) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
override _updateEmulatorCredentials(opts: { projectId?: string, publishableClientKey?: string, secretServerKey?: string, superSecretAdminKey?: string }) {
|
||||
super._updateEmulatorCredentials(opts);
|
||||
if (opts.superSecretAdminKey) {
|
||||
this._superSecretAdminKeyOverride = opts.superSecretAdminKey;
|
||||
}
|
||||
}
|
||||
|
||||
public async sendAdminRequest(path: string, options: RequestInit, session: InternalSession | null, requestType: "admin" = "admin") {
|
||||
return await this.sendServerRequest(
|
||||
path,
|
||||
{
|
||||
...options,
|
||||
headers: {
|
||||
"x-stack-super-secret-admin-key": "superSecretAdminKey" in this.options ? this.options.superSecretAdminKey : "",
|
||||
"x-stack-super-secret-admin-key": this._superSecretAdminKeyOverride ?? ("superSecretAdminKey" in this.options ? this.options.superSecretAdminKey : ""),
|
||||
...options.headers,
|
||||
},
|
||||
},
|
||||
|
||||
@ -50,12 +50,24 @@ export type ClientInterfaceOptions = {
|
||||
export class StackClientInterface {
|
||||
private pendingNetworkDiagnostics?: ReturnType<StackClientInterface["_runNetworkDiagnosticsInner"]>;
|
||||
|
||||
protected _projectIdOverride?: string;
|
||||
protected _publishableClientKeyOverride?: string;
|
||||
|
||||
constructor(public readonly options: ClientInterfaceOptions) {
|
||||
// nothing here
|
||||
}
|
||||
|
||||
get projectId() {
|
||||
return this.options.projectId;
|
||||
return this._projectIdOverride ?? this.options.projectId;
|
||||
}
|
||||
|
||||
_updateEmulatorCredentials(opts: { projectId?: string, publishableClientKey?: string }) {
|
||||
if (opts.projectId) {
|
||||
this._projectIdOverride = opts.projectId;
|
||||
}
|
||||
if (opts.publishableClientKey) {
|
||||
this._publishableClientKeyOverride = opts.publishableClientKey;
|
||||
}
|
||||
}
|
||||
|
||||
getApiUrl() {
|
||||
@ -397,7 +409,9 @@ export class StackClientInterface {
|
||||
"X-Stack-Refresh-Token": tokenObj.refreshToken.token,
|
||||
} : {}),
|
||||
"X-Stack-Allow-Anonymous-User": "true",
|
||||
...("publishableClientKey" in this.options && this.options.publishableClientKey ? {
|
||||
...(this._publishableClientKeyOverride ? {
|
||||
"X-Stack-Publishable-Client-Key": this._publishableClientKeyOverride,
|
||||
} : "publishableClientKey" in this.options && this.options.publishableClientKey ? {
|
||||
"X-Stack-Publishable-Client-Key": this.options.publishableClientKey,
|
||||
} : {}),
|
||||
...(adminTokenObj ? {
|
||||
|
||||
@ -39,17 +39,26 @@ export type ServerAuthApplicationOptions = (
|
||||
);
|
||||
|
||||
export class StackServerInterface extends StackClientInterface {
|
||||
protected _secretServerKeyOverride?: string;
|
||||
|
||||
constructor(public override options: ServerAuthApplicationOptions) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
override _updateEmulatorCredentials(opts: { projectId?: string, publishableClientKey?: string, secretServerKey?: string }) {
|
||||
super._updateEmulatorCredentials(opts);
|
||||
if (opts.secretServerKey) {
|
||||
this._secretServerKeyOverride = opts.secretServerKey;
|
||||
}
|
||||
}
|
||||
|
||||
protected async sendServerRequest(path: string, options: RequestInit, session: InternalSession | null, requestType: "server" | "admin" = "server") {
|
||||
return await this.sendClientRequest(
|
||||
path,
|
||||
{
|
||||
...options,
|
||||
headers: {
|
||||
"x-stack-secret-server-key": "secretServerKey" in this.options ? this.options.secretServerKey : "",
|
||||
"x-stack-secret-server-key": this._secretServerKeyOverride ?? ("secretServerKey" in this.options ? this.options.secretServerKey : ""),
|
||||
...options.headers,
|
||||
},
|
||||
},
|
||||
|
||||
@ -22,7 +22,7 @@ import { AdminProjectPermission, AdminProjectPermissionDefinition, AdminProjectP
|
||||
import { AdminOwnedProject, AdminProject, AdminProjectUpdateOptions, PushConfigOptions, adminProjectUpdateOptionsToCrud } from "../../projects";
|
||||
import type { AdminSessionReplay, AdminSessionReplayChunk, ListSessionReplayChunksOptions, ListSessionReplayChunksResult, ListSessionReplaysOptions, ListSessionReplaysResult, SessionReplayAllEventsResult } from "../../session-replays";
|
||||
import { ManagedEmailProviderListItem, ManagedEmailProviderSetupResult, ManagedEmailProviderStatus, EmailOutboxUpdateOptions, StackAdminApp, StackAdminAppConstructorOptions } from "../interfaces/admin-app";
|
||||
import { clientVersion, createCache, getBaseUrl, getDefaultExtraRequestHeaders, getDefaultProjectId, getDefaultPublishableClientKey, getDefaultSecretServerKey, getDefaultSuperSecretAdminKey, resolveConstructorOptions } from "./common";
|
||||
import { LOCAL_EMULATOR_INTERNAL_PUBLISHABLE_CLIENT_KEY, clientVersion, createCache, fetchEmulatorProjectCredentials, getBaseUrl, getDefaultExtraRequestHeaders, getDefaultProjectId, getDefaultPublishableClientKey, getDefaultSecretServerKey, getDefaultSuperSecretAdminKey, getLocalEmulatorConfigFilePath, resolveConstructorOptions } from "./common";
|
||||
import { _StackServerAppImplIncomplete } from "./server-app-impl";
|
||||
|
||||
import { CompleteConfig, EnvironmentConfigOverrideOverride } from "@stackframe/stack-shared/dist/config/schema";
|
||||
@ -128,24 +128,40 @@ export class _StackAdminAppImplIncomplete<HasTokenStore extends boolean, Project
|
||||
|
||||
constructor(options: StackAdminAppConstructorOptions<HasTokenStore, ProjectId>, extraOptions?: { uniqueIdentifier?: string, checkString?: string, interface?: StackAdminInterface }) {
|
||||
const resolvedOptions = resolveConstructorOptions(options);
|
||||
const publishableClientKey = resolvedOptions.publishableClientKey ?? getDefaultPublishableClientKey();
|
||||
|
||||
const emulatorConfigFilePath = getLocalEmulatorConfigFilePath(resolvedOptions.localEmulatorConfigFilePath);
|
||||
const isEmulator = !!emulatorConfigFilePath;
|
||||
|
||||
const publishableClientKey = resolvedOptions.publishableClientKey ?? getDefaultPublishableClientKey() ?? (isEmulator ? LOCAL_EMULATOR_INTERNAL_PUBLISHABLE_CLIENT_KEY : undefined);
|
||||
|
||||
super(resolvedOptions, {
|
||||
...extraOptions,
|
||||
interface: extraOptions?.interface ?? new StackAdminInterface({
|
||||
getBaseUrl: () => getBaseUrl(resolvedOptions.baseUrl),
|
||||
projectId: resolvedOptions.projectId ?? getDefaultProjectId(),
|
||||
getBaseUrl: () => getBaseUrl(resolvedOptions.baseUrl, { isEmulator }),
|
||||
projectId: resolvedOptions.projectId ?? getDefaultProjectId({ isEmulator }),
|
||||
extraRequestHeaders: resolvedOptions.extraRequestHeaders ?? getDefaultExtraRequestHeaders(),
|
||||
clientVersion,
|
||||
...resolvedOptions.projectOwnerSession ? {
|
||||
projectOwnerSession: resolvedOptions.projectOwnerSession,
|
||||
} : {
|
||||
...(publishableClientKey ? { publishableClientKey } : {}),
|
||||
secretServerKey: resolvedOptions.secretServerKey ?? getDefaultSecretServerKey(),
|
||||
superSecretAdminKey: resolvedOptions.superSecretAdminKey ?? getDefaultSuperSecretAdminKey(),
|
||||
secretServerKey: resolvedOptions.secretServerKey ?? getDefaultSecretServerKey({ isEmulator }),
|
||||
superSecretAdminKey: resolvedOptions.superSecretAdminKey ?? getDefaultSuperSecretAdminKey({ isEmulator }),
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
if (isEmulator && !extraOptions?.interface) {
|
||||
const iface = this._interface;
|
||||
this._emulatorInitPromise = fetchEmulatorProjectCredentials(emulatorConfigFilePath!).then((data) => {
|
||||
iface._updateEmulatorCredentials({
|
||||
projectId: data.project_id,
|
||||
publishableClientKey: data.publishable_client_key,
|
||||
secretServerKey: data.secret_server_key,
|
||||
superSecretAdminKey: data.super_secret_admin_key,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_adminConfigFromCrud(data: { config_string: string }): CompleteConfig {
|
||||
|
||||
@ -52,7 +52,7 @@ import { EditableTeamMemberProfile, ReceivedTeamInvitation, SentTeamInvitation,
|
||||
import { ActiveSession, Auth, BaseUser, CurrentUser, InternalUserExtra, OAuthProvider, ProjectCurrentUser, SyncedPartialUser, TokenPartialUser, UserExtra, UserUpdateOptions, userUpdateOptionsToCrud, withUserDestructureGuard } from "../../users";
|
||||
import { StackClientApp, StackClientAppConstructorOptions, StackClientAppJson } from "../interfaces/client-app";
|
||||
import { _StackAdminAppImplIncomplete } from "./admin-app-impl";
|
||||
import { TokenObject, clientVersion, createCache, createCacheBySession, createEmptyTokenStore, getAnalyticsBaseUrl, getBaseUrl, getDefaultExtraRequestHeaders, getDefaultProjectId, getDefaultPublishableClientKey, getUrls, resolveConstructorOptions } from "./common";
|
||||
import { LOCAL_EMULATOR_INTERNAL_PUBLISHABLE_CLIENT_KEY, TokenObject, clientVersion, createCache, createCacheBySession, createEmptyTokenStore, fetchEmulatorProjectCredentials, getAnalyticsBaseUrl, getBaseUrl, getDefaultExtraRequestHeaders, getDefaultProjectId, getDefaultPublishableClientKey, getLocalEmulatorConfigFilePath, getUrls, resolveConstructorOptions } from "./common";
|
||||
import { EventTracker } from "./event-tracker";
|
||||
import { AnalyticsOptions, SessionRecorder, analyticsOptionsFromJson, analyticsOptionsToJson } from "./session-replay";
|
||||
|
||||
@ -101,6 +101,7 @@ export class _StackClientAppImplIncomplete<HasTokenStore extends boolean, Projec
|
||||
private _sessionRecorder: SessionRecorder | null = null;
|
||||
private _eventTracker: EventTracker | null = null;
|
||||
|
||||
protected _emulatorInitPromise: Promise<void> | null = null;
|
||||
private __DEMO_ENABLE_SLIGHT_FETCH_DELAY = false;
|
||||
private readonly _ownedAdminApps = new DependenciesMap<[InternalSession, string], _StackAdminAppImplIncomplete<false, string>>();
|
||||
|
||||
@ -499,29 +500,43 @@ export class _StackClientAppImplIncomplete<HasTokenStore extends boolean, Projec
|
||||
this._options = resolvedOptions;
|
||||
this._extraOptions = extraOptions;
|
||||
|
||||
const projectId = resolvedOptions.projectId ?? getDefaultProjectId();
|
||||
const emulatorConfigFilePath = getLocalEmulatorConfigFilePath(resolvedOptions.localEmulatorConfigFilePath);
|
||||
const isEmulator = !!emulatorConfigFilePath;
|
||||
|
||||
const projectId = resolvedOptions.projectId ?? getDefaultProjectId({ isEmulator });
|
||||
if (projectId !== "internal" && !(projectId.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i))) {
|
||||
throw new Error(`Invalid project ID: ${projectId}. Project IDs must be UUIDs. Please check your environment variables and/or your StackApp.`);
|
||||
}
|
||||
|
||||
const publishableClientKey = resolvedOptions.publishableClientKey ?? getDefaultPublishableClientKey();
|
||||
const publishableClientKey = resolvedOptions.publishableClientKey ?? getDefaultPublishableClientKey() ?? (isEmulator ? LOCAL_EMULATOR_INTERNAL_PUBLISHABLE_CLIENT_KEY : undefined);
|
||||
|
||||
if (extraOptions && extraOptions.interface) {
|
||||
this._interface = extraOptions.interface;
|
||||
} else {
|
||||
this._interface = new StackClientInterface({
|
||||
getBaseUrl: () => getBaseUrl(resolvedOptions.baseUrl),
|
||||
getAnalyticsBaseUrl: () => getAnalyticsBaseUrl(getBaseUrl(resolvedOptions.baseUrl)),
|
||||
getBaseUrl: () => getBaseUrl(resolvedOptions.baseUrl, { isEmulator }),
|
||||
getAnalyticsBaseUrl: () => getAnalyticsBaseUrl(getBaseUrl(resolvedOptions.baseUrl, { isEmulator })),
|
||||
extraRequestHeaders: resolvedOptions.extraRequestHeaders ?? getDefaultExtraRequestHeaders(),
|
||||
projectId,
|
||||
clientVersion,
|
||||
...(publishableClientKey != null ? { publishableClientKey } : {}),
|
||||
prepareRequest: async () => {
|
||||
if (this._emulatorInitPromise) await this._emulatorInitPromise;
|
||||
await cookies?.(); // THIS_LINE_PLATFORM next
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isEmulator && !(extraOptions && extraOptions.interface)) {
|
||||
const iface = this._interface;
|
||||
this._emulatorInitPromise = fetchEmulatorProjectCredentials(emulatorConfigFilePath!).then((data) => {
|
||||
iface._updateEmulatorCredentials({
|
||||
projectId: data.project_id,
|
||||
publishableClientKey: data.publishable_client_key,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this._tokenStoreInit = resolvedOptions.tokenStore;
|
||||
this._redirectMethod = resolvedOptions.redirectMethod || "none";
|
||||
this._redirectMethod = resolvedOptions.redirectMethod || "nextjs"; // THIS_LINE_PLATFORM next
|
||||
|
||||
@ -81,7 +81,44 @@ export function getUrls(partial: Partial<HandlerUrls>): HandlerUrls {
|
||||
};
|
||||
}
|
||||
|
||||
export function getDefaultProjectId() {
|
||||
export const localEmulatorBaseUrl = "http://localhost:9999";
|
||||
|
||||
export const LOCAL_EMULATOR_INTERNAL_PUBLISHABLE_CLIENT_KEY = "local-emulator-publishable-client-key";
|
||||
export const LOCAL_EMULATOR_INTERNAL_SECRET_SERVER_KEY = "local-emulator-secret-server-key";
|
||||
export const LOCAL_EMULATOR_INTERNAL_SUPER_SECRET_ADMIN_KEY = "local-emulator-super-secret-admin-key";
|
||||
|
||||
export function getLocalEmulatorConfigFilePath(explicitOption?: string): string | undefined {
|
||||
return explicitOption || process.env.NEXT_PUBLIC_STACK_LOCAL_EMULATOR_CONFIG_FILE_PATH || undefined;
|
||||
}
|
||||
|
||||
export function fetchEmulatorProjectCredentials(emulatorConfigFilePath: string): Promise<{
|
||||
project_id: string,
|
||||
publishable_client_key: string,
|
||||
secret_server_key: string,
|
||||
super_secret_admin_key: string,
|
||||
}> {
|
||||
return (async () => {
|
||||
const res = await fetch(`${localEmulatorBaseUrl}/api/v1/internal/local-emulator/project`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Stack-Project-Id": "internal",
|
||||
"X-Stack-Access-Type": "client",
|
||||
"X-Stack-Publishable-Client-Key": LOCAL_EMULATOR_INTERNAL_PUBLISHABLE_CLIENT_KEY,
|
||||
},
|
||||
body: JSON.stringify({ absolute_file_path: emulatorConfigFilePath }),
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to initialize local emulator: ${res.status} ${await res.text()}`);
|
||||
}
|
||||
return await res.json();
|
||||
})();
|
||||
}
|
||||
|
||||
export function getDefaultProjectId(options?: { isEmulator?: boolean }) {
|
||||
if (options?.isEmulator) {
|
||||
return process.env.NEXT_PUBLIC_STACK_PROJECT_ID || process.env.STACK_PROJECT_ID || "internal";
|
||||
}
|
||||
return process.env.NEXT_PUBLIC_STACK_PROJECT_ID || process.env.STACK_PROJECT_ID || throwErr(new Error("Welcome to Stack Auth! It seems that you haven't provided a project ID. Please create a project on the Stack dashboard at https://app.stack-auth.com and put it in the NEXT_PUBLIC_STACK_PROJECT_ID environment variable."));
|
||||
}
|
||||
|
||||
@ -89,11 +126,17 @@ export function getDefaultPublishableClientKey() {
|
||||
return process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY || process.env.STACK_PUBLISHABLE_CLIENT_KEY;
|
||||
}
|
||||
|
||||
export function getDefaultSecretServerKey() {
|
||||
export function getDefaultSecretServerKey(options?: { isEmulator?: boolean }) {
|
||||
if (options?.isEmulator) {
|
||||
return process.env.STACK_SECRET_SERVER_KEY || LOCAL_EMULATOR_INTERNAL_SECRET_SERVER_KEY;
|
||||
}
|
||||
return process.env.STACK_SECRET_SERVER_KEY || throwErr(new Error("No secret server key provided. Please copy your key from the Stack dashboard and put it in the STACK_SECRET_SERVER_KEY environment variable."));
|
||||
}
|
||||
|
||||
export function getDefaultSuperSecretAdminKey() {
|
||||
export function getDefaultSuperSecretAdminKey(options?: { isEmulator?: boolean }) {
|
||||
if (options?.isEmulator) {
|
||||
return process.env.STACK_SUPER_SECRET_ADMIN_KEY || LOCAL_EMULATOR_INTERNAL_SUPER_SECRET_ADMIN_KEY;
|
||||
}
|
||||
return process.env.STACK_SUPER_SECRET_ADMIN_KEY || throwErr(new Error("No super secret admin key provided. Please copy your key from the Stack dashboard and put it in the STACK_SUPER_SECRET_ADMIN_KEY environment variable."));
|
||||
}
|
||||
|
||||
@ -119,7 +162,7 @@ export function getDefaultExtraRequestHeaders() {
|
||||
* @returns The configured base URL without trailing slash
|
||||
|
||||
*/
|
||||
export function getBaseUrl(userSpecifiedBaseUrl: string | { browser: string, server: string } | undefined) {
|
||||
export function getBaseUrl(userSpecifiedBaseUrl: string | { browser: string, server: string } | undefined, options?: { isEmulator?: boolean }) {
|
||||
let url;
|
||||
if (userSpecifiedBaseUrl) {
|
||||
if (typeof userSpecifiedBaseUrl === "string") {
|
||||
@ -138,7 +181,7 @@ export function getBaseUrl(userSpecifiedBaseUrl: string | { browser: string, ser
|
||||
} else {
|
||||
url = process.env.NEXT_PUBLIC_SERVER_STACK_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL_SERVER || process.env.STACK_API_URL_SERVER;
|
||||
}
|
||||
url = url || process.env.NEXT_PUBLIC_STACK_API_URL || process.env.STACK_API_URL || process.env.NEXT_PUBLIC_STACK_URL || defaultBaseUrl;
|
||||
url = url || process.env.NEXT_PUBLIC_STACK_API_URL || process.env.STACK_API_URL || process.env.NEXT_PUBLIC_STACK_URL || (options?.isEmulator ? localEmulatorBaseUrl : defaultBaseUrl);
|
||||
}
|
||||
|
||||
return replaceStackPortPrefix(url.endsWith('/') ? url.slice(0, -1) : url);
|
||||
|
||||
@ -35,7 +35,7 @@ import { EditableTeamMemberProfile, ReceivedTeamInvitation, SentTeamInvitation,
|
||||
import { ProjectCurrentServerUser, ServerOAuthProvider, ServerUser, ServerUserCreateOptions, ServerUserUpdateOptions, serverUserCreateOptionsToCrud, serverUserUpdateOptionsToCrud, withUserDestructureGuard } from "../../users";
|
||||
import { StackServerAppConstructorOptions } from "../interfaces/server-app";
|
||||
import { _StackClientAppImplIncomplete } from "./client-app-impl";
|
||||
import { clientVersion, createCache, createCacheBySession, getBaseUrl, getDefaultExtraRequestHeaders, getDefaultProjectId, getDefaultPublishableClientKey, getDefaultSecretServerKey, resolveConstructorOptions } from "./common";
|
||||
import { LOCAL_EMULATOR_INTERNAL_PUBLISHABLE_CLIENT_KEY, clientVersion, createCache, createCacheBySession, fetchEmulatorProjectCredentials, getBaseUrl, getDefaultExtraRequestHeaders, getDefaultProjectId, getDefaultPublishableClientKey, getDefaultSecretServerKey, getLocalEmulatorConfigFilePath, resolveConstructorOptions } from "./common";
|
||||
|
||||
import { useAsyncCache } from "./common"; // THIS_LINE_PLATFORM react-like
|
||||
|
||||
@ -410,19 +410,33 @@ export class _StackServerAppImplIncomplete<HasTokenStore extends boolean, Projec
|
||||
constructor(options: StackServerAppConstructorOptions<HasTokenStore, ProjectId>, extraOptions?: { uniqueIdentifier?: string, checkString?: string, interface?: StackServerInterface }) {
|
||||
const resolvedOptions = resolveConstructorOptions(options);
|
||||
|
||||
const publishableClientKey = resolvedOptions.publishableClientKey ?? getDefaultPublishableClientKey();
|
||||
const emulatorConfigFilePath = getLocalEmulatorConfigFilePath(resolvedOptions.localEmulatorConfigFilePath);
|
||||
const isEmulator = !!emulatorConfigFilePath;
|
||||
|
||||
const publishableClientKey = resolvedOptions.publishableClientKey ?? getDefaultPublishableClientKey() ?? (isEmulator ? LOCAL_EMULATOR_INTERNAL_PUBLISHABLE_CLIENT_KEY : undefined);
|
||||
|
||||
super(resolvedOptions, {
|
||||
...extraOptions,
|
||||
interface: extraOptions?.interface ?? new StackServerInterface({
|
||||
getBaseUrl: () => getBaseUrl(resolvedOptions.baseUrl),
|
||||
projectId: resolvedOptions.projectId ?? getDefaultProjectId(),
|
||||
getBaseUrl: () => getBaseUrl(resolvedOptions.baseUrl, { isEmulator }),
|
||||
projectId: resolvedOptions.projectId ?? getDefaultProjectId({ isEmulator }),
|
||||
extraRequestHeaders: resolvedOptions.extraRequestHeaders ?? getDefaultExtraRequestHeaders(),
|
||||
clientVersion,
|
||||
...(publishableClientKey != null ? { publishableClientKey } : {}),
|
||||
secretServerKey: resolvedOptions.secretServerKey ?? getDefaultSecretServerKey(),
|
||||
secretServerKey: resolvedOptions.secretServerKey ?? getDefaultSecretServerKey({ isEmulator }),
|
||||
}),
|
||||
});
|
||||
|
||||
if (isEmulator && !extraOptions?.interface) {
|
||||
const iface = this._interface;
|
||||
this._emulatorInitPromise = fetchEmulatorProjectCredentials(emulatorConfigFilePath!).then((data) => {
|
||||
iface._updateEmulatorCredentials({
|
||||
projectId: data.project_id,
|
||||
publishableClientKey: data.publishable_client_key,
|
||||
secretServerKey: data.secret_server_key,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -19,6 +19,13 @@ export type StackClientAppConstructorOptions<HasTokenStore extends boolean, Proj
|
||||
redirectMethod?: RedirectMethod,
|
||||
inheritsFrom?: StackClientApp<any, any>,
|
||||
|
||||
/**
|
||||
* Path to the local emulator config file. When set, connects to the local
|
||||
* emulator and automatically fetches project credentials.
|
||||
* Defaults to NEXT_PUBLIC_STACK_LOCAL_EMULATOR_CONFIG_FILE_PATH env var.
|
||||
*/
|
||||
localEmulatorConfigFilePath?: string,
|
||||
|
||||
/**
|
||||
* By default, the Stack app will automatically prefetch some data from Stack's server when this app is first
|
||||
* constructed. This improves the performance of your app, but will create network requests that are unnecessary if
|
||||
|
||||
Loading…
Reference in New Issue
Block a user