feat!: @rudder/sdk 0.1.0: createClient, idempotent modules.call retries, storage save(type, data), drop resources and projectStorage
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
import { vi } from 'vitest';
|
||||
import type { StorageItem } from '../../src/generated/storage.js';
|
||||
import type { ResourceRow } from '../../src/generated/resources.js';
|
||||
import type { CallModuleFunctionClientResponse } from '../../src/generated/modules.js';
|
||||
import type { CatalogCurrency } from '../../src/generated/catalog.js';
|
||||
import type { ProjectStorageItem } from '../../src/generated/project-storage.js';
|
||||
|
||||
export interface RecordedRequest {
|
||||
method: string;
|
||||
@@ -11,14 +9,14 @@ export interface RecordedRequest {
|
||||
query: URLSearchParams;
|
||||
body: unknown;
|
||||
authToken: string | null;
|
||||
headers: Headers;
|
||||
}
|
||||
|
||||
export interface FakeGatewayState {
|
||||
storage: Map<string, StorageItem>;
|
||||
projectStorage: Map<string, ProjectStorageItem>;
|
||||
currencies: CatalogCurrency[];
|
||||
resources: Map<string, Map<string, ResourceRow>>;
|
||||
moduleCalls: CallModuleFunctionClientResponse;
|
||||
/** Response per `module/fn`; falls back to `{ result: {} }`. */
|
||||
moduleCalls: Map<string, CallModuleFunctionClientResponse>;
|
||||
}
|
||||
|
||||
export interface FakeGateway {
|
||||
@@ -39,10 +37,8 @@ const noContent = (): Response => new Response(null, { status: 204 });
|
||||
export function createFakeGateway(seed?: Partial<FakeGatewayState>): FakeGateway {
|
||||
const state: FakeGatewayState = {
|
||||
storage: seed?.storage ?? new Map(),
|
||||
projectStorage: seed?.projectStorage ?? new Map(),
|
||||
currencies: seed?.currencies ?? [],
|
||||
resources: seed?.resources ?? new Map(),
|
||||
moduleCalls: seed?.moduleCalls ?? { result: {} },
|
||||
moduleCalls: seed?.moduleCalls ?? new Map(),
|
||||
};
|
||||
|
||||
const recorded: RecordedRequest[] = [];
|
||||
@@ -72,49 +68,7 @@ export function createFakeGateway(seed?: Partial<FakeGatewayState>): FakeGateway
|
||||
|
||||
const moduleMatch = path.match(/^\/sdk\/v1\/modules\/([^/]+)\/([^/]+)$/);
|
||||
if (method === 'POST' && moduleMatch) {
|
||||
return json(state.moduleCalls);
|
||||
}
|
||||
|
||||
const resourceItemMatch = path.match(/^\/sdk\/v1\/resources\/([^/]+)\/([^/]+)$/);
|
||||
const resourceListMatch = path.match(/^\/sdk\/v1\/resources\/([^/]+)$/);
|
||||
if (resourceItemMatch) {
|
||||
const slug = decodeURIComponent(resourceItemMatch[1]);
|
||||
const id = decodeURIComponent(resourceItemMatch[2]);
|
||||
const rows = state.resources.get(slug) ?? new Map();
|
||||
if (method === 'GET') {
|
||||
const row = rows.get(id);
|
||||
return row ? json(row) : json({ error: 'not found' }, 404);
|
||||
}
|
||||
if (method === 'PATCH') {
|
||||
const existing = rows.get(id);
|
||||
if (!existing) return json({ error: 'not found' }, 404);
|
||||
const next = { ...existing, ...(body as ResourceRow), id };
|
||||
rows.set(id, next);
|
||||
state.resources.set(slug, rows);
|
||||
return json(next);
|
||||
}
|
||||
if (method === 'DELETE') {
|
||||
rows.delete(id);
|
||||
state.resources.set(slug, rows);
|
||||
return noContent();
|
||||
}
|
||||
}
|
||||
if (resourceListMatch) {
|
||||
const slug = decodeURIComponent(resourceListMatch[1]);
|
||||
const rows = state.resources.get(slug) ?? new Map();
|
||||
if (method === 'GET') {
|
||||
return json({ items: [...rows.values()], total: rows.size });
|
||||
}
|
||||
if (method === 'POST') {
|
||||
const created: ResourceRow = {
|
||||
id: (body as ResourceRow).id ?? `row-${rows.size + 1}`,
|
||||
data: (body as ResourceRow).data,
|
||||
version: 1,
|
||||
};
|
||||
rows.set(created.id!, created);
|
||||
state.resources.set(slug, rows);
|
||||
return json(created);
|
||||
}
|
||||
return json(state.moduleCalls.get(`${moduleMatch[1]}/${moduleMatch[2]}`) ?? { result: {} });
|
||||
}
|
||||
|
||||
if (path === '/sdk/v1/storage') {
|
||||
@@ -128,28 +82,14 @@ export function createFakeGateway(seed?: Partial<FakeGatewayState>): FakeGateway
|
||||
if (method === 'PUT') {
|
||||
const items = (body as { items?: StorageItem[] }).items ?? [];
|
||||
for (const item of items) {
|
||||
if (item.id) state.storage.set(item.id, item);
|
||||
if (item.type) state.storage.set(item.type, { id: `id-${item.type}`, ...item });
|
||||
}
|
||||
return noContent();
|
||||
}
|
||||
if (method === 'DELETE') {
|
||||
const type = query.get('type');
|
||||
for (const [id, item] of state.storage) {
|
||||
if (!type || item.type === type) state.storage.delete(id);
|
||||
}
|
||||
return noContent();
|
||||
}
|
||||
}
|
||||
|
||||
if (path === '/sdk/v1/project-storage') {
|
||||
if (method === 'GET') {
|
||||
return json({ items: [...state.projectStorage.values()], nextCursor: '' });
|
||||
}
|
||||
if (method === 'PUT') {
|
||||
const items = (body as { items?: ProjectStorageItem[] }).items ?? [];
|
||||
for (const item of items) {
|
||||
if (item.id) state.projectStorage.set(item.id, item);
|
||||
}
|
||||
if (type) state.storage.delete(type);
|
||||
else state.storage.clear();
|
||||
return noContent();
|
||||
}
|
||||
}
|
||||
@@ -170,6 +110,7 @@ export function createFakeGateway(seed?: Partial<FakeGatewayState>): FakeGateway
|
||||
query: url.searchParams,
|
||||
body: init?.body ? JSON.parse(init.body as string) : undefined,
|
||||
authToken: auth ? auth.replace(/^Bearer\s+/, '') : null,
|
||||
headers,
|
||||
};
|
||||
recorded.push(req);
|
||||
return handle(req);
|
||||
|
||||
Reference in New Issue
Block a user