@tacoreai/web-sdk 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -30,6 +30,20 @@ const getRequestSource = (isPlatformProxyRequest, isSchedulerRequest) => {
|
|
|
30
30
|
return isPreviewMode() ? "preview-direct" : "external-direct";
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
const createRequestScopedAppsClient = (env, options = {}) => {
|
|
34
|
+
const { accessToken = null, previewAppServerApiKey = null } = options;
|
|
35
|
+
const config = {
|
|
36
|
+
...env,
|
|
37
|
+
accessToken: accessToken || null,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (previewAppServerApiKey) {
|
|
41
|
+
config.previewAppServerApiKey = previewAppServerApiKey;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return new AppsClient(env.appId, config);
|
|
45
|
+
};
|
|
46
|
+
|
|
33
47
|
const isPreviewApiKeyShapeValid = (apiKey) => {
|
|
34
48
|
if (typeof apiKey !== "string") return false;
|
|
35
49
|
const value = apiKey.trim();
|
|
@@ -247,7 +261,6 @@ export const createAppServerRuntime = async (options = {}) => {
|
|
|
247
261
|
});
|
|
248
262
|
}
|
|
249
263
|
|
|
250
|
-
const appsClient = AppsClient.getInstance(env.appId, { ...env, accessToken: requestAccessToken || null });
|
|
251
264
|
const previewBridgeInteropToken =
|
|
252
265
|
process.env.TACORE_APPSERVER_PREVIEW_BRIDGE_INTEROP_TOKEN ||
|
|
253
266
|
process.env.TACORE_SERVER_INTEROP_APP_SERVER_API_KEY;
|
|
@@ -260,6 +273,7 @@ export const createAppServerRuntime = async (options = {}) => {
|
|
|
260
273
|
process.env.CLOUDFLARE_WORKER_INTEROP_APP_SERVER_TOKEN
|
|
261
274
|
);
|
|
262
275
|
const requestSource = getRequestSource(isPlatformProxyRequest, isSchedulerRequest);
|
|
276
|
+
let previewAppServerApiKey = null;
|
|
263
277
|
|
|
264
278
|
console.log(`[AppServer] invoke api="${apiName}" source="${requestSource}"`);
|
|
265
279
|
|
|
@@ -283,7 +297,10 @@ export const createAppServerRuntime = async (options = {}) => {
|
|
|
283
297
|
|
|
284
298
|
let isValidApiKey = false;
|
|
285
299
|
try {
|
|
286
|
-
|
|
300
|
+
const authClient = createRequestScopedAppsClient(env, {
|
|
301
|
+
accessToken: requestAccessToken || null,
|
|
302
|
+
});
|
|
303
|
+
isValidApiKey = await validateExternalApiKey(authClient, env.appId, requestApiKey);
|
|
287
304
|
} catch (error) {
|
|
288
305
|
console.error("[AppServer] Failed to validate external API key:", error);
|
|
289
306
|
return res.status(500).json({
|
|
@@ -300,9 +317,31 @@ export const createAppServerRuntime = async (options = {}) => {
|
|
|
300
317
|
error: "Invalid X-API-Key",
|
|
301
318
|
});
|
|
302
319
|
}
|
|
320
|
+
|
|
321
|
+
if (isPreviewMode() && !requestAccessToken) {
|
|
322
|
+
previewAppServerApiKey = requestApiKey;
|
|
323
|
+
}
|
|
303
324
|
}
|
|
304
325
|
|
|
305
326
|
try {
|
|
327
|
+
console.log(`[AppServer Debug] invoke api="${apiName}" auth forwarding`, {
|
|
328
|
+
requestSource,
|
|
329
|
+
hasAuthorization: Boolean(requestAccessToken),
|
|
330
|
+
hasRequestApiKey: Boolean(requestApiKey),
|
|
331
|
+
hasPlatformInteropHeader: Boolean(platformInteropHeader),
|
|
332
|
+
hasSchedulerInteropHeader: Boolean(schedulerInteropHeader),
|
|
333
|
+
willForwardPreviewAppServerApiKey: Boolean(previewAppServerApiKey),
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const appsClient = createRequestScopedAppsClient(env, {
|
|
337
|
+
accessToken: requestAccessToken || null,
|
|
338
|
+
previewAppServerApiKey,
|
|
339
|
+
});
|
|
340
|
+
console.log(`[AppServer Debug] scoped AppsClient api="${apiName}"`, {
|
|
341
|
+
hasAccessToken: Boolean(appsClient.getAccessToken()),
|
|
342
|
+
hasPreviewAppServerApiKey: Boolean(appsClient.config.previewAppServerApiKey),
|
|
343
|
+
hasInteropKey: Boolean(appsClient.config.tacoreServerInteropAppServerApiKey),
|
|
344
|
+
});
|
|
306
345
|
const data = await appsClient.invokeAppServerAPI(apiName, payload, {
|
|
307
346
|
appsClient,
|
|
308
347
|
req,
|
|
@@ -7,6 +7,10 @@ const previewSessionPromiseCache = new Map();
|
|
|
7
7
|
const PREVIEW_TOKEN_HEADER = "X-Tacore-AppServer-Preview-Token";
|
|
8
8
|
const APPSERVER_REQUEST_DATA_FIELD = "requestData";
|
|
9
9
|
const DEFAULT_FILE_FIELD_NAME = "file";
|
|
10
|
+
const REMOTE_REQUEST_HEADER_MODE = {
|
|
11
|
+
ACCESS_TOKEN_ONLY: "access-token-only",
|
|
12
|
+
APPS_CLIENT: "apps-client",
|
|
13
|
+
};
|
|
10
14
|
|
|
11
15
|
const isBrowserPreviewRuntime = () => {
|
|
12
16
|
if (typeof window === "undefined") {
|
|
@@ -304,15 +308,34 @@ const normalizeAppServerFiles = (files) => {
|
|
|
304
308
|
return normalizeSingleFileInput(files, DEFAULT_FILE_FIELD_NAME);
|
|
305
309
|
};
|
|
306
310
|
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
311
|
+
const buildRemoteRequestHeaders = function(extraHeaders = {}, headerMode = REMOTE_REQUEST_HEADER_MODE.ACCESS_TOKEN_ONLY) {
|
|
312
|
+
if (headerMode === REMOTE_REQUEST_HEADER_MODE.APPS_CLIENT && typeof this._getRequestHeaders === "function") {
|
|
313
|
+
return this._getRequestHeaders(extraHeaders);
|
|
314
|
+
}
|
|
315
|
+
|
|
310
316
|
const headers = { ...extraHeaders };
|
|
311
317
|
const authorizationHeader = getAccessTokenHeaderValue.call(this);
|
|
312
318
|
if (authorizationHeader && !headers.Authorization && !headers.authorization) {
|
|
313
319
|
headers.Authorization = authorizationHeader;
|
|
314
320
|
}
|
|
315
321
|
|
|
322
|
+
return headers;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const buildRemoteRequestInit = function(
|
|
326
|
+
payload,
|
|
327
|
+
options = {},
|
|
328
|
+
extraHeaders = {},
|
|
329
|
+
requestOptions = {}
|
|
330
|
+
) {
|
|
331
|
+
const requestPayload = typeof payload === "undefined" ? {} : payload;
|
|
332
|
+
const normalizedFiles = normalizeAppServerFiles(options.files);
|
|
333
|
+
const headers = buildRemoteRequestHeaders.call(
|
|
334
|
+
this,
|
|
335
|
+
extraHeaders,
|
|
336
|
+
requestOptions.headerMode || REMOTE_REQUEST_HEADER_MODE.ACCESS_TOKEN_ONLY
|
|
337
|
+
);
|
|
338
|
+
|
|
316
339
|
if (normalizedFiles.length === 0) {
|
|
317
340
|
headers["Content-Type"] = "application/json";
|
|
318
341
|
return {
|
|
@@ -345,7 +368,12 @@ const buildRemoteRequestInit = function(payload, options = {}, extraHeaders = {}
|
|
|
345
368
|
|
|
346
369
|
const invokeByPlatformProxy = async function(appServerAPIName, payload, options = {}) {
|
|
347
370
|
const endpoint = `/apps/invokeAppServerAPI?appId=${encodeURIComponent(this.appId)}&apiName=${encodeURIComponent(appServerAPIName)}`;
|
|
348
|
-
const response = await fetch(
|
|
371
|
+
const response = await fetch(
|
|
372
|
+
`${this.config.apiBaseUrl}${endpoint}`,
|
|
373
|
+
buildRemoteRequestInit.call(this, payload, options, {}, {
|
|
374
|
+
headerMode: REMOTE_REQUEST_HEADER_MODE.APPS_CLIENT,
|
|
375
|
+
})
|
|
376
|
+
);
|
|
349
377
|
return await unwrapAppServerResponse(response, "[AppServer-PlatformProxy]");
|
|
350
378
|
};
|
|
351
379
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getAppsApiBaseUrl, isBrowser, isBackend, getGlobalOptions } from "../../../utils/index.js";
|
|
2
2
|
|
|
3
3
|
const ACCESS_TOKEN_STORAGE_KEY = "tacoreai_apps_access_token";
|
|
4
|
+
const PREVIEW_APPSERVER_API_KEY_HEADER = "x-tacore-preview-app-server-api-key";
|
|
4
5
|
|
|
5
6
|
const normalizeAccessToken = (value) => {
|
|
6
7
|
if (typeof value !== "string") {
|
|
@@ -44,6 +45,8 @@ const writePersistedAccessToken = (token) => {
|
|
|
44
45
|
}
|
|
45
46
|
};
|
|
46
47
|
|
|
48
|
+
const isBackendPreviewMode = () => isBackend && process.env.TACORE_APPSERVER_PREVIEW_MODE === "true";
|
|
49
|
+
|
|
47
50
|
/**
|
|
48
51
|
* Apps SDK 基类
|
|
49
52
|
* 封装通用的配置管理、Header构建、HTTP请求逻辑
|
|
@@ -178,6 +181,13 @@ export class BaseAppsClient {
|
|
|
178
181
|
|
|
179
182
|
if (isBackend && this.config.tacoreServerInteropAppServerApiKey) {
|
|
180
183
|
headers["x-tacore-server-interop-app-server-api-key"] = this.config.tacoreServerInteropAppServerApiKey;
|
|
184
|
+
} else if (
|
|
185
|
+
isBackendPreviewMode() &&
|
|
186
|
+
!token &&
|
|
187
|
+
this.config.previewAppServerApiKey &&
|
|
188
|
+
!headers[PREVIEW_APPSERVER_API_KEY_HEADER]
|
|
189
|
+
) {
|
|
190
|
+
headers[PREVIEW_APPSERVER_API_KEY_HEADER] = this.config.previewAppServerApiKey;
|
|
181
191
|
}
|
|
182
192
|
|
|
183
193
|
return headers;
|
|
@@ -190,6 +200,14 @@ export class BaseAppsClient {
|
|
|
190
200
|
const url = `${this.config.apiBaseUrl}${endpoint}`;
|
|
191
201
|
const headers = this._getRequestHeaders(options.headers);
|
|
192
202
|
|
|
203
|
+
if (isBackendPreviewMode()) {
|
|
204
|
+
console.log(`[BaseAppsClient Debug][${this.appId}] endpoint="${endpoint}"`, {
|
|
205
|
+
hasAuthorization: Boolean(headers.Authorization || headers.authorization),
|
|
206
|
+
hasInteropHeader: Boolean(headers["x-tacore-server-interop-app-server-api-key"]),
|
|
207
|
+
hasPreviewAppServerApiKeyHeader: Boolean(headers[PREVIEW_APPSERVER_API_KEY_HEADER]),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
193
211
|
const response = await fetch(url, {
|
|
194
212
|
...options,
|
|
195
213
|
headers,
|
|
@@ -276,6 +294,7 @@ export class BaseAppsClient {
|
|
|
276
294
|
getConfig() {
|
|
277
295
|
const config = { ...this.config };
|
|
278
296
|
delete config.accessToken;
|
|
297
|
+
delete config.previewAppServerApiKey;
|
|
279
298
|
return config;
|
|
280
299
|
}
|
|
281
300
|
|