feat(page-data): complete Phase 4-5, ops UI, and publish integration
Add visitor roles, row-level scope, owner ops APIs, MySQL policy index, Turnstile captcha, browser client SDK, publish-panel dataset binding, acceptance tests, and usage documentation. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
buildPageDataAuthPath,
|
||||
buildPageDataPublicPath,
|
||||
createPageDataBrowserClient,
|
||||
} from './page-data-browser-client.mjs';
|
||||
|
||||
test('buildPageDataPublicPath encodes page and dataset segments', () => {
|
||||
assert.equal(
|
||||
buildPageDataPublicPath('/api', 'page 1', 'sign ups', 'rows'),
|
||||
'/api/public/pages/page%201/data/sign%20ups/rows',
|
||||
);
|
||||
assert.equal(buildPageDataAuthPath('/api/', 'page-1'), '/api/public/pages/page-1/data-auth');
|
||||
});
|
||||
|
||||
test('createPageDataBrowserClient sends token header and parses success payload', async () => {
|
||||
const calls = [];
|
||||
const client = createPageDataBrowserClient({
|
||||
pageId: 'page-1',
|
||||
apiBase: '/api',
|
||||
token: 'token-abc',
|
||||
fetchImpl: async (url, init) => {
|
||||
calls.push({ url, init });
|
||||
return {
|
||||
ok: true,
|
||||
async json() {
|
||||
return { data: { rows: [{ id: 1, title: 'A' }] } };
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
const rows = await client.listRows('tasks', { limit: 5 });
|
||||
assert.equal(rows.rows[0].title, 'A');
|
||||
assert.match(calls[0].url, /\/api\/public\/pages\/page-1\/data\/tasks\?limit=5/);
|
||||
assert.equal(calls[0].init.headers['x-page-data-token'], 'token-abc');
|
||||
assert.equal(calls[0].init.credentials, 'include');
|
||||
});
|
||||
|
||||
test('createPageDataBrowserClient authenticate stores returned token', async () => {
|
||||
const client = createPageDataBrowserClient({
|
||||
pageId: 'page-1',
|
||||
fetchImpl: async () => ({
|
||||
ok: true,
|
||||
async json() {
|
||||
return { data: { token: 'fresh-token', expiresAt: Date.now() + 1000 } };
|
||||
},
|
||||
}),
|
||||
});
|
||||
const auth = await client.authenticate('secret-pass');
|
||||
assert.equal(auth.token, 'fresh-token');
|
||||
assert.equal(client.token, 'fresh-token');
|
||||
});
|
||||
|
||||
test('createPageDataBrowserClient insertRow sends captcha header when provided', async () => {
|
||||
const calls = [];
|
||||
const client = createPageDataBrowserClient({
|
||||
pageId: 'page-1',
|
||||
fetchImpl: async (url, init) => {
|
||||
calls.push({ url, init });
|
||||
return {
|
||||
ok: true,
|
||||
async json() {
|
||||
return { data: { row: { id: 1, title: 'A' } } };
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
await client.insertRow('signups', { name: 'A' }, { turnstileToken: 'captcha-123' });
|
||||
assert.equal(calls[0].init.headers['x-page-data-captcha'], 'captcha-123');
|
||||
});
|
||||
Reference in New Issue
Block a user