| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- import assert from 'node:assert/strict';
- import test from 'node:test';
- import { ParseRestClient, ParseRestError } from '../src/db/parse-rest.client.js';
- test('Parse REST client keeps the master key server-side and encodes structured queries', async () => {
- const calls: Array<{ url: string; init: RequestInit }> = [];
- const fetchMock: typeof fetch = async (input, init = {}) => {
- calls.push({ url: String(input), init });
- return new Response(JSON.stringify({ results: [] }), {
- status: 200,
- headers: { 'Content-Type': 'application/json' },
- });
- };
- const client = new ParseRestClient({
- serverUrl: 'https://parse.example.test/parse/',
- appId: 'app-id',
- masterKey: 'master-secret',
- }, fetchMock);
- await client.find('VocProduct', {
- where: { workspaceId: 'demashi', platform: 'jd' },
- order: 'productKey',
- limit: 25,
- });
- await client.request('/health', { master: false });
- const queryUrl = new URL(calls[0]!.url);
- assert.equal(queryUrl.pathname, '/parse/classes/VocProduct');
- assert.deepEqual(JSON.parse(queryUrl.searchParams.get('where')!), { workspaceId: 'demashi', platform: 'jd' });
- assert.equal(queryUrl.searchParams.get('order'), 'productKey');
- assert.equal(queryUrl.searchParams.get('limit'), '25');
- assert.equal((calls[0]!.init.headers as Record<string, string>)['X-Parse-Master-Key'], 'master-secret');
- assert.equal((calls[0]!.init.headers as Record<string, string>)['Cache-Control'], 'no-cache, no-store, max-age=0');
- assert.equal((calls[0]!.init.headers as Record<string, string>).Pragma, 'no-cache');
- assert.equal('X-Parse-Master-Key' in (calls[1]!.init.headers as Record<string, string>), false);
- });
- test('Parse REST batch requests stay under the upstream limit and preserve the mount path', async () => {
- let requestBody: { requests: Array<{ path: string }> } | null = null;
- const fetchMock: typeof fetch = async (_input, init = {}) => {
- requestBody = JSON.parse(String(init.body)) as { requests: Array<{ path: string }> };
- return new Response(JSON.stringify([{ success: { objectId: 'one' } }]), {
- status: 200,
- headers: { 'Content-Type': 'application/json' },
- });
- };
- const client = new ParseRestClient({
- serverUrl: 'https://parse.example.test/custom/parse',
- appId: 'app-id',
- masterKey: 'master-secret',
- }, fetchMock);
- await client.batch([{ method: 'POST', path: '/classes/VocWorkspace', body: { publicId: 'demashi' } }]);
- assert.equal(requestBody!.requests[0]!.path, '/custom/parse/classes/VocWorkspace');
- await assert.rejects(
- () => client.batch(Array.from({ length: 51 }, () => ({ method: 'DELETE' as const, path: '/classes/VocProduct/id' }))),
- /limited to 50/,
- );
- });
- test('Parse REST errors expose status and Parse code without returning raw response text', async () => {
- const client = new ParseRestClient({
- serverUrl: 'https://parse.example.test/parse',
- appId: 'app-id',
- masterKey: 'master-secret',
- }, async () => new Response(JSON.stringify({ code: 119, error: 'Permission denied' }), {
- status: 400,
- headers: { 'Content-Type': 'application/json' },
- }));
- await assert.rejects(
- () => client.find('VocWorkspace'),
- (error: unknown) => error instanceof ParseRestError
- && error.status === 400
- && error.code === 119
- && error.message === 'Permission denied',
- );
- });
- test('Parse REST schema writes retry without required flags for older managed servers', async () => {
- const bodies: Array<{
- fields: Record<string, { type: string; required?: boolean }>;
- indexes?: Record<string, Record<string, number>>;
- }> = [];
- const client = new ParseRestClient({
- serverUrl: 'https://parse.example.test/parse',
- appId: 'app-id',
- masterKey: 'master-secret',
- }, async (_input, init = {}) => {
- bodies.push(JSON.parse(String(init.body)) as {
- fields: Record<string, { type: string; required?: boolean }>;
- indexes?: Record<string, Record<string, number>>;
- });
- if (bodies.length === 1) {
- return new Response(JSON.stringify({ error: 'unauthorized' }), {
- status: 403,
- headers: { 'Content-Type': 'application/json' },
- });
- }
- return new Response(JSON.stringify({ className: 'VocWorkspace' }), {
- status: 200,
- headers: { 'Content-Type': 'application/json' },
- });
- });
- await client.createSchema({
- className: 'VocWorkspace',
- fields: {
- publicId: { type: 'String', required: true },
- name: { type: 'String', required: false },
- },
- indexes: { voc_workspace_publicid_idx: { publicId: 1 } },
- });
- assert.equal(bodies.length, 2);
- assert.equal(bodies[0]!.fields.publicId!.required, true);
- assert.equal('required' in bodies[1]!.fields.publicId!, false);
- assert.equal('required' in bodies[1]!.fields.name!, false);
- assert.deepEqual(bodies[1]!.indexes, { voc_workspace_publicid_idx: { publicId: 1 } });
- });
- test('Parse REST schema index updates use the managed schema endpoint', async () => {
- let request: { url: string; method: string | undefined; body: string | undefined } | null = null;
- const client = new ParseRestClient({
- serverUrl: 'https://parse.example.test/parse',
- appId: 'app-id',
- masterKey: 'master-secret',
- }, async (input, init = {}) => {
- request = { url: String(input), method: init.method, body: String(init.body) };
- return new Response(JSON.stringify({ className: 'VocProduct' }), {
- status: 200,
- headers: { 'Content-Type': 'application/json' },
- });
- });
- await client.addSchemaIndexes('VocProduct', {
- voc_product_naturalkey_idx: { naturalKey: 1 },
- });
- assert.equal(request!.url, 'https://parse.example.test/parse/schemas/VocProduct');
- assert.equal(request!.method, 'PUT');
- assert.deepEqual(JSON.parse(request!.body!), {
- indexes: { voc_product_naturalkey_idx: { naturalKey: 1 } },
- });
- });
- test('Parse REST class requests retry transient master authorization drift', async () => {
- let attempts = 0;
- const client = new ParseRestClient({
- serverUrl: 'https://parse.example.test/parse',
- appId: 'app-id',
- masterKey: 'master-secret',
- }, async () => {
- attempts += 1;
- if (attempts < 3) {
- return new Response(JSON.stringify({ error: 'unauthorized' }), {
- status: 403,
- headers: { 'Content-Type': 'application/json' },
- });
- }
- return new Response(JSON.stringify({ results: [], count: 0 }), {
- status: 200,
- headers: { 'Content-Type': 'application/json' },
- });
- });
- const result = await client.find('VocWorkspace', { count: true });
- assert.equal(attempts, 3);
- assert.equal(result.count, 0);
- });
|