Files
memind/public/assets/page-data-client.js

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);