138 lines
5.2 KiB
JavaScript
138 lines
5.2 KiB
JavaScript
(function (global) {
|
|
'use strict';
|
|
|
|
function normalizeApiBase(apiBase) {
|
|
var base = String(apiBase || '/api').trim() || '/api';
|
|
return base.replace(/\/$/, '');
|
|
}
|
|
|
|
function resolvePageId(options) {
|
|
options = options || {};
|
|
var explicit = options.pageId != null ? String(options.pageId).trim() : '';
|
|
if (explicit && explicit !== 'PLACEHOLDER_PAGE_ID') return explicit;
|
|
if (typeof document !== 'undefined') {
|
|
var meta = document.querySelector('meta[name="mindspace-page-data-page-id"]');
|
|
if (meta && meta.content) {
|
|
var fromMeta = String(meta.content).trim();
|
|
if (fromMeta) return fromMeta;
|
|
}
|
|
}
|
|
if (global.__MINDSPACE_PAGE_DATA__ && global.__MINDSPACE_PAGE_DATA__.pageId) {
|
|
return String(global.__MINDSPACE_PAGE_DATA__.pageId).trim();
|
|
}
|
|
return explicit || null;
|
|
}
|
|
|
|
function buildAuthPath(apiBase, pageId) {
|
|
return normalizeApiBase(apiBase) + '/public/pages/' + encodeURIComponent(String(pageId || '').trim()) + '/data-auth';
|
|
}
|
|
|
|
function buildDataPath(apiBase, pageId, dataset, suffix) {
|
|
var base = normalizeApiBase(apiBase);
|
|
var tail = suffix ? (String(suffix).charAt(0) === '/' ? suffix : '/' + suffix) : '';
|
|
return base + '/public/pages/' + encodeURIComponent(String(pageId || '').trim()) + '/data/' + encodeURIComponent(String(dataset || '').trim()) + tail;
|
|
}
|
|
|
|
function buildAuthHeaders(token) {
|
|
var headers = { accept: 'application/json' };
|
|
if (token) headers['x-page-data-token'] = token;
|
|
return headers;
|
|
}
|
|
|
|
function resolveCaptchaToken(options) {
|
|
options = options || {};
|
|
return options.captchaToken || options.turnstileToken || options.captcha_token || null;
|
|
}
|
|
|
|
async function parseJsonResponse(response) {
|
|
var payload = await response.json().catch(function () { return {}; });
|
|
if (!response.ok) {
|
|
var error = (payload && payload.error) || {};
|
|
var err = new Error(error.message || '页面数据请求失败');
|
|
err.code = error.code || 'page_data_failed';
|
|
err.status = response.status;
|
|
throw err;
|
|
}
|
|
return (payload && payload.data) || payload;
|
|
}
|
|
|
|
function createClient(options) {
|
|
options = options || {};
|
|
var pageId = resolvePageId(options);
|
|
var apiBase = options.apiBase || '/api';
|
|
var fetchImpl = options.fetchImpl || global.fetch;
|
|
var sessionToken = options.token || null;
|
|
if (!pageId) {
|
|
throw new Error('pageId 未配置:请先发布页面,平台会在访问时注入 __MINDSPACE_PAGE_DATA__');
|
|
}
|
|
if (typeof fetchImpl !== 'function') throw new Error('fetch 不可用');
|
|
|
|
async function request(method, path, opts) {
|
|
opts = opts || {};
|
|
var url = new URL(path, global.location ? global.location.origin : 'http://localhost');
|
|
if (opts.query) {
|
|
Object.keys(opts.query).forEach(function (key) {
|
|
var value = opts.query[key];
|
|
if (value == null || value === '') return;
|
|
url.searchParams.set(key, String(value));
|
|
});
|
|
}
|
|
var headers = Object.assign(
|
|
{},
|
|
opts.body ? { 'content-type': 'application/json' } : {},
|
|
opts.auth === false ? { accept: 'application/json' } : buildAuthHeaders(sessionToken),
|
|
opts.extraHeaders || {},
|
|
);
|
|
var response = await fetchImpl(url.toString(), {
|
|
method: method,
|
|
headers: headers,
|
|
credentials: 'include',
|
|
body: opts.body ? JSON.stringify(opts.body) : undefined,
|
|
});
|
|
return parseJsonResponse(response);
|
|
}
|
|
|
|
return {
|
|
get pageId() { return pageId; },
|
|
get token() { return sessionToken; },
|
|
setToken: function (nextToken) { sessionToken = nextToken ? String(nextToken) : null; },
|
|
authenticate: function (password) {
|
|
return request('POST', buildAuthPath(apiBase, pageId), { body: { password: password }, auth: false })
|
|
.then(function (result) {
|
|
if (result && result.token) sessionToken = result.token;
|
|
return result;
|
|
});
|
|
},
|
|
listRows: function (dataset, query) {
|
|
return request('GET', buildDataPath(apiBase, pageId, dataset), { query: query || {} });
|
|
},
|
|
getSchema: function (dataset) {
|
|
return request('GET', buildDataPath(apiBase, pageId, dataset, 'schema'));
|
|
},
|
|
getStats: function (dataset) {
|
|
return request('GET', buildDataPath(apiBase, pageId, dataset, 'stats'));
|
|
},
|
|
insertRow: function (dataset, row, insertOptions) {
|
|
var captchaToken = resolveCaptchaToken(insertOptions);
|
|
return request('POST', buildDataPath(apiBase, pageId, dataset, 'rows'), {
|
|
body: row,
|
|
extraHeaders: captchaToken ? { 'x-page-data-captcha': String(captchaToken) } : {},
|
|
});
|
|
},
|
|
updateRow: function (dataset, rowId, row) {
|
|
return request('PATCH', buildDataPath(apiBase, pageId, dataset, 'rows/' + rowId), { body: row });
|
|
},
|
|
deleteRow: function (dataset, rowId) {
|
|
return request('DELETE', buildDataPath(apiBase, pageId, dataset, 'rows/' + rowId));
|
|
},
|
|
};
|
|
}
|
|
|
|
global.MindSpacePageData = {
|
|
createClient: createClient,
|
|
resolvePageId: resolvePageId,
|
|
buildAuthPath: buildAuthPath,
|
|
buildDataPath: buildDataPath,
|
|
};
|
|
})(typeof window !== 'undefined' ? window : globalThis);
|