6b0c633a75
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>
72 lines
2.3 KiB
JavaScript
72 lines
2.3 KiB
JavaScript
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');
|
|
});
|