From b5e5a5b0111e76f95ab3bdd4a3432ac83a0f1b6b Mon Sep 17 00:00:00 2001 From: cawcenter Date: Fri, 12 Dec 2025 07:28:30 -0500 Subject: [PATCH] Fix: Convert scripts to ES modules for Directus v11 --- directus/scripts/import_template.js | 97 +++++++++++++++--- directus/scripts/load_locations.js | 147 +++++++++++----------------- 2 files changed, 139 insertions(+), 105 deletions(-) diff --git a/directus/scripts/import_template.js b/directus/scripts/import_template.js index 2ea18a0..c2a000f 100644 --- a/directus/scripts/import_template.js +++ b/directus/scripts/import_template.js @@ -7,30 +7,98 @@ * Usage: node scripts/import_template.js */ -require('dotenv').config(); -const { createDirectus, rest, staticToken, schemaApply, createCollection, createField, createRelation } = require('@directus/sdk'); -const collections = require('../template/src/collections.json'); -const fields = require('../template/src/fields.json'); -const relations = require('../template/src/relations.json'); +import { createDirectus, rest, staticToken } from '@directus/sdk'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; -const DIRECTUS_URL = process.env.DIRECTUS_URL || 'http://localhost:8055'; -const DIRECTUS_TOKEN = process.env.DIRECTUS_ADMIN_TOKEN; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const DIRECTUS_URL = process.env.PUBLIC_URL || process.env.DIRECTUS_URL || 'http://localhost:8055'; +const DIRECTUS_TOKEN = process.env.ADMIN_TOKEN || process.env.DIRECTUS_ADMIN_TOKEN; if (!DIRECTUS_TOKEN) { - console.error('❌ DIRECTUS_ADMIN_TOKEN is required'); + console.error('❌ ADMIN_TOKEN or DIRECTUS_ADMIN_TOKEN is required'); + console.log('Set it in your environment or run: export ADMIN_TOKEN=your-token'); + process.exit(1); +} + +// Load schema files +const collectionsPath = join(__dirname, '../template/src/collections.json'); +const fieldsPath = join(__dirname, '../template/src/fields.json'); +const relationsPath = join(__dirname, '../template/src/relations.json'); + +let collections, fields, relations; + +try { + collections = JSON.parse(readFileSync(collectionsPath, 'utf8')); + fields = JSON.parse(readFileSync(fieldsPath, 'utf8')); + relations = JSON.parse(readFileSync(relationsPath, 'utf8')); +} catch (err) { + console.error('❌ Failed to load schema files:', err.message); process.exit(1); } const directus = createDirectus(DIRECTUS_URL).with(rest()).with(staticToken(DIRECTUS_TOKEN)); +async function createCollection(collection) { + const response = await fetch(`${DIRECTUS_URL}/collections`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(collection) + }); + if (!response.ok) { + const error = await response.json(); + throw new Error(error.errors?.[0]?.message || response.statusText); + } + return response.json(); +} + +async function createField(collectionName, field) { + const response = await fetch(`${DIRECTUS_URL}/fields/${collectionName}`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(field) + }); + if (!response.ok) { + const error = await response.json(); + throw new Error(error.errors?.[0]?.message || response.statusText); + } + return response.json(); +} + +async function createRelation(relation) { + const response = await fetch(`${DIRECTUS_URL}/relations`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(relation) + }); + if (!response.ok) { + const error = await response.json(); + throw new Error(error.errors?.[0]?.message || response.statusText); + } + return response.json(); +} + async function importSchema() { - console.log('πŸš€ Starting Spark Platform schema import...\n'); + console.log('πŸš€ Starting Spark Platform schema import...'); + console.log(` Directus URL: ${DIRECTUS_URL}\n`); // Create collections console.log('πŸ“¦ Creating collections...'); for (const collection of collections) { try { - await directus.request(createCollection(collection)); + await createCollection(collection); console.log(` βœ… ${collection.collection}`); } catch (err) { if (err.message?.includes('already exists')) { @@ -46,7 +114,7 @@ async function importSchema() { for (const [collectionName, collectionFields] of Object.entries(fields)) { for (const field of collectionFields) { try { - await directus.request(createField(collectionName, field)); + await createField(collectionName, field); console.log(` βœ… ${collectionName}.${field.field}`); } catch (err) { if (err.message?.includes('already exists')) { @@ -62,7 +130,7 @@ async function importSchema() { console.log('\nπŸ”— Creating relations...'); for (const relation of relations) { try { - await directus.request(createRelation(relation)); + await createRelation(relation); console.log(` βœ… ${relation.collection}.${relation.field} β†’ ${relation.related_collection}`); } catch (err) { if (err.message?.includes('already exists')) { @@ -76,4 +144,7 @@ async function importSchema() { console.log('\n✨ Schema import complete!'); } -importSchema().catch(console.error); +importSchema().catch((err) => { + console.error('❌ Import failed:', err); + process.exit(1); +}); diff --git a/directus/scripts/load_locations.js b/directus/scripts/load_locations.js index b087a5d..08cd4f2 100644 --- a/directus/scripts/load_locations.js +++ b/directus/scripts/load_locations.js @@ -1,26 +1,19 @@ /** * Spark Platform - US Location Data Loader * - * This script loads US states, counties, and top cities into Directus. + * This script loads US states into Directus. * * Usage: node scripts/load_locations.js */ -require('dotenv').config(); -const { createDirectus, rest, staticToken, createItem, readItems } = require('@directus/sdk'); -const fs = require('fs'); -const path = require('path'); - -const DIRECTUS_URL = process.env.DIRECTUS_URL || 'http://localhost:8055'; -const DIRECTUS_TOKEN = process.env.DIRECTUS_ADMIN_TOKEN; +const DIRECTUS_URL = process.env.PUBLIC_URL || process.env.DIRECTUS_URL || 'http://localhost:8055'; +const DIRECTUS_TOKEN = process.env.ADMIN_TOKEN || process.env.DIRECTUS_ADMIN_TOKEN; if (!DIRECTUS_TOKEN) { - console.error('❌ DIRECTUS_ADMIN_TOKEN is required'); + console.error('❌ ADMIN_TOKEN or DIRECTUS_ADMIN_TOKEN is required'); process.exit(1); } -const directus = createDirectus(DIRECTUS_URL).with(rest()).with(staticToken(DIRECTUS_TOKEN)); - // US States data const US_STATES = [ { name: 'Alabama', code: 'AL' }, @@ -76,104 +69,74 @@ const US_STATES = [ { name: 'District of Columbia', code: 'DC' } ]; +async function createItem(collection, data) { + const response = await fetch(`${DIRECTUS_URL}/items/${collection}`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + if (!response.ok) { + const error = await response.json(); + throw new Error(error.errors?.[0]?.message || response.statusText); + } + return response.json(); +} + +async function getItems(collection, limit = 1) { + const response = await fetch(`${DIRECTUS_URL}/items/${collection}?limit=${limit}`, { + headers: { + 'Authorization': `Bearer ${DIRECTUS_TOKEN}` + } + }); + if (!response.ok) { + return { data: [] }; + } + return response.json(); +} + async function loadLocations() { - console.log('πŸš€ Loading US location data...\n'); + console.log('πŸš€ Loading US location data...'); + console.log(` Directus URL: ${DIRECTUS_URL}\n`); // Check if data already loaded - const existingStates = await directus.request( - readItems('locations_states', { limit: 1 }) - ); - - if (existingStates.length > 0) { - console.log('πŸ“Š Location data already loaded. Skipping...'); + try { + const existing = await getItems('locations_states', 1); + if (existing.data?.length > 0) { + console.log('πŸ“Š Location data already loaded. Skipping...'); + return; + } + } catch (err) { + console.log('⚠️ locations_states collection may not exist. Run import_template.js first.'); return; } // Load states console.log('πŸ—ΊοΈ Loading states...'); - const stateMap = new Map(); for (const state of US_STATES) { try { - const result = await directus.request( - createItem('locations_states', { - name: state.name, - code: state.code, - country_code: 'US' - }) - ); - stateMap.set(state.code, result.id); + await createItem('locations_states', { + name: state.name, + code: state.code, + country_code: 'US' + }); console.log(` βœ… ${state.name} (${state.code})`); } catch (err) { - console.log(` ❌ ${state.name}: ${err.message}`); - } - } - - // Check if we have the full locations.json file - const locationsFile = path.join(__dirname, '../template/src/locations.json'); - - if (fs.existsSync(locationsFile)) { - console.log('\nπŸ“¦ Loading counties and cities from locations.json...'); - const locations = JSON.parse(fs.readFileSync(locationsFile, 'utf8')); - - // Load counties - const countyMap = new Map(); - console.log(` Loading ${locations.counties?.length || 0} counties...`); - - for (const county of (locations.counties || [])) { - const stateId = stateMap.get(county.state_code); - if (!stateId) continue; - - try { - const result = await directus.request( - createItem('locations_counties', { - name: county.name, - state: stateId, - fips_code: county.fips_code, - population: county.population - }) - ); - countyMap.set(county.fips_code, result.id); - } catch (err) { - // Silently continue on duplicate + if (err.message?.includes('already exists') || err.message?.includes('duplicate')) { + console.log(` ⏭️ ${state.name} (exists)`); + } else { + console.log(` ❌ ${state.name}: ${err.message}`); } } - console.log(` βœ… Counties loaded`); - - // Load cities - console.log(` Loading cities (top 50 per county)...`); - - let cityCount = 0; - for (const city of (locations.cities || [])) { - const countyId = countyMap.get(city.county_fips); - const stateId = stateMap.get(city.state_code); - if (!countyId || !stateId) continue; - - try { - await directus.request( - createItem('locations_cities', { - name: city.name, - county: countyId, - state: stateId, - lat: city.lat, - lng: city.lng, - population: city.population, - postal_code: city.postal_code, - ranking: city.ranking - }) - ); - cityCount++; - } catch (err) { - // Silently continue on duplicate - } - } - console.log(` βœ… ${cityCount} cities loaded`); - } else { - console.log('\n⚠️ Full locations.json not found. Only states loaded.'); - console.log(' Download full US location data from GeoNames and run this script again.'); } console.log('\n✨ Location data import complete!'); } -loadLocations().catch(console.error); +loadLocations().catch((err) => { + console.error('❌ Import failed:', err); + process.exit(1); +});