feat: upgrade multi-flow account contributions
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
(function attachMultiPageContributionRegistry(root, factory) {
|
||||
root.MultiPageContributionRegistry = factory(root);
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createContributionRegistryModule(root) {
|
||||
const flowRegistryApi = root?.MultiPageFlowRegistry || {};
|
||||
const DEFAULT_FLOW_ID = flowRegistryApi.DEFAULT_FLOW_ID || 'openai';
|
||||
const DEFAULT_KIRO_TARGET_ID = flowRegistryApi.DEFAULT_KIRO_TARGET_ID || 'kiro-rs';
|
||||
const DEFAULT_OPENAI_TARGET_ID = flowRegistryApi.DEFAULT_OPENAI_TARGET_ID || 'cpa';
|
||||
|
||||
const ADAPTER_DEFINITIONS = Object.freeze({
|
||||
'openai-oauth': Object.freeze({
|
||||
id: 'openai-oauth',
|
||||
flowId: 'openai',
|
||||
artifactKind: 'openai-oauth',
|
||||
trigger: 'interactive-oauth',
|
||||
label: 'OpenAI OAuth 贡献',
|
||||
defaultTargetId: DEFAULT_OPENAI_TARGET_ID,
|
||||
sensitiveFieldPaths: Object.freeze([
|
||||
'credentials.access_token',
|
||||
'credentials.refresh_token',
|
||||
'credentials.id_token',
|
||||
]),
|
||||
}),
|
||||
'openai-codex-file': Object.freeze({
|
||||
id: 'openai-codex-file',
|
||||
flowId: 'openai',
|
||||
artifactKind: 'codex',
|
||||
trigger: 'manual-upload',
|
||||
label: 'OpenAI Codex 文件贡献',
|
||||
defaultTargetId: 'codex2api',
|
||||
sensitiveFieldPaths: Object.freeze([
|
||||
'credentials.access_token',
|
||||
'credentials.refresh_token',
|
||||
'credentials.id_token',
|
||||
]),
|
||||
}),
|
||||
'openai-sub2api-file': Object.freeze({
|
||||
id: 'openai-sub2api-file',
|
||||
flowId: 'openai',
|
||||
artifactKind: 'sub2api',
|
||||
trigger: 'manual-upload',
|
||||
label: 'OpenAI Sub2API 文件贡献',
|
||||
defaultTargetId: 'sub2api',
|
||||
sensitiveFieldPaths: Object.freeze([
|
||||
'credentials.accounts[].credentials.access_token',
|
||||
'credentials.accounts[].credentials.refresh_token',
|
||||
'credentials.accounts[].credentials.id_token',
|
||||
]),
|
||||
}),
|
||||
'kiro-builder-id': Object.freeze({
|
||||
id: 'kiro-builder-id',
|
||||
flowId: 'kiro',
|
||||
artifactKind: 'kiro-builder-id',
|
||||
trigger: 'after-desktop-authorize',
|
||||
label: 'Kiro Builder ID 贡献',
|
||||
defaultTargetId: DEFAULT_KIRO_TARGET_ID,
|
||||
sensitiveFieldPaths: Object.freeze([
|
||||
'credentials.refreshToken',
|
||||
'credentials.clientSecret',
|
||||
'metadata.proxyPassword',
|
||||
]),
|
||||
}),
|
||||
});
|
||||
|
||||
const FLOW_ADAPTER_IDS = Object.freeze({
|
||||
openai: Object.freeze(['openai-oauth', 'openai-codex-file', 'openai-sub2api-file']),
|
||||
kiro: Object.freeze(['kiro-builder-id']),
|
||||
});
|
||||
|
||||
const CONTRIBUTION_TUTORIAL_ENTRIES = Object.freeze({
|
||||
openai: Object.freeze({
|
||||
id: 'openai-contribution-tutorial',
|
||||
flowId: 'openai',
|
||||
label: '贡献/使用教程',
|
||||
portalPath: '/tutorial',
|
||||
defaultTargetId: DEFAULT_OPENAI_TARGET_ID,
|
||||
contributionAdapterId: 'openai-oauth',
|
||||
action: 'open-portal-and-enable-contribution',
|
||||
}),
|
||||
kiro: Object.freeze({
|
||||
id: 'kiro-contribution-tutorial',
|
||||
flowId: 'kiro',
|
||||
label: '贡献/使用教程',
|
||||
portalPath: '/tutorial',
|
||||
defaultTargetId: DEFAULT_KIRO_TARGET_ID,
|
||||
contributionAdapterId: 'kiro-builder-id',
|
||||
action: 'open-portal-and-enable-contribution',
|
||||
}),
|
||||
});
|
||||
|
||||
function normalizeString(value = '') {
|
||||
return String(value || '').trim();
|
||||
}
|
||||
|
||||
function normalizeFlowId(value = '', fallback = DEFAULT_FLOW_ID) {
|
||||
const normalized = normalizeString(value).toLowerCase();
|
||||
if (normalized && Object.prototype.hasOwnProperty.call(FLOW_ADAPTER_IDS, normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
if (!normalized && typeof flowRegistryApi.normalizeFlowId === 'function') {
|
||||
return flowRegistryApi.normalizeFlowId(value, fallback);
|
||||
}
|
||||
return normalized || normalizeString(fallback).toLowerCase() || DEFAULT_FLOW_ID;
|
||||
}
|
||||
|
||||
function normalizeAdapterId(value = '') {
|
||||
return normalizeString(value).toLowerCase();
|
||||
}
|
||||
|
||||
function normalizeTargetId(flowId = DEFAULT_FLOW_ID, targetId = '') {
|
||||
if (typeof flowRegistryApi.normalizeTargetId === 'function') {
|
||||
return flowRegistryApi.normalizeTargetId(flowId, targetId);
|
||||
}
|
||||
const normalizedFlowId = normalizeFlowId(flowId, DEFAULT_FLOW_ID);
|
||||
const normalizedTargetId = normalizeString(targetId).toLowerCase();
|
||||
if (normalizedTargetId) {
|
||||
return normalizedTargetId;
|
||||
}
|
||||
return normalizedFlowId === 'kiro' ? DEFAULT_KIRO_TARGET_ID : DEFAULT_OPENAI_TARGET_ID;
|
||||
}
|
||||
|
||||
function cloneAdapter(adapter) {
|
||||
if (!adapter) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
...adapter,
|
||||
sensitiveFieldPaths: Array.isArray(adapter.sensitiveFieldPaths)
|
||||
? adapter.sensitiveFieldPaths.slice()
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
function getAdapterDefinition(adapterId = '') {
|
||||
return cloneAdapter(ADAPTER_DEFINITIONS[normalizeAdapterId(adapterId)] || null);
|
||||
}
|
||||
|
||||
function getContributionAdapterIds(flowId = DEFAULT_FLOW_ID) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId, DEFAULT_FLOW_ID);
|
||||
return (FLOW_ADAPTER_IDS[normalizedFlowId] || []).slice();
|
||||
}
|
||||
|
||||
function getContributionAdapters(flowId = DEFAULT_FLOW_ID) {
|
||||
return getContributionAdapterIds(flowId)
|
||||
.map((adapterId) => getAdapterDefinition(adapterId))
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function getDefaultContributionAdapterId(flowId = DEFAULT_FLOW_ID) {
|
||||
return getContributionAdapterIds(flowId)[0] || '';
|
||||
}
|
||||
|
||||
function buildPortalPageUrl(portalBaseUrl = '', portalPath = '/tutorial', params = {}) {
|
||||
const baseUrl = normalizeString(portalBaseUrl).replace(/\/+$/, '') || 'https://flowpilot.qlhazycoder.top';
|
||||
const path = normalizeString(portalPath) || '/tutorial';
|
||||
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
||||
const query = Object.entries(params)
|
||||
.map(([key, value]) => [normalizeString(key), normalizeString(value)])
|
||||
.filter(([key, value]) => key && value)
|
||||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
||||
.join('&');
|
||||
return `${baseUrl}${normalizedPath}${query ? `?${query}` : ''}`;
|
||||
}
|
||||
|
||||
function getContributionTutorialEntry(flowId = DEFAULT_FLOW_ID, options = {}) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId, DEFAULT_FLOW_ID);
|
||||
const definition = CONTRIBUTION_TUTORIAL_ENTRIES[normalizedFlowId] || null;
|
||||
if (!definition) {
|
||||
return null;
|
||||
}
|
||||
const requestedAdapterId = normalizeAdapterId(options.adapterId);
|
||||
const adapterId = requestedAdapterId && hasContributionAdapter(normalizedFlowId, requestedAdapterId)
|
||||
? requestedAdapterId
|
||||
: definition.contributionAdapterId;
|
||||
const targetId = normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
options.targetId || definition.defaultTargetId
|
||||
);
|
||||
return {
|
||||
...definition,
|
||||
targetId,
|
||||
contributionAdapterId: adapterId,
|
||||
portalUrl: buildPortalPageUrl(options.portalBaseUrl, definition.portalPath, {
|
||||
flow: normalizedFlowId,
|
||||
target: targetId,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
function hasContributionAdapter(flowId = DEFAULT_FLOW_ID, adapterId = '') {
|
||||
const normalizedAdapterId = normalizeAdapterId(adapterId);
|
||||
return Boolean(normalizedAdapterId) && getContributionAdapterIds(flowId).includes(normalizedAdapterId);
|
||||
}
|
||||
|
||||
function assertPublishedFlowsHaveContributionAdapters(flowIds = undefined) {
|
||||
const ids = Array.isArray(flowIds)
|
||||
? flowIds
|
||||
: (typeof flowRegistryApi.getRegisteredFlowIds === 'function'
|
||||
? flowRegistryApi.getRegisteredFlowIds()
|
||||
: Object.keys(FLOW_ADAPTER_IDS));
|
||||
const missing = ids
|
||||
.map((flowId) => normalizeString(flowId).toLowerCase())
|
||||
.filter(Boolean)
|
||||
.filter((flowId) => getContributionAdapterIds(flowId).length === 0);
|
||||
if (missing.length) {
|
||||
throw new Error(`缺少账号贡献适配器:${missing.join(', ')}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return {
|
||||
ADAPTER_DEFINITIONS,
|
||||
CONTRIBUTION_TUTORIAL_ENTRIES,
|
||||
FLOW_ADAPTER_IDS,
|
||||
assertPublishedFlowsHaveContributionAdapters,
|
||||
getContributionTutorialEntry,
|
||||
getAdapterDefinition,
|
||||
getContributionAdapterIds,
|
||||
getContributionAdapters,
|
||||
getDefaultContributionAdapterId,
|
||||
hasContributionAdapter,
|
||||
normalizeAdapterId,
|
||||
normalizeFlowId,
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user