@saptools/sharepoint-excel 0.1.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,352 @@
1
+ <div align="center">
2
+
3
+ # ๐Ÿ“Š `@saptools/sharepoint-excel`
4
+
5
+ **Safe SharePoint Excel automation for Microsoft Graph app-only integrations.**
6
+
7
+ Create `.xlsx` files, read workbook content, append records, update cells, and add sheets from a focused CLI or typed TypeScript API without overwriting somebody else's SharePoint file by accident.
8
+
9
+ [![npm version](https://img.shields.io/npm/v/@saptools/sharepoint-excel.svg?style=flat&color=CB3837&logo=npm)](https://www.npmjs.com/package/@saptools/sharepoint-excel)
10
+ [![node](https://img.shields.io/node/v/@saptools/sharepoint-excel.svg?style=flat&color=339933&logo=node.js&logoColor=white)](https://nodejs.org)
11
+ [![install size](https://packagephobia.com/badge?p=@saptools/sharepoint-excel)](https://packagephobia.com/result?p=@saptools/sharepoint-excel)
12
+ [![types](https://img.shields.io/npm/types/@saptools/sharepoint-excel.svg?style=flat&color=3178C6&logo=typescript&logoColor=white)](https://www.typescriptlang.org)
13
+
14
+ [Install](#-install) โ€ข [Quick Start](#-quick-start) โ€ข [CLI](#-cli) โ€ข [Security](#-credential-security) โ€ข [API](#-programmatic-usage)
15
+
16
+ </div>
17
+
18
+ ---
19
+
20
+ ## โœจ Features
21
+
22
+ - ๐Ÿ” **Safe local profiles**: stores profile metadata under `~/.saptools/sharepoint-excel/` and keeps `clientSecret` in the OS credential vault by default
23
+ - ๐Ÿงญ **Graph app-only flow**: uses Azure AD client credentials to resolve SharePoint sites and document libraries
24
+ - ๐Ÿงฑ **Local workbook engine**: edits `.xlsx` bytes with `exceljs`, avoiding delegated-only Microsoft Graph workbook endpoints
25
+ - ๐Ÿ›ก๏ธ **No accidental overwrite on create**: refuses to create when the target path already exists
26
+ - ๐Ÿ” **ETag-protected updates**: append/update/add-sheet operations upload with `If-Match` so concurrent SharePoint edits fail fast instead of being silently overwritten
27
+ - ๐Ÿ“– **Workbook reads**: inspect all sheets, a single sheet, or an A1 range
28
+ - โž• **Content mutation**: append JSON objects/rows, update a single cell, and add new sheets with headers
29
+ - ๐Ÿงช **Fake-backed e2e tests**: package tests do not call real Microsoft Graph or SharePoint
30
+ - ๐Ÿงฐ **CLI and typed API**: every CLI action is backed by exported TypeScript functions
31
+
32
+ > [!NOTE]
33
+ > Microsoft Graph's direct Excel workbook APIs are excellent for delegated user flows, but several workbook mutation endpoints do not support application permissions. This package intentionally treats SharePoint as file storage, edits the workbook locally, and uploads the changed `.xlsx` with conflict protection.
34
+
35
+ ---
36
+
37
+ ## ๐Ÿ“ฆ Install
38
+
39
+ ```bash
40
+ # Global CLI
41
+ npm install -g @saptools/sharepoint-excel
42
+
43
+ # Or as a dependency
44
+ npm install @saptools/sharepoint-excel
45
+ # pnpm add @saptools/sharepoint-excel
46
+ # yarn add @saptools/sharepoint-excel
47
+ ```
48
+
49
+ Requires **Node.js >= 20**. The CLI binary is `saptools-sharepoint-excel`.
50
+
51
+ ---
52
+
53
+ ## ๐Ÿš€ Quick Start
54
+
55
+ ```bash
56
+ # 1. Store an app-only SharePoint profile
57
+ saptools-sharepoint-excel config set \
58
+ --tenant "11111111-1111-1111-1111-111111111111" \
59
+ --client-id "22222222-2222-2222-2222-222222222222" \
60
+ --client-secret "<your-client-secret>" \
61
+ --site "contoso.sharepoint.com/sites/demo" \
62
+ --drive "Documents"
63
+
64
+ # 2. Prove auth and target resolution
65
+ saptools-sharepoint-excel test
66
+
67
+ # 3. Create a workbook without overwriting an existing file
68
+ saptools-sharepoint-excel create \
69
+ --path "Reports/orders.xlsx" \
70
+ --sheet "Orders" \
71
+ --headers "Name,Amount,Status" \
72
+ --rows '[{"Name":"Coffee","Amount":3,"Status":"open"}]'
73
+
74
+ # 4. Append one object by matching row 1 headers
75
+ saptools-sharepoint-excel append \
76
+ --path "Reports/orders.xlsx" \
77
+ --sheet "Orders" \
78
+ --record '{"Name":"Tea","Amount":8,"Status":"open"}'
79
+
80
+ # 5. Update one cell
81
+ saptools-sharepoint-excel update-cell \
82
+ --path "Reports/orders.xlsx" \
83
+ --sheet "Orders" \
84
+ --cell "C2" \
85
+ --value '"closed"'
86
+
87
+ # 6. Read workbook JSON
88
+ saptools-sharepoint-excel read --path "Reports/orders.xlsx" --json
89
+ ```
90
+
91
+ For CI, every command can also read credentials from environment variables:
92
+
93
+ ```bash
94
+ export SHAREPOINT_EXCEL_TENANT_ID="11111111-1111-1111-1111-111111111111"
95
+ export SHAREPOINT_EXCEL_CLIENT_ID="22222222-2222-2222-2222-222222222222"
96
+ export SHAREPOINT_EXCEL_CLIENT_SECRET="<your-client-secret>"
97
+ export SHAREPOINT_EXCEL_SITE="contoso.sharepoint.com/sites/demo"
98
+ export SHAREPOINT_EXCEL_DRIVE="Documents"
99
+ ```
100
+
101
+ The CLI also accepts the shorter `SHAREPOINT_TENANT_ID`, `SHAREPOINT_CLIENT_ID`, `SHAREPOINT_CLIENT_SECRET`, `SHAREPOINT_SITE`, and `SHAREPOINT_DRIVE` fallbacks for consistency with `@saptools/sharepoint-check`.
102
+
103
+ ---
104
+
105
+ ## ๐Ÿงฐ CLI
106
+
107
+ ### Common auth flags
108
+
109
+ | Flag | Env | Description |
110
+ | --- | --- | --- |
111
+ | `--profile <name>` | `SHAREPOINT_EXCEL_PROFILE` | Stored profile name; default is `default` |
112
+ | `--tenant <id>` | `SHAREPOINT_EXCEL_TENANT_ID` | Azure AD tenant id |
113
+ | `--client-id <id>` | `SHAREPOINT_EXCEL_CLIENT_ID` | App registration client id |
114
+ | `--client-secret <secret>` | `SHAREPOINT_EXCEL_CLIENT_SECRET` | App registration client secret |
115
+ | `--site <ref>` | `SHAREPOINT_EXCEL_SITE` | SharePoint site, e.g. `contoso.sharepoint.com/sites/demo` |
116
+ | `--drive <nameOrId>` | `SHAREPOINT_EXCEL_DRIVE` | Document library name or id |
117
+ | `--json` | - | Machine-readable output |
118
+
119
+ ### ๐Ÿ” `config set`
120
+
121
+ Store a reusable local profile.
122
+
123
+ ```bash
124
+ saptools-sharepoint-excel config set \
125
+ --profile finance \
126
+ --tenant "$SHAREPOINT_EXCEL_TENANT_ID" \
127
+ --client-id "$SHAREPOINT_EXCEL_CLIENT_ID" \
128
+ --client-secret "$SHAREPOINT_EXCEL_CLIENT_SECRET" \
129
+ --site "contoso.sharepoint.com/sites/finance" \
130
+ --drive "Documents"
131
+ ```
132
+
133
+ By default, the secret goes to the OS credential vault:
134
+
135
+ - macOS: Keychain
136
+ - Windows: Credential Manager
137
+ - Linux: Secret Service-compatible keyring
138
+
139
+ For headless CI containers where an OS keyring is unavailable, an explicit plaintext fallback exists:
140
+
141
+ ```bash
142
+ SAPTOOLS_SHAREPOINT_EXCEL_ALLOW_PLAINTEXT=1 \
143
+ saptools-sharepoint-excel config set --store file --allow-plaintext-secret ...
144
+ ```
145
+
146
+ Use that only in controlled CI environments. The file is written with `0600` permissions under `~/.saptools/sharepoint-excel/secrets.json`.
147
+
148
+ ### ๐Ÿ‘€ `config get`
149
+
150
+ ```bash
151
+ saptools-sharepoint-excel config get --profile finance
152
+ saptools-sharepoint-excel config get --profile finance --json
153
+ ```
154
+
155
+ Secrets are never printed.
156
+
157
+ ### ๐Ÿงน `config remove`
158
+
159
+ ```bash
160
+ saptools-sharepoint-excel config remove --profile finance
161
+ ```
162
+
163
+ Removes both profile metadata and the stored secret.
164
+
165
+ ### โœ… `test`
166
+
167
+ Authenticate, resolve the site, and list document libraries.
168
+
169
+ ```bash
170
+ saptools-sharepoint-excel test
171
+ saptools-sharepoint-excel test --json
172
+ ```
173
+
174
+ ### ๐Ÿ—‚๏ธ `drives`
175
+
176
+ ```bash
177
+ saptools-sharepoint-excel drives
178
+ saptools-sharepoint-excel drives --json
179
+ ```
180
+
181
+ Use this when you are unsure whether the document library is named `Documents`, `Shared Documents`, or something custom.
182
+
183
+ ### ๐Ÿ†• `create`
184
+
185
+ ```bash
186
+ saptools-sharepoint-excel create \
187
+ --path "Reports/orders.xlsx" \
188
+ --sheet "Orders" \
189
+ --headers "Name,Amount,Status" \
190
+ --rows '[{"Name":"Coffee","Amount":3,"Status":"open"}]' \
191
+ --table "OrdersTable"
192
+ ```
193
+
194
+ `create` fails if `Reports/orders.xlsx` already exists.
195
+
196
+ ### ๐Ÿ“– `read`
197
+
198
+ ```bash
199
+ saptools-sharepoint-excel read --path "Reports/orders.xlsx"
200
+ saptools-sharepoint-excel read --path "Reports/orders.xlsx" --sheet "Orders" --range "A1:C10" --json
201
+ ```
202
+
203
+ ### โž• `append`
204
+
205
+ ```bash
206
+ saptools-sharepoint-excel append \
207
+ --path "Reports/orders.xlsx" \
208
+ --sheet "Orders" \
209
+ --record '{"Name":"Tea","Amount":8,"Status":"open"}'
210
+ ```
211
+
212
+ Objects are mapped by the first row's headers by default. Use `--no-match-header` to append object values by their JSON key order instead.
213
+
214
+ ### ๐ŸŽฏ `update-cell`
215
+
216
+ ```bash
217
+ saptools-sharepoint-excel update-cell \
218
+ --path "Reports/orders.xlsx" \
219
+ --sheet "Orders" \
220
+ --cell "B2" \
221
+ --value "42"
222
+ ```
223
+
224
+ `--value` accepts a JSON scalar (`42`, `true`, `null`, `"text"`) or a raw string.
225
+
226
+ ### ๐Ÿ“„ `add-sheet`
227
+
228
+ ```bash
229
+ saptools-sharepoint-excel add-sheet \
230
+ --path "Reports/orders.xlsx" \
231
+ --sheet "Audit" \
232
+ --headers "At,Action,Actor"
233
+ ```
234
+
235
+ Fails if the sheet already exists.
236
+
237
+ ---
238
+
239
+ ## ๐Ÿ” Credential Security
240
+
241
+ `@saptools/sharepoint-excel` handles Microsoft Graph app secrets. Treat them like production credentials.
242
+
243
+ - The CLI never prints `clientSecret`.
244
+ - Default secret storage uses OS-provided credential storage via `@napi-rs/keyring`.
245
+ - Local profile metadata lives under `~/.saptools/sharepoint-excel/profiles.json` with `0600` permissions.
246
+ - Plaintext secret files require explicit opt-in and should only be used in controlled automation.
247
+ - Mutating workbook commands use SharePoint ETags so a stale local download cannot silently replace a newer SharePoint edit.
248
+
249
+ Required Graph application permissions depend on your tenant model. Typical setups use `Sites.Selected` with site-specific grant plus file read/write access, or a broader `Files.ReadWrite.All`/`Sites.ReadWrite.All` policy where your organization permits it.
250
+
251
+ ---
252
+
253
+ ## ๐Ÿง‘โ€๐Ÿ’ป Programmatic Usage
254
+
255
+ ```ts
256
+ import {
257
+ appendRemoteWorkbookRows,
258
+ createRemoteWorkbook,
259
+ openSession,
260
+ parseSiteRef,
261
+ } from "@saptools/sharepoint-excel";
262
+
263
+ const session = await openSession({
264
+ credentials: {
265
+ tenantId: process.env.SHAREPOINT_EXCEL_TENANT_ID ?? "",
266
+ clientId: process.env.SHAREPOINT_EXCEL_CLIENT_ID ?? "",
267
+ clientSecret: process.env.SHAREPOINT_EXCEL_CLIENT_SECRET ?? "",
268
+ },
269
+ site: parseSiteRef("contoso.sharepoint.com/sites/demo"),
270
+ });
271
+
272
+ await createRemoteWorkbook(
273
+ { session, driveHint: "Documents" },
274
+ "Reports/orders.xlsx",
275
+ {
276
+ sheetName: "Orders",
277
+ headers: ["Name", "Amount"],
278
+ rows: [{ Name: "Coffee", Amount: 3 }],
279
+ },
280
+ );
281
+
282
+ await appendRemoteWorkbookRows(
283
+ { session, driveHint: "Documents" },
284
+ "Reports/orders.xlsx",
285
+ "Orders",
286
+ [{ Name: "Tea", Amount: 8 }],
287
+ true,
288
+ );
289
+ ```
290
+
291
+ <details>
292
+ <summary><b>๐Ÿ“š Main exports</b></summary>
293
+
294
+ | Export | Description |
295
+ | --- | --- |
296
+ | `resolveRuntime()` | Resolve flags/env/profile into a SharePoint target |
297
+ | `createProfileStore()` | Read/write redacted local profile metadata |
298
+ | `createKeyringSecretVault()` | OS credential vault adapter |
299
+ | `acquireAppToken()` | Request an app-only Graph token |
300
+ | `createGraphClient()` | Minimal Graph JSON/binary client |
301
+ | `parseSiteRef()` / `resolveSite()` | Parse and resolve SharePoint site references |
302
+ | `listDrives()` / `selectDrive()` | Discover and select document libraries |
303
+ | `createWorkbookBytes()` | Build a local `.xlsx` workbook |
304
+ | `readWorkbookBytes()` | Read sheet rows from workbook bytes |
305
+ | `appendWorkbookRows()` | Append rows in workbook bytes |
306
+ | `updateWorkbookCell()` | Update an A1 cell in workbook bytes |
307
+ | `addWorkbookSheet()` | Add a new worksheet |
308
+ | `createRemoteWorkbook()` | Create SharePoint workbook without overwriting |
309
+ | `readRemoteWorkbook()` | Download and read SharePoint workbook |
310
+ | `appendRemoteWorkbookRows()` | Append rows and upload with ETag protection |
311
+ | `updateRemoteWorkbookCell()` | Update one cell and upload with ETag protection |
312
+ | `addRemoteWorkbookSheet()` | Add a worksheet and upload with ETag protection |
313
+
314
+ </details>
315
+
316
+ ---
317
+
318
+ ## ๐Ÿ› ๏ธ Development
319
+
320
+ From the monorepo root:
321
+
322
+ ```bash
323
+ pnpm install
324
+ pnpm --filter @saptools/sharepoint-excel lint
325
+ pnpm --filter @saptools/sharepoint-excel typecheck
326
+ pnpm --filter @saptools/sharepoint-excel build
327
+ pnpm --filter @saptools/sharepoint-excel test:unit
328
+ pnpm --filter @saptools/sharepoint-excel test:e2e:fake
329
+ ```
330
+
331
+ The e2e suite uses a fake Microsoft Graph server and does not call real SharePoint.
332
+
333
+ ---
334
+
335
+ ## ๐ŸŒ Related
336
+
337
+ - ๐Ÿ”Ž [`@saptools/sharepoint-check`](https://www.npmjs.com/package/@saptools/sharepoint-check) โ€” pre-flight Graph and SharePoint diagnostics
338
+ - ๐Ÿ—‚๏ธ [saptools monorepo](https://github.com/dongitran/saptools) โ€” the full toolbox
339
+
340
+ ---
341
+
342
+ ## ๐Ÿ‘จโ€๐Ÿ’ป Author
343
+
344
+ **dongtran** โœจ
345
+
346
+ ## ๐Ÿ“„ License
347
+
348
+ MIT
349
+
350
+ ---
351
+
352
+ Made with โค๏ธ to make your work life easier!
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ declare function main(argv: readonly string[]): Promise<void>;
2
+
3
+ export { main };