Add prebuild script to fetch event kinds from nostr library
- Add scripts/fetch-kinds.js to fetch kinds.json from central source - Add event-kinds.ts with TypeScript types and 184 event kinds - Update package.json build scripts to fetch kinds before building - Source: https://git.mleku.dev/mleku/nostr/raw/branch/main/encoders/kind/kinds.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,10 +15,11 @@
|
||||
"clean:firefox": "rimraf dist/firefox",
|
||||
"start:chrome": "ng serve chrome",
|
||||
"start:firefox": "ng serve firefox",
|
||||
"fetch-kinds": "node scripts/fetch-kinds.js",
|
||||
"prepare:chrome": "./chrome_prepare_manifest.sh",
|
||||
"prepare:firefox": "./firefox_prepare_manifest.sh",
|
||||
"build:chrome": "npm run prepare:chrome && ng build chrome",
|
||||
"build:firefox": "npm run prepare:firefox && ng build firefox",
|
||||
"build:chrome": "npm run fetch-kinds && npm run prepare:chrome && ng build chrome",
|
||||
"build:firefox": "npm run fetch-kinds && npm run prepare:firefox && ng build firefox",
|
||||
"watch:chrome": "npm run prepare:chrome && ng build chrome --watch --configuration development",
|
||||
"watch:firefox": "npm run prepare:firefox && ng build firefox --watch --configuration development",
|
||||
"test": "ng test",
|
||||
|
||||
1756
projects/common/src/lib/constants/event-kinds.ts
Normal file
1756
projects/common/src/lib/constants/event-kinds.ts
Normal file
File diff suppressed because it is too large
Load Diff
147
scripts/fetch-kinds.js
Normal file
147
scripts/fetch-kinds.js
Normal file
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Fetches kinds.json from the nostr library and generates TypeScript definitions
|
||||
* Run: node scripts/fetch-kinds.js
|
||||
*/
|
||||
|
||||
import { writeFileSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const KINDS_URL = 'https://git.mleku.dev/mleku/nostr/raw/branch/main/encoders/kind/kinds.json';
|
||||
|
||||
async function fetchKinds() {
|
||||
console.log(`Fetching kinds from ${KINDS_URL}...`);
|
||||
|
||||
const response = await fetch(KINDS_URL);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch kinds.json: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log(`Fetched ${Object.keys(data.kinds).length} kinds (version: ${data.version})`);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function generateTypeScript(data) {
|
||||
const kinds = [];
|
||||
|
||||
for (const [kindNum, info] of Object.entries(data.kinds)) {
|
||||
const k = parseInt(kindNum, 10);
|
||||
|
||||
// Determine classification
|
||||
let classification = 'regular';
|
||||
if (info.classification) {
|
||||
classification = info.classification;
|
||||
} else if (k === 0 || k === 3 || (k >= data.ranges.replaceable.start && k < data.ranges.replaceable.end)) {
|
||||
classification = 'replaceable';
|
||||
} else if (k >= data.ranges.parameterized.start && k <= data.ranges.parameterized.end) {
|
||||
classification = 'parameterized';
|
||||
} else if (k >= data.ranges.ephemeral.start && k < data.ranges.ephemeral.end) {
|
||||
classification = 'ephemeral';
|
||||
}
|
||||
|
||||
kinds.push({
|
||||
kind: k,
|
||||
name: info.name,
|
||||
description: info.description,
|
||||
nip: info.nip || null,
|
||||
classification,
|
||||
deprecated: info.deprecated || false,
|
||||
spec: info.spec || null
|
||||
});
|
||||
}
|
||||
|
||||
// Sort by kind number
|
||||
kinds.sort((a, b) => a.kind - b.kind);
|
||||
|
||||
return `/**
|
||||
* Nostr Event Kinds Database
|
||||
* Auto-generated from ${KINDS_URL}
|
||||
* Version: ${data.version}
|
||||
* Source: ${data.source}
|
||||
*
|
||||
* DO NOT EDIT - This file is auto-generated by scripts/fetch-kinds.js
|
||||
*/
|
||||
|
||||
export interface KindInfo {
|
||||
kind: number;
|
||||
name: string;
|
||||
description: string;
|
||||
nip: string | null;
|
||||
classification: 'regular' | 'replaceable' | 'ephemeral' | 'parameterized';
|
||||
deprecated: boolean;
|
||||
spec: string | null;
|
||||
}
|
||||
|
||||
export interface KindRanges {
|
||||
regular: { start: number; end: number; description: string };
|
||||
replaceable: { start: number; end: number; description: string };
|
||||
ephemeral: { start: number; end: number; description: string };
|
||||
parameterized: { start: number; end: number; description: string };
|
||||
}
|
||||
|
||||
export const EVENT_KINDS: KindInfo[] = ${JSON.stringify(kinds, null, 2)};
|
||||
|
||||
export const KIND_RANGES: KindRanges = ${JSON.stringify(data.ranges, null, 2)};
|
||||
|
||||
export const PRIVILEGED_KINDS: number[] = ${JSON.stringify(data.privileged)};
|
||||
|
||||
export const DIRECTORY_KINDS: number[] = ${JSON.stringify(data.directory)};
|
||||
|
||||
export const KIND_ALIASES: Record<string, number> = ${JSON.stringify(data.aliases, null, 2)};
|
||||
|
||||
// Lookup map for fast access
|
||||
const kindMap = new Map<number, KindInfo>(EVENT_KINDS.map(k => [k.kind, k]));
|
||||
|
||||
export function getKindInfo(kind: number): KindInfo | undefined {
|
||||
return kindMap.get(kind);
|
||||
}
|
||||
|
||||
export function getKindName(kind: number): string {
|
||||
const info = kindMap.get(kind);
|
||||
return info ? info.name : \`Kind \${kind}\`;
|
||||
}
|
||||
|
||||
export function isReplaceable(kind: number): boolean {
|
||||
if (kind === 0 || kind === 3) return true;
|
||||
return kind >= KIND_RANGES.replaceable.start && kind < KIND_RANGES.replaceable.end;
|
||||
}
|
||||
|
||||
export function isEphemeral(kind: number): boolean {
|
||||
return kind >= KIND_RANGES.ephemeral.start && kind < KIND_RANGES.ephemeral.end;
|
||||
}
|
||||
|
||||
export function isParameterized(kind: number): boolean {
|
||||
return kind >= KIND_RANGES.parameterized.start && kind <= KIND_RANGES.parameterized.end;
|
||||
}
|
||||
|
||||
export function isPrivileged(kind: number): boolean {
|
||||
return PRIVILEGED_KINDS.includes(kind);
|
||||
}
|
||||
|
||||
export function isDirectoryKind(kind: number): boolean {
|
||||
return DIRECTORY_KINDS.includes(kind);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const data = await fetchKinds();
|
||||
const ts = generateTypeScript(data);
|
||||
|
||||
// Write to common library
|
||||
const outPath = join(__dirname, '..', 'projects', 'common', 'src', 'lib', 'constants', 'event-kinds.ts');
|
||||
|
||||
writeFileSync(outPath, ts);
|
||||
console.log(`Generated ${outPath} with ${Object.keys(data.kinds).length} kinds`);
|
||||
} catch (error) {
|
||||
console.error('Error:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user