// Builds n8n/W4-daily-reconcile.json — the daily full reconciliation workflow. // Single source of truth: shared/effective-grants.js (inlined) + w4-body.js. // Run: node n8n/gen_w4.js const fs = require('fs'); const path = require('path'); const { sharedSource } = require('./inline_shared'); let body = fs.readFileSync(path.join(__dirname, 'w4-body.js'), 'utf8'); body = body.replace('// __SHARED_INLINE__ (replaced by shared/effective-grants.js source at build)', sharedSource()); // n8n API import (POST /api/v1/workflows) strictly validates: node ids must be // UUIDs and top-level must NOT carry pinData (class-validator whitelist). const uuid = () => require('crypto').randomUUID(); const node = (o) => Object.assign({ id: uuid() }, o); const workflow = { name: 'W4 - Daily Full Reconciliation (AList Drift Repair)', nodes: [ node({ parameters: { rule: { interval: [{ field: 'cronExpression', expression: '0 3 * * *' }] } }, name: 'Daily 03:00', type: 'n8n-nodes-base.scheduleTrigger', typeVersion: 1.2, position: [-420, 0] }), node({ parameters: { httpMethod: 'POST', path: 'alist-w4-reconcile', options: {} }, name: 'Manual / Webhook', type: 'n8n-nodes-base.webhook', typeVersion: 2, webhookId: 'alist-w4-reconcile', // required: without it the production URL never registers position: [-420, 240] }), node({ parameters: { jsCode: body }, name: 'Reconcile & Repair (Daily Full)', type: 'n8n-nodes-base.code', typeVersion: 2, position: [0, 120] }) ], connections: { 'Daily 03:00': { main: [[{ node: 'Reconcile & Repair (Daily Full)', type: 'main', index: 0 }]] }, 'Manual / Webhook': { main: [[{ node: 'Reconcile & Repair (Daily Full)', type: 'main', index: 0 }]] } }, settings: { executionOrder: 'v1' } }; fs.writeFileSync(path.join(__dirname, 'W4-daily-reconcile.json'), JSON.stringify(workflow, null, 2) + '\n'); console.log('wrote W4-daily-reconcile.json (' + body.length + ' chars body)');