// Builds n8n/W2-customerproduct-sync.json — the CustomerProduct webhook. // Single source of truth: shared/effective-grants.js (inlined) + w2-body.js. // Run: node n8n/gen_w2.js const fs = require('fs'); const path = require('path'); const { sharedSource } = require('./inline_shared'); let body = fs.readFileSync(path.join(__dirname, 'w2-body.js'), 'utf8'); body = body.replace('// __SHARED_INLINE__ (replaced by shared/effective-grants.js source at build)', sharedSource()); const workflow = { name: 'W2 - CustomerProduct Sync (Effective Grants)', nodes: [ { parameters: { httpMethod: 'POST', path: 'alist-customerproduct-sync', responseMode: 'onReceived', options: {} }, id: 'trigger-webhook', name: 'NocoDB: CustomerProduct Webhook', type: 'n8n-nodes-base.webhook', typeVersion: 2, position: [0, 0], webhookId: 'customerproduct-sync' }, { parameters: { jsCode: "const body = $input.item.json.body ?? $input.item.json;\nconst data = body.data ?? {};\nconst rows = data.rows?.[0] ?? data.rows_new?.[0] ?? data.rows_old?.[0] ?? {};\nconst id = rows.Id ?? data.data?.rows?.[0]?.Id;\nif (!id) throw new Error('no CustomerProduct Id in webhook');\nreturn { json: { customerProductId: Number(id), eventType: body.type ?? '' } };\n" }, id: 'extract-id', name: 'Extract CustomerProduct Id', type: 'n8n-nodes-base.code', typeVersion: 2, position: [220, 0] }, { parameters: { jsCode: "// pass-through env + webhook fields (Code node reads $env reliably only here)\nconst prev = $input.item.json;\nreturn { json: {\n customerProductId: prev.customerProductId,\n eventType: prev.eventType,\n NOCODB_URL: $env.NOCODB_URL,\n NOCODB_TOKEN: $env.NOCODB_TOKEN,\n NOCODB_TABLE_CUSTOMERPRODUCTS: $env.NOCODB_TABLE_CUSTOMERPRODUCTS,\n NOCODB_TABLE_CUSTOMERS: $env.NOCODB_TABLE_CUSTOMERS,\n NOCODB_TABLE_PRODUCTS: $env.NOCODB_TABLE_PRODUCTS,\n NOCODB_TABLE_RESOURCES: $env.NOCODB_TABLE_RESOURCES,\n NOCODB_TABLE_ACCESSGRANTS: $env.NOCODB_TABLE_ACCESSGRANTS,\n NOCODB_LINK_PROD_RESOURCES: $env.NOCODB_LINK_PROD_RESOURCES,\n ALIST_URL: $env.ALIST_URL,\n ALIST_ADMIN_USERNAME: $env.ALIST_ADMIN_USERNAME,\n ALIST_ADMIN_PASSWORD: $env.ALIST_ADMIN_PASSWORD,\n} };\n" }, id: 'load-env', name: 'Load Env', type: 'n8n-nodes-base.code', typeVersion: 2, position: [220, 0] }, { parameters: { jsCode: body }, id: 'compute-apply', name: 'Compute Effective Grants & Apply', type: 'n8n-nodes-base.code', typeVersion: 2, position: [440, 0] }, { parameters: { conditions: { options: { caseSensitive: true, leftValue: '', typeName: 'boolean', ignoreCase: true }, conditions: [ { id: 'cond-skip', leftValue: "={{ $('Compute Effective Grants & Apply').item.json.skipWriteBack }}", rightValue: true, operator: { type: 'boolean', operation: 'equals', singleValue: true, rightType: 'boolean' } } ], combinator: 'and' }, options: {} }, id: 'if-skip', name: 'Skip if no change', type: 'n8n-nodes-base.if', typeVersion: 2, position: [660, 0] }, { parameters: { jsCode: "return { json: { skipped: true, customerId: $('Compute Effective Grants & Apply').item.json.customerId } };" }, id: 'skip-echo', name: 'Skip Echo (No-op)', type: 'n8n-nodes-base.code', typeVersion: 2, position: [660, -200] } ], connections: { 'NocoDB: CustomerProduct Webhook': { main: [[{ node: 'Extract CustomerProduct Id', type: 'main', index: 0 }]] }, 'Extract CustomerProduct Id': { main: [[{ node: 'Load Env', type: 'main', index: 0 }]] }, 'Load Env': { main: [[{ node: 'Compute Effective Grants & Apply', type: 'main', index: 0 }]] }, 'Compute Effective Grants & Apply': { main: [[{ node: 'Skip if no change', type: 'main', index: 0 }]] }, 'Skip if no change': { main: [ [{ node: 'Skip Echo (No-op)', type: 'main', index: 0 }], [] // no-change path terminates silently (nothing to do) ] }, 'Skip Echo (No-op)': { main: [] } }, settings: { executionOrder: 'v1' }, pinData: {} }; fs.writeFileSync(path.join(__dirname, 'W2-customerproduct-sync.json'), JSON.stringify(workflow, null, 2) + '\n'); console.log('wrote W2-customerproduct-sync.json (' + body.length + ' chars body)');