Skip to content
Closed
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ CLAUDE.local.md
coverage
example/public/
out
example/tsconfig.e2e.tsbuildinfo
example/tsconfig.e2e.tsbuildinfo
.schema-dumps/
1 change: 1 addition & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ The example app will be available at `http://localhost:3001`.
- `npm test` - Run tests
- `npm run type-check` - Run TypeScript type checking
- `npm run format` - Format code with Prettier
- `npm run dump:schema -- --country=XXX [--form=contract_details] [--version=N|latest]` - Dump a country schema from the sandbox gateway to `.schema-dumps/`
- `npm run size` - Analyze bundle size
- `npm run size:check` - Check if bundle size is within limits
- `npm run size:badge` - Generate badge and history data
Expand Down
32 changes: 16 additions & 16 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
},
"devDependencies": {
"@playwright/test": "1.63.0",
"@remoteoss/remote-json-schema-form-kit": "1.1.2",
"@remoteoss/remote-json-schema-form-kit": "1.1.4",
"@types/node": "24.12.4",
"@types/react-dom": "19.3.0",
"@types/react-syntax-highlighter": "15.5.13",
Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"release": "tsx scripts/release.ts",
"release:fix": "tsx scripts/release-hotfix.ts",
"schema-canary": "tsx scripts/schema-canary.ts",
"dump:schema": "tsx scripts/dump-schema.ts",
"seed:onboarding": "tsx scripts/seed-onboarding.ts",
"size": "tsx scripts/analyze-bundle-size.ts",
"size:check": "tsx scripts/check-size-limits.ts",
Expand Down Expand Up @@ -104,8 +105,8 @@
"@radix-ui/react-scroll-area": "1.2.11",
"@radix-ui/react-select": "2.3.0",
"@radix-ui/react-tabs": "1.1.14",
"@remoteoss/json-schema-form": "^1.2.18",
"@remoteoss/remote-json-schema-form-kit": "1.1.2",
"@remoteoss/json-schema-form": "1.2.19",
"@remoteoss/remote-json-schema-form-kit": "1.1.4",
"@tailwindcss/cli": "4.2.4",
"@tailwindcss/postcss": "4.2.4",
"@tanstack/react-query": "5.104.1",
Expand Down
35 changes: 35 additions & 0 deletions scripts/check-single-schema-form.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#!/usr/bin/env tsx

import { execSync } from 'child_process';
import { readFileSync } from 'fs';
import chalk from 'chalk';

const PACKAGE_NAME = '@remoteoss/json-schema-form';
const KIT_NAME = '@remoteoss/remote-json-schema-form-kit';

type TreeNode = {
version?: string;
Expand All @@ -30,6 +32,35 @@ function readTree(): string {
}
}

type PackageJson = { dependencies?: Record<string, string> };

function readPackageJson(path: string): PackageJson {
return JSON.parse(readFileSync(path, 'utf-8')) as PackageJson;
}

function checkPinMatchesKit(): boolean {
const declared = readPackageJson('package.json').dependencies?.[PACKAGE_NAME];
const required = readPackageJson(`node_modules/${KIT_NAME}/package.json`)
.dependencies?.[PACKAGE_NAME];
const kitFloor = required?.replace(/^[\^~>=\s]+/, '');

if (!declared || !kitFloor || declared === kitFloor) {
return true;
}

console.error(
chalk.red.bold(
`❌ ${PACKAGE_NAME} is declared as ${declared}; it must be pinned to the floor of what ${KIT_NAME} requires (${required})`,
),
);
console.error(
chalk.red(
` Set "${PACKAGE_NAME}": "${kitFloor}" in package.json, then run npm install.`,
),
);
return false;
}

function main(): void {
const output = readTree();
const versions = new Set<string>();
Expand All @@ -49,6 +80,10 @@ function main(): void {
process.exit(1);
}

if (!checkPinMatchesKit()) {
process.exit(1);
}

console.log(
chalk.green(`✅ ${PACKAGE_NAME} resolves to ${[...versions][0]}`),
);
Expand Down
83 changes: 83 additions & 0 deletions scripts/dump-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env tsx
import { mkdirSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import dotenv from 'dotenv';
import { getV1CountriesCountryCodeForm } from '@/src/client';
import { createSandboxClient } from './schema-canary/auth';
import {
archiveEmployment,
seedEmploymentForCountry,
} from './schema-canary/seed-employment';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
dotenv.config({ path: path.resolve(__dirname, '..', '.env.sandbox') });

const args: Record<string, string> = {};
for (const raw of process.argv.slice(2)) {
const match = raw.match(/^--([^=]+)=(.*)$/);
if (match) {
args[match[1]] = match[2];
}
}
const country = args.country?.toUpperCase();
const form = args.form ?? 'contract_details';
const version: number | 'latest' =
args.version === undefined || args.version === 'latest'
? 'latest'
: Number(args.version);
if (version !== 'latest' && !Number.isInteger(version)) {
throw new Error(
`--version must be an integer or 'latest', got ${args.version}`,
);
}
const outDir = args.out ?? path.resolve(__dirname, '..', '.schema-dumps');
if (!country) {
throw new Error('--country=XXX is required');
}

const { VITE_CLIENT_ID, VITE_CLIENT_SECRET, VITE_REFRESH_TOKEN } = process.env;
if (!VITE_CLIENT_ID || !VITE_CLIENT_SECRET || !VITE_REFRESH_TOKEN) {
throw new Error(
'Missing VITE_CLIENT_ID/SECRET/REFRESH_TOKEN in .env.sandbox',
);
}
const client = createSandboxClient(
VITE_CLIENT_ID,
VITE_CLIENT_SECRET,
VITE_REFRESH_TOKEN,
);

let employmentId: string | undefined;
try {
if (form === 'contract_details') {
employmentId = await seedEmploymentForCountry(client, country);
}
const response = await getV1CountriesCountryCodeForm({
client,
headers: { Authorization: '' },
path: { country_code: country, form },
query: {
skip_benefits: true,
...(employmentId ? { employment_id: employmentId } : {}),
json_schema_version: version,
},
});
if (response.error || !response.data) {
throw new Error(`Fetch failed: ${JSON.stringify(response.error)}`);
}
mkdirSync(outDir, { recursive: true });
const file = path.join(outDir, `${country}.${form}.v${version}.json`);
writeFileSync(file, JSON.stringify(response.data.data, null, 2));
console.log(`Wrote ${file}`);
} finally {
if (employmentId) {
try {
await archiveEmployment(client, employmentId);
} catch (error) {
console.warn(
`Failed to archive employment ${employmentId}: ${error instanceof Error ? error.message : String(error)}`,
);
}
}
}
Loading