n8n-nodes-sharepointexcel 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # N8N SharePoint Excel Node
2
+
3
+ An N8N community node that allows you to read Excel tables from SharePoint and perform table lookups.
4
+
5
+ ## Features
6
+
7
+ - **Get Table**: Retrieve all data from a named Excel table in SharePoint
8
+ - **Lookup**: Search for values in a table column and return matching rows
9
+ - **Get Table Names**: List all table names in an Excel file
10
+ - **Multiple Match Types**: Exact match, contains, starts with, ends with
11
+ - **Flexible Output**: Return all matches or just the first one
12
+
13
+ ## Installation
14
+
15
+ ### Via NPM (Recommended)
16
+
17
+ N8N will automatically detect and install this node when you use it in a workflow, or you can install it manually:
18
+
19
+ ```bash
20
+ npm install n8n-nodes-sharepointexcel
21
+ ```
22
+
23
+ ### Manual Installation
24
+
25
+ 1. Install dependencies:
26
+ ```bash
27
+ npm install
28
+ ```
29
+
30
+ 2. Build the node:
31
+ ```bash
32
+ npm run build
33
+ ```
34
+
35
+ 3. Copy the `dist` folder to your N8N custom nodes directory:
36
+ - For Docker: `/home/node/.n8n/custom/`
37
+ - For npm: `~/.n8n/custom/`
38
+
39
+ ## Setup
40
+
41
+ ### Azure AD App Registration
42
+
43
+ 1. Go to [Azure Portal](https://portal.azure.com) → Azure Active Directory → App registrations
44
+ 2. Create a new registration
45
+ 3. Note your **Application (client) ID** and **Directory (tenant) ID**
46
+ 4. Go to "Certificates & secrets" → Create a new client secret
47
+ 5. Go to "API permissions" → Add permissions:
48
+ - Microsoft Graph → Delegated permissions:
49
+ - `Files.Read.All`
50
+ - `Sites.Read.All`
51
+ - Click "Grant admin consent"
52
+
53
+ ### N8N Credentials Setup
54
+
55
+ 1. In N8N, go to Credentials → Add Credential
56
+ 2. Select "SharePoint OAuth2 API"
57
+ 3. Enter your:
58
+ - **Client ID**: Your Azure AD Application ID
59
+ - **Client Secret**: Your Azure AD Client Secret
60
+ - **Tenant ID**: Your Azure AD Tenant ID
61
+ 4. Complete the OAuth2 flow to authorize access
62
+
63
+ ## Usage
64
+
65
+ ### Get Table Names
66
+
67
+ 1. Add the "SharePoint Excel" node to your workflow
68
+ 2. Select operation: "Get Table Names"
69
+ 3. Enter:
70
+ - **SharePoint Site URL**: `https://yourtenant.sharepoint.com/sites/yoursite`
71
+ - **File Path**: `/Shared Documents/MyFile.xlsx`
72
+ 4. Execute to get a list of all table names
73
+
74
+ ### Get Table Data
75
+
76
+ 1. Select operation: "Get Table"
77
+ 2. Enter:
78
+ - **SharePoint Site URL**: Your SharePoint site URL
79
+ - **File Path**: Path to your Excel file
80
+ - **Table Name**: Name of the Excel table (e.g., "Table1")
81
+ 3. Execute to get all rows from the table
82
+
83
+ ### Table Lookup
84
+
85
+ 1. Select operation: "Lookup"
86
+ 2. Enter:
87
+ - **SharePoint Site URL**: Your SharePoint site URL
88
+ - **File Path**: Path to your Excel file
89
+ - **Table Name**: Name of the Excel table
90
+ - **Lookup Column**: Column name to search in
91
+ - **Lookup Value**: Value to search for
92
+ - **Match Type**: How to match (exact, contains, startsWith, endsWith)
93
+ - **Return All Matches**: Whether to return all matches or just the first
94
+ 3. Execute to get matching rows
95
+
96
+ ## Example Workflow
97
+
98
+ ```
99
+ Trigger → SharePoint Excel (Get Table Names) →
100
+ SharePoint Excel (Lookup) → Process Results
101
+ ```
102
+
103
+ ## File Path Format
104
+
105
+ The file path should be relative to the SharePoint site root:
106
+ - `/Shared Documents/MyFile.xlsx`
107
+ - `/Documents/Reports/Data.xlsx`
108
+ - `/SiteAssets/Data/Table.xlsx`
109
+
110
+ ## Excel Table Requirements
111
+
112
+ - The Excel file must contain named tables (created via Insert → Table in Excel)
113
+ - Table names are case-sensitive
114
+ - Column names are taken from the table header row
115
+
116
+ ## Troubleshooting
117
+
118
+ ### "Table not found" error
119
+ - Ensure the table name matches exactly (case-sensitive)
120
+ - Verify the table exists in the Excel file
121
+ - Use "Get Table Names" operation to list available tables
122
+
123
+ ### Authentication errors
124
+ - Verify your Azure AD app has the correct permissions
125
+ - Ensure admin consent has been granted
126
+ - Check that the OAuth2 flow completed successfully
127
+
128
+ ### File not found
129
+ - Verify the file path is correct
130
+ - Ensure the path starts with `/`
131
+ - Check that the file exists in SharePoint
132
+
133
+ ## Development
134
+
135
+ ```bash
136
+ # Build
137
+ npm run build
138
+
139
+ # Watch mode
140
+ npm run dev
141
+
142
+ # Lint
143
+ npm run lint
144
+ ```
145
+
146
+ ## License
147
+
148
+ MIT
@@ -0,0 +1,8 @@
1
+ import { ICredentialType, INodeProperties } from "n8n-workflow";
2
+ export declare class SharePointOAuth2Api implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ extends: string[];
7
+ properties: INodeProperties[];
8
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SharePointOAuth2Api = void 0;
4
+ class SharePointOAuth2Api {
5
+ constructor() {
6
+ this.name = "sharePointOAuth2Api";
7
+ this.displayName = "SharePoint OAuth2 API";
8
+ this.documentationUrl = "https://docs.microsoft.com/en-us/graph/auth/";
9
+ this.extends = ["oAuth2Api"];
10
+ this.properties = [
11
+ {
12
+ displayName: "Grant Type",
13
+ name: "grantType",
14
+ type: "hidden",
15
+ default: "authorizationCode",
16
+ },
17
+ {
18
+ displayName: "Authorization URL",
19
+ name: "authUrl",
20
+ type: "hidden",
21
+ default: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
22
+ },
23
+ {
24
+ displayName: "Access Token URL",
25
+ name: "accessTokenUrl",
26
+ type: "hidden",
27
+ default: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
28
+ },
29
+ {
30
+ displayName: "Scope",
31
+ name: "scope",
32
+ type: "hidden",
33
+ default: "https://graph.microsoft.com/.default",
34
+ },
35
+ {
36
+ displayName: "Auth URI Query Parameters",
37
+ name: "authQueryParameters",
38
+ type: "hidden",
39
+ default: "",
40
+ },
41
+ {
42
+ displayName: "Authentication",
43
+ name: "authentication",
44
+ type: "hidden",
45
+ default: "body",
46
+ },
47
+ ];
48
+ }
49
+ }
50
+ exports.SharePointOAuth2Api = SharePointOAuth2Api;
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
2
+ export declare class SharePointExcel implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,426 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SharePointExcel = void 0;
37
+ const microsoft_graph_client_1 = require("@microsoft/microsoft-graph-client");
38
+ const ExcelJS = __importStar(require("exceljs"));
39
+ class SharePointExcel {
40
+ constructor() {
41
+ this.description = {
42
+ displayName: "SharePoint Excel",
43
+ name: "sharePointExcel",
44
+ icon: "file:sharepoint.svg",
45
+ group: ["transform"],
46
+ version: 1,
47
+ subtitle: '={{$parameter["operation"]}}',
48
+ description: "Read Excel tables from SharePoint and perform table lookups",
49
+ defaults: {
50
+ name: "SharePoint Excel",
51
+ },
52
+ inputs: ["main"],
53
+ outputs: ["main"],
54
+ credentials: [
55
+ {
56
+ name: "sharePointOAuth2Api",
57
+ required: true,
58
+ },
59
+ ],
60
+ properties: [
61
+ {
62
+ displayName: "Operation",
63
+ name: "operation",
64
+ type: "options",
65
+ noDataExpression: true,
66
+ options: [
67
+ {
68
+ name: "Get Table",
69
+ value: "getTable",
70
+ description: "Get all data from an Excel table",
71
+ action: "Get all data from a table",
72
+ },
73
+ {
74
+ name: "Lookup",
75
+ value: "lookup",
76
+ description: "Lookup a value in a table and return matching row(s)",
77
+ action: "Lookup a value in a table",
78
+ },
79
+ {
80
+ name: "Get Table Names",
81
+ value: "getTableNames",
82
+ description: "Get list of table names in the Excel file",
83
+ action: "Get list of table names",
84
+ },
85
+ ],
86
+ default: "getTable",
87
+ },
88
+ {
89
+ displayName: "SharePoint Site URL",
90
+ name: "siteUrl",
91
+ type: "string",
92
+ required: true,
93
+ displayOptions: {
94
+ show: {
95
+ operation: ["getTable", "lookup", "getTableNames"],
96
+ },
97
+ },
98
+ default: "",
99
+ placeholder: "https://yourtenant.sharepoint.com/sites/yoursite",
100
+ description: "The SharePoint site URL where the Excel file is located",
101
+ },
102
+ {
103
+ displayName: "File Path",
104
+ name: "filePath",
105
+ type: "string",
106
+ required: true,
107
+ displayOptions: {
108
+ show: {
109
+ operation: ["getTable", "lookup", "getTableNames"],
110
+ },
111
+ },
112
+ default: "",
113
+ placeholder: "/Shared Documents/MyFile.xlsx",
114
+ description: "The path to the Excel file in SharePoint",
115
+ },
116
+ {
117
+ displayName: "Table Name",
118
+ name: "tableName",
119
+ type: "string",
120
+ required: true,
121
+ displayOptions: {
122
+ show: {
123
+ operation: ["getTable", "lookup"],
124
+ },
125
+ },
126
+ default: "",
127
+ description: "The name of the Excel table to work with",
128
+ },
129
+ {
130
+ displayName: "Lookup Column",
131
+ name: "lookupColumn",
132
+ type: "string",
133
+ required: true,
134
+ displayOptions: {
135
+ show: {
136
+ operation: ["lookup"],
137
+ },
138
+ },
139
+ default: "",
140
+ description: "The column name to search in",
141
+ },
142
+ {
143
+ displayName: "Lookup Value",
144
+ name: "lookupValue",
145
+ type: "string",
146
+ required: true,
147
+ displayOptions: {
148
+ show: {
149
+ operation: ["lookup"],
150
+ },
151
+ },
152
+ default: "",
153
+ description: "The value to search for",
154
+ },
155
+ {
156
+ displayName: "Match Type",
157
+ name: "matchType",
158
+ type: "options",
159
+ displayOptions: {
160
+ show: {
161
+ operation: ["lookup"],
162
+ },
163
+ },
164
+ options: [
165
+ {
166
+ name: "Exact Match",
167
+ value: "exact",
168
+ },
169
+ {
170
+ name: "Contains",
171
+ value: "contains",
172
+ },
173
+ {
174
+ name: "Starts With",
175
+ value: "startsWith",
176
+ },
177
+ {
178
+ name: "Ends With",
179
+ value: "endsWith",
180
+ },
181
+ ],
182
+ default: "exact",
183
+ description: "How to match the lookup value",
184
+ },
185
+ {
186
+ displayName: "Return All Matches",
187
+ name: "returnAll",
188
+ type: "boolean",
189
+ displayOptions: {
190
+ show: {
191
+ operation: ["lookup"],
192
+ },
193
+ },
194
+ default: false,
195
+ description: "Whether to return all matching rows or just the first one",
196
+ },
197
+ ],
198
+ };
199
+ }
200
+ async execute() {
201
+ const items = this.getInputData();
202
+ const returnData = [];
203
+ const nodeInstance = this;
204
+ const operation = this.getNodeParameter("operation", 0);
205
+ // Get credentials
206
+ const credentials = await this.getCredentials("sharePointOAuth2Api");
207
+ // Initialize Microsoft Graph client with access token
208
+ const accessToken = credentials.accessToken;
209
+ const client = microsoft_graph_client_1.Client.init({
210
+ authProvider: (done) => {
211
+ done(null, accessToken);
212
+ },
213
+ });
214
+ // Create helper instance to access private methods
215
+ const helper = new SharePointExcelHelper();
216
+ for (let i = 0; i < items.length; i++) {
217
+ try {
218
+ const siteUrl = this.getNodeParameter("siteUrl", i);
219
+ const filePath = this.getNodeParameter("filePath", i);
220
+ // Get the Excel file from SharePoint
221
+ const fileContent = await helper.downloadExcelFile(client, siteUrl, filePath);
222
+ // Load the workbook
223
+ const workbook = new ExcelJS.Workbook();
224
+ // ExcelJS.load accepts Buffer, ArrayBuffer, or Uint8Array
225
+ // TypeScript 5.9 has strict Buffer types - ExcelJS accepts Buffer at runtime
226
+ // @ts-expect-error - TypeScript 5.9 strict Buffer type checking, but ExcelJS accepts Buffer
227
+ await workbook.xlsx.load(fileContent);
228
+ if (operation === "getTableNames") {
229
+ // Get all table names from all worksheets
230
+ const tableNames = [];
231
+ workbook.eachSheet((worksheet) => {
232
+ const tables = worksheet.tables || [];
233
+ tables.forEach((table) => {
234
+ tableNames.push(table.name);
235
+ });
236
+ });
237
+ returnData.push({
238
+ json: {
239
+ tableNames,
240
+ },
241
+ pairedItem: { item: i },
242
+ });
243
+ }
244
+ else {
245
+ const tableName = this.getNodeParameter("tableName", i);
246
+ // Find the table in the workbook
247
+ let targetTable = null;
248
+ let targetWorksheet = null;
249
+ workbook.eachSheet((worksheet) => {
250
+ const tables = worksheet.tables || [];
251
+ tables.forEach((table) => {
252
+ if (table.name === tableName) {
253
+ targetTable = table;
254
+ targetWorksheet = worksheet;
255
+ }
256
+ });
257
+ });
258
+ if (!targetTable || !targetWorksheet) {
259
+ throw new Error(`Table "${tableName}" not found in the Excel file`);
260
+ }
261
+ if (operation === "getTable") {
262
+ // Get all data from the table
263
+ const tableData = helper.getTableData(targetWorksheet, targetTable);
264
+ returnData.push({
265
+ json: {
266
+ tableName,
267
+ data: tableData,
268
+ },
269
+ pairedItem: { item: i },
270
+ });
271
+ }
272
+ else if (operation === "lookup") {
273
+ // Perform lookup
274
+ const lookupColumn = this.getNodeParameter("lookupColumn", i);
275
+ const lookupValue = this.getNodeParameter("lookupValue", i);
276
+ const matchType = this.getNodeParameter("matchType", i);
277
+ const returnAll = this.getNodeParameter("returnAll", i);
278
+ const tableData = helper.getTableData(targetWorksheet, targetTable);
279
+ const matches = helper.performLookup(tableData, lookupColumn, lookupValue, matchType, returnAll);
280
+ if (returnAll) {
281
+ returnData.push({
282
+ json: {
283
+ tableName,
284
+ lookupColumn,
285
+ lookupValue,
286
+ matches,
287
+ matchCount: matches.length,
288
+ },
289
+ pairedItem: { item: i },
290
+ });
291
+ }
292
+ else {
293
+ // Return each match as a separate item
294
+ matches.forEach((match) => {
295
+ returnData.push({
296
+ json: {
297
+ tableName,
298
+ lookupColumn,
299
+ lookupValue,
300
+ ...match,
301
+ },
302
+ pairedItem: { item: i },
303
+ });
304
+ });
305
+ }
306
+ }
307
+ }
308
+ }
309
+ catch (error) {
310
+ if (this.continueOnFail()) {
311
+ returnData.push({
312
+ json: {
313
+ error: error instanceof Error ? error.message : String(error),
314
+ },
315
+ pairedItem: { item: i },
316
+ });
317
+ continue;
318
+ }
319
+ throw error;
320
+ }
321
+ }
322
+ return [returnData];
323
+ }
324
+ }
325
+ exports.SharePointExcel = SharePointExcel;
326
+ // Helper class to access private methods
327
+ class SharePointExcelHelper {
328
+ async downloadExcelFile(client, siteUrl, filePath) {
329
+ // Extract site ID from URL
330
+ const siteId = await this.getSiteId(client, siteUrl);
331
+ // Get drive ID
332
+ const drive = await client.api(`/sites/${siteId}/drive`).get();
333
+ const driveId = drive.id;
334
+ // Download the file
335
+ const response = await client
336
+ .api(`/sites/${siteId}/drives/${driveId}/root:${filePath}:/content`)
337
+ .getStream();
338
+ // Convert stream to buffer (Node.js environment)
339
+ const chunks = [];
340
+ for await (const chunk of response) {
341
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
342
+ }
343
+ return Buffer.concat(chunks);
344
+ }
345
+ async getSiteId(client, siteUrl) {
346
+ // Extract hostname and path from URL
347
+ const url = new URL(siteUrl);
348
+ const hostname = url.hostname;
349
+ const path = url.pathname;
350
+ // Get site by hostname and path
351
+ const site = await client.api(`/sites/${hostname}:${path}`).get();
352
+ return site.id;
353
+ }
354
+ getTableData(worksheet, table) {
355
+ const data = [];
356
+ // ExcelJS Table range structure
357
+ const range = table.range || {};
358
+ const headerRow = range.top || 1;
359
+ const startRow = (range.top || 1) + 1; // Skip header
360
+ const endRow = range.bottom || worksheet.rowCount;
361
+ const startCol = range.left || 1;
362
+ const endCol = range.right || worksheet.columnCount;
363
+ // Get column names from header row
364
+ const columnNames = [];
365
+ for (let col = startCol; col <= endCol; col++) {
366
+ const cell = worksheet.getCell(headerRow, col);
367
+ columnNames.push(cell.value?.toString() || `Column${col}`);
368
+ }
369
+ // Get data rows
370
+ for (let row = startRow; row <= endRow; row++) {
371
+ const rowData = {};
372
+ for (let col = startCol; col <= endCol; col++) {
373
+ const cell = worksheet.getCell(row, col);
374
+ const columnName = columnNames[col - startCol];
375
+ rowData[columnName] = this.getCellValue(cell);
376
+ }
377
+ data.push(rowData);
378
+ }
379
+ return data;
380
+ }
381
+ getCellValue(cell) {
382
+ if (cell.value === null || cell.value === undefined) {
383
+ return null;
384
+ }
385
+ if (typeof cell.value === "object" && "text" in cell.value) {
386
+ return cell.value.text;
387
+ }
388
+ if (cell.value instanceof Date) {
389
+ return cell.value.toISOString();
390
+ }
391
+ return cell.value;
392
+ }
393
+ performLookup(tableData, lookupColumn, lookupValue, matchType, returnAll) {
394
+ const matches = [];
395
+ for (const row of tableData) {
396
+ const cellValue = row[lookupColumn];
397
+ if (cellValue === null || cellValue === undefined) {
398
+ continue;
399
+ }
400
+ const cellValueStr = String(cellValue).toLowerCase();
401
+ const lookupValueStr = String(lookupValue).toLowerCase();
402
+ let isMatch = false;
403
+ switch (matchType) {
404
+ case "exact":
405
+ isMatch = cellValueStr === lookupValueStr;
406
+ break;
407
+ case "contains":
408
+ isMatch = cellValueStr.includes(lookupValueStr);
409
+ break;
410
+ case "startsWith":
411
+ isMatch = cellValueStr.startsWith(lookupValueStr);
412
+ break;
413
+ case "endsWith":
414
+ isMatch = cellValueStr.endsWith(lookupValueStr);
415
+ break;
416
+ }
417
+ if (isMatch) {
418
+ matches.push(row);
419
+ if (!returnAll && matches.length === 1) {
420
+ break;
421
+ }
422
+ }
423
+ }
424
+ return matches;
425
+ }
426
+ }
@@ -0,0 +1,34 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
2
+ <!-- Excel logo inspired design in blue -->
3
+ <defs>
4
+ <linearGradient id="blueGradient" x1="0%" y1="0%" x2="100%" y2="100%">
5
+ <stop offset="0%" style="stop-color:#2171B5;stop-opacity:1" />
6
+ <stop offset="100%" style="stop-color:#185A9D;stop-opacity:1" />
7
+ </linearGradient>
8
+ </defs>
9
+
10
+ <!-- Main rectangle with folded corner -->
11
+ <path d="M 10 10 L 90 10 L 90 90 L 10 90 Z M 10 10 L 25 10 L 10 25 Z"
12
+ fill="url(#blueGradient)" stroke="#0F4C75" stroke-width="1"/>
13
+
14
+ <!-- Folded corner highlight -->
15
+ <path d="M 10 10 L 25 10 L 10 25 Z" fill="#2E86AB" opacity="0.6"/>
16
+
17
+ <!-- White X on the left side -->
18
+ <text x="20" y="60" font-family="Arial, sans-serif" font-size="45" font-weight="bold" fill="white">X</text>
19
+
20
+ <!-- Grid pattern on the right side -->
21
+ <g fill="none" stroke="white" stroke-width="2.5" stroke-linecap="square">
22
+ <!-- Vertical lines -->
23
+ <line x1="50" y1="20" x2="50" y2="80"/>
24
+ <line x1="65" y1="20" x2="65" y2="80"/>
25
+ <line x1="80" y1="20" x2="80" y2="80"/>
26
+
27
+ <!-- Horizontal lines -->
28
+ <line x1="50" y1="20" x2="80" y2="20"/>
29
+ <line x1="50" y1="35" x2="80" y2="35"/>
30
+ <line x1="50" y1="50" x2="80" y2="50"/>
31
+ <line x1="50" y1="65" x2="80" y2="65"/>
32
+ <line x1="50" y1="80" x2="80" y2="80"/>
33
+ </g>
34
+ </svg>
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "n8n-nodes-sharepointexcel",
3
+ "version": "1.0.0",
4
+ "description": "N8N node for reading Excel tables from SharePoint and performing table lookups",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "n8n-nodes",
9
+ "sharepoint",
10
+ "excel",
11
+ "table",
12
+ "lookup",
13
+ "microsoft-graph"
14
+ ],
15
+ "license": "MIT",
16
+ "engines": {
17
+ "node": ">=18.0.0"
18
+ },
19
+ "scripts": {
20
+ "postinstall": "chmod +x node_modules/.bin/* 2>/dev/null || true",
21
+ "build": "node build.js",
22
+ "build:ts": "node -r typescript/bin/tsc",
23
+ "build:icons": "node -r gulp/bin/gulp.js build:icons",
24
+ "dev": "node -r typescript/bin/tsc --watch",
25
+ "format": "prettier nodes credentials --write",
26
+ "lint": "eslint nodes credentials package.json",
27
+ "lintfix": "eslint nodes credentials package.json --fix",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ],
34
+ "n8n": {
35
+ "n8nNodesApiVersion": 1,
36
+ "nodes": [
37
+ "dist/nodes/SharePointExcel/SharePointExcel.node.js"
38
+ ],
39
+ "credentials": [
40
+ "dist/credentials/SharePointOAuth2Api.credentials.js"
41
+ ]
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^18.15.0",
45
+ "@typescript-eslint/eslint-plugin": "^8.56.0",
46
+ "@typescript-eslint/parser": "^8.56.0",
47
+ "eslint": "^10.0.1",
48
+ "eslint-plugin-n8n-nodes-base": "~1.16.6",
49
+ "gulp": "^5.0.1",
50
+ "n8n-workflow": "*",
51
+ "prettier": "^3.8.1",
52
+ "typescript": "~5.9.3"
53
+ },
54
+ "dependencies": {
55
+ "@microsoft/microsoft-graph-client": "^3.0.7",
56
+ "exceljs": "^4.4.0",
57
+ "n8n-workflow": "*"
58
+ }
59
+ }