diff --git a/docz/docs/02-getting-started/01-installation/02-frameworks.md b/docz/docs/02-getting-started/01-installation/02-frameworks.md
index e2d33ea..38e2ab7 100644
--- a/docz/docs/02-getting-started/01-installation/02-frameworks.md
+++ b/docz/docs/02-getting-started/01-installation/02-frameworks.md
@@ -65,7 +65,7 @@ Snyk security tooling may report errors involving "Prototype Pollution":
Prototype Pollution [Medium Severity][https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926]
```
-As noted in the [Snyk report](https://web.archive.org/web/20230920204324/https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
+As noted in the [Snyk report](https://web.archive.org/web/20231129100639/https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
> The issue is resolved in version 0.19.3
diff --git a/docz/docs/02-getting-started/01-installation/03-nodejs.md b/docz/docs/02-getting-started/01-installation/03-nodejs.md
index d1dfd8f..3f02b35 100644
--- a/docz/docs/02-getting-started/01-installation/03-nodejs.md
+++ b/docz/docs/02-getting-started/01-installation/03-nodejs.md
@@ -55,7 +55,7 @@ Snyk security tooling may report errors involving "Prototype Pollution":
Prototype Pollution [Medium Severity][https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926]
```
-As noted in the [Snyk report](https://web.archive.org/web/20230920204324/https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
+As noted in the [Snyk report](https://web.archive.org/web/20231129100639/https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
> The issue is resolved in version 0.19.3
diff --git a/docz/docs/03-demos/08-local/01-file.md b/docz/docs/03-demos/27-local/01-file.md
similarity index 99%
rename from docz/docs/03-demos/08-local/01-file.md
rename to docz/docs/03-demos/27-local/01-file.md
index 723bab7..6d04a9f 100644
--- a/docz/docs/03-demos/08-local/01-file.md
+++ b/docz/docs/03-demos/27-local/01-file.md
@@ -446,7 +446,7 @@ This browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
-| Chrome 119 | 2023-11-04 |
+| Chrome 119 | 2023-11-30 |
Some lesser-used browsers do not support File System Access API:
diff --git a/docz/docs/03-demos/08-local/01-websql.md b/docz/docs/03-demos/27-local/02-websql.md
similarity index 99%
rename from docz/docs/03-demos/08-local/01-websql.md
rename to docz/docs/03-demos/27-local/02-websql.md
index 97af103..5212e69 100644
--- a/docz/docs/03-demos/08-local/01-websql.md
+++ b/docz/docs/03-demos/27-local/02-websql.md
@@ -144,13 +144,13 @@ This workbook is typically exported to the filesystem with `writeFile`[^6].
## Live Demo
-:::note
+:::note Tested Deployments
This browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
-| Chrome 117 | 2023-10-13 |
+| Chrome 119 | 2023-11-30 |
Some lesser-used browsers do not support WebSQL:
diff --git a/docz/docs/03-demos/08-local/03-storageapi.md b/docz/docs/03-demos/27-local/03-storageapi.md
similarity index 99%
rename from docz/docs/03-demos/08-local/03-storageapi.md
rename to docz/docs/03-demos/27-local/03-storageapi.md
index fb5635b..81cdf1c 100644
--- a/docz/docs/03-demos/08-local/03-storageapi.md
+++ b/docz/docs/03-demos/27-local/03-storageapi.md
@@ -14,13 +14,13 @@ This demo covers two common use patterns:
- "Row Objects" shows a simple convention for loading and storing row objects
- "Simple Strings" discusses how to persist and recover a raw Storage
-:::note
+:::note Tested Deployments
Each browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
-| Chrome 116 | 2023-09-17 |
+| Chrome 119 | 2023-11-30 |
| Safari 16.6 | 2023-09-17 |
:::
diff --git a/docz/docs/03-demos/08-local/05-clipboard.md b/docz/docs/03-demos/27-local/05-clipboard.md
similarity index 96%
rename from docz/docs/03-demos/08-local/05-clipboard.md
rename to docz/docs/03-demos/27-local/05-clipboard.md
index 807048b..7b2a0a0 100644
--- a/docz/docs/03-demos/08-local/05-clipboard.md
+++ b/docz/docs/03-demos/27-local/05-clipboard.md
@@ -16,13 +16,13 @@ XLS (both '97-2004 and '95), and SpreadsheetML 2003.
Not all Clipboard APIs offer access to all clipboard types.
-:::note
+:::note Tested Deployments
Each browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
-| Chrome 116 | 2023-09-01 |
+| Chrome 119 | 2023-11-30 |
| Safari 16.6 | 2023-09-01 |
| Brave 1.57 | 2023-09-01 |
diff --git a/docz/docs/03-demos/08-local/09-indexeddb.md b/docz/docs/03-demos/27-local/09-indexeddb.md
similarity index 97%
rename from docz/docs/03-demos/08-local/09-indexeddb.md
rename to docz/docs/03-demos/27-local/09-indexeddb.md
index 633a019..d08bc1f 100644
--- a/docz/docs/03-demos/08-local/09-indexeddb.md
+++ b/docz/docs/03-demos/27-local/09-indexeddb.md
@@ -37,13 +37,14 @@ production sites.
### localForage
-:::note
+:::note Tested Deployments
This demo was last tested in the following environments:
| Browser | Date | `localForage` |
|:------------|:-----------|:--------------|
-| Chrome 117 | 2023-10-18 | 1.10.0 |
+| Chrome 119 | 2023-11-30 | 1.10.0 |
+| Safari 17.0 | 2023-11-30 | 1.10.0 |
:::
@@ -108,13 +109,13 @@ function SheetJSLocalForage() {
### DexieJS
-:::note
+:::note Tested Deployments
This demo was last tested in the following environments:
| Browser | Date | DexieJS |
|:------------|:-----------|:--------|
-| Chrome 117 | 2023-10-18 | 3.2.4 |
+| Chrome 119 | 2023-11-30 | 3.2.4 |
:::
diff --git a/docz/docs/03-demos/08-local/_category_.json b/docz/docs/03-demos/27-local/_category_.json
similarity index 60%
rename from docz/docs/03-demos/08-local/_category_.json
rename to docz/docs/03-demos/27-local/_category_.json
index 3e07617..8516511 100644
--- a/docz/docs/03-demos/08-local/_category_.json
+++ b/docz/docs/03-demos/27-local/_category_.json
@@ -1,4 +1,4 @@
{
"label": "Local Data",
- "position": 8
+ "position": 27
}
\ No newline at end of file
diff --git a/docz/docs/03-demos/08-local/index.md b/docz/docs/03-demos/27-local/index.md
similarity index 100%
rename from docz/docs/03-demos/08-local/index.md
rename to docz/docs/03-demos/27-local/index.md
diff --git a/docz/docs/03-demos/09-cloud/01-salesforce.md b/docz/docs/03-demos/30-cloud/01-salesforce.md
similarity index 93%
rename from docz/docs/03-demos/09-cloud/01-salesforce.md
rename to docz/docs/03-demos/30-cloud/01-salesforce.md
index c95b5cd..6f7e751 100644
--- a/docz/docs/03-demos/09-cloud/01-salesforce.md
+++ b/docz/docs/03-demos/30-cloud/01-salesforce.md
@@ -27,7 +27,7 @@ may require some adjustments. The official documentation should be consulted.
:::
-:::note
+:::note Tested Deployments
This demo was last tested on 2023 September 30 using Lightning API version `58.0`.
@@ -71,6 +71,7 @@ It is recommended to load the library in a callback. For example, the following
```js
import { LightningElement, api } from 'lwc';
import { loadScript } from 'lightning/platformResourceLoader';
+// highlight-next-line
import sheetjs from '@salesforce/resourceUrl/sheetjs';
export default class SheetComponent extends LightningElement {
@@ -96,21 +97,17 @@ export default class SheetComponent extends LightningElement {
### Exporting Data from SF List
-:::note pass
-
-There are many different data types and APIs. This demo uses the deprecated
-`getListUi` function to pull account data.
-
-:::
-
-Using the LWC Wire Service, components receive data in separate events. Exports
-are typically generated in a separate event handler. Component state is normally
-used to handle the timing mismatch.
+Using the LWC Wire Service, components receive data in separate events.[^3]
+Event handlers typically store the updated data in component state, ensuring the
+data is available when a spreadsheet export is requested.
#### Getting Account Data
-The main method to obtain data is `getListUi` and the key for account data is
-`ACCOUNT_OBJECT`:
+This demo uses the deprecated `getListUi` function[^4] to pull account data.
+`getListUi` requires the name of the LWC object (`objectApiName` property) and
+name of the LWC list view (`listViewApiName` property)
+
+The following snippet receives data from the "All Accounts" list view:
```js
import { LightningElement, wire } from 'lwc';
@@ -231,10 +228,10 @@ export default class SheetComponent extends LightningElement {
#### Exporting Data
This is readily exported to a spreadsheet in a callback function. Starting from
-the array of arrays, the SheetJS `aoa_to_sheet` method[^3] generates a SheetJS
-sheet object[^4]. A workbook object[^5] is created with `book_new`[^6] and the
-sheet is added with `book_append_sheet`[^7]. Finally, the SheetJS `writeFile`
-method creates a XLSX file and initiates a download[^8].
+the array of arrays, the SheetJS `aoa_to_sheet` method[^5] generates a SheetJS
+sheet object[^6]. A workbook object[^7] is created with `book_new`[^8] and the
+sheet is added with `book_append_sheet`[^9]. Finally, the SheetJS `writeFile`
+method creates a XLSX file and initiates a download[^10].
```js
@api async download() {
@@ -708,9 +705,11 @@ cell styling, automatic column width calculations, and frozen rows.
[^1]: It is strongly recommended to review the [detailed introduction in the Salesforce documentation](https://developer.salesforce.com/docs/platform/lwc/guide/get-started-introduction.html)
[^2]: The `XLSX` variable is the main global for the SheetJS library. It exposes methods as described in ["API Reference"](/docs/api/)
-[^3]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
-[^4]: See ["Sheet Objects"](/docs/csf/sheet)
-[^5]: See ["Workbook Object"](/docs/csf/book)
-[^6]: See [`book_new` in "Utilities"](/docs/api/utilities/wb)
-[^7]: See [`book_append_sheet` in "Utilities"](/docs/api/utilities/wb)
-[^8]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
\ No newline at end of file
+[^3]: See ["Understand the Wire Service"](https://developer.salesforce.com/docs/platform/lwc/guide/data-wire-service-about.html) in the Salesforce LWC documentation.
+[^4]: See [`getListUI`](https://developer.salesforce.com/docs/platform/lwc/guide/reference-get-list-ui.html) in the Salesforce LWC documentation.
+[^5]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
+[^6]: See ["Sheet Objects"](/docs/csf/sheet)
+[^7]: See ["Workbook Object"](/docs/csf/book)
+[^8]: See [`book_new` in "Utilities"](/docs/api/utilities/wb)
+[^9]: See [`book_append_sheet` in "Utilities"](/docs/api/utilities/wb)
+[^10]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
\ No newline at end of file
diff --git a/docz/docs/03-demos/09-cloud/02-netsuite.md b/docz/docs/03-demos/30-cloud/02-netsuite.md
similarity index 97%
rename from docz/docs/03-demos/09-cloud/02-netsuite.md
rename to docz/docs/03-demos/30-cloud/02-netsuite.md
index dd0d10c..249fabc 100644
--- a/docz/docs/03-demos/09-cloud/02-netsuite.md
+++ b/docz/docs/03-demos/30-cloud/02-netsuite.md
@@ -18,7 +18,7 @@ data from spreadsheets.
This demo explores the SuiteScript scripting features in NetSuite. We'll explore
how to use SheetJS in SuiteScripts for reading and writing files in NetSuite.
-:::note
+:::note Tested Deployments
This demo was verified by NetSuite consultants in the following deployments:
@@ -40,8 +40,8 @@ to the file cabinet and referenced in the `define` call in SuiteScripts.
:::info pass
-SheetJS scripts have been tested against the Rhino engine[^3] and work in both
-SuiteScript 2.0 and SuiteScript 2.1.
+SheetJS scripts have been tested against the Rhino JavaScript engine[^3] and
+work in both SuiteScript 2.0 and SuiteScript 2.1 deployments.
:::
diff --git a/docz/docs/03-demos/09-cloud/11-aws.md b/docz/docs/03-demos/30-cloud/11-aws.md
similarity index 99%
rename from docz/docs/03-demos/09-cloud/11-aws.md
rename to docz/docs/03-demos/30-cloud/11-aws.md
index bf39824..01f602a 100644
--- a/docz/docs/03-demos/09-cloud/11-aws.md
+++ b/docz/docs/03-demos/30-cloud/11-aws.md
@@ -7,7 +7,7 @@ pagination_next: demos/extensions/index
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
-[Amazon Web Services](https://aws.amazon.com/) (AWS) is a Cloud Services
+[Amazon Web Services](https://aws.amazon.com/) (AWS) is a cloud services
platform which includes traditional virtual machine support, "Serverless
Functions" and cloud storage.
@@ -31,7 +31,7 @@ will be available in the future.
:::
-:::note
+:::note Tested Deployments
This demo was last tested on 2023 October 01.
@@ -39,7 +39,7 @@ This demo was last tested on 2023 October 01.
## Lambda Functions
-AWS offers the NodeJS runtime for JavaScript serverless function.[^1]
+AWS offers NodeJS runtimes for running JavaScript serverless functions.[^1]
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
required in Lambda functions. When deploying, the entire `node_modules` folder
diff --git a/docz/docs/03-demos/09-cloud/12-azure.md b/docz/docs/03-demos/30-cloud/12-azure.md
similarity index 94%
rename from docz/docs/03-demos/09-cloud/12-azure.md
rename to docz/docs/03-demos/30-cloud/12-azure.md
index 5cca6b2..9350892 100644
--- a/docz/docs/03-demos/09-cloud/12-azure.md
+++ b/docz/docs/03-demos/30-cloud/12-azure.md
@@ -9,7 +9,7 @@ import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
-[Azure Cloud Services](https://azure.microsoft.com/) is a Cloud Services
+[Azure Cloud Services](https://azure.microsoft.com/) is a cloud services
platform which includes traditional virtual machine support, "Serverless
Functions" and cloud storage.
@@ -33,7 +33,7 @@ will be available in the future.
:::
-:::note
+:::note Tested Deployments
This demo was last tested on 2023 October 06.
@@ -123,13 +123,39 @@ option was not required.
### Reading Data
-Using `@azure/functions`, the handler callback receives a `Request` object. With
-standard JS operations, the file can be pulled into an `ArrayBuffer` object.
+Using `@azure/functions`, the handler callback receives a `Request` object.
+Uploaded files can be pulled into `ArrayBuffer` objects.
+
+Code Snippet (click to show)
+
+This function returns a promise that resolves to an `ArrayBuffer` object:
+
+```js
+const { Blob } = require('buffer');
+
+async function get_file_from_request(request, form_field_name) {
+ /* parse the request body */
+ const formData = await request.formData();
+
+ /* pull the specified field */
+ const file = formData.get(form_field_name);
+
+ /* if a file was submitted, `file` will be a Blob */
+ if(!(file instanceof Blob)) throw new Error(`File is missing!`);
+
+ /* pull data into an ArrayBuffer object */
+ const ab = await file.arrayBuffer();
+ return ab;
+}
+```
+
+
The SheetJS `read` method[^2] can read the `ArrayBuffer` objects and generate
SheetJS workbook objects[^3] which can be processed with other API functions.
-For example, a handler can use `sheet_to_csv`[^4] to generate CSV text:
+For example, a handler can use `sheet_to_csv`[^4] to generate CSV text from
+user-submitted spreadsheets:
```js
const { Blob } = require('buffer');
@@ -143,6 +169,7 @@ app.http('SheetJSAzure', {
const formData = await req.formData();
const f = formData.get("upload");
+ /* if a file was submitted, `f` will be a Blob object */
if(!(f instanceof Blob)) return { status: 400, body: "Must submit a file" };
/* parse file */
diff --git a/docz/docs/03-demos/09-cloud/18-github.md b/docz/docs/03-demos/30-cloud/18-github.md
similarity index 89%
rename from docz/docs/03-demos/09-cloud/18-github.md
rename to docz/docs/03-demos/30-cloud/18-github.md
index b8ebc5e..c61fb00 100644
--- a/docz/docs/03-demos/09-cloud/18-github.md
+++ b/docz/docs/03-demos/30-cloud/18-github.md
@@ -60,17 +60,17 @@ As a project from the company, the entire lifecycle uses GitHub offerings:
- GitHub offers free hosting for Git repositories
- GitHub Actions[^1] infrastructure runs tasks at regular intervals
-- `githubocto/flat`[^2] Action to help fetch data and automate post-processing
-- `flat-postprocessing`[^3] Post-processing helper functions and examples
-- "Flat Viewer"[^4]: Web viewer for structured CSV and JSON data on GitHub
+- `githubocto/flat`[^2] library helps fetch data and automate post-processing
+- `flat-postprocessing`[^3] library provides post-processing helper functions
+- "Flat Viewer"[^4] displays structured CSV and JSON data from Git repositories
:::caution pass
-A GitHub account is required. When the demo was tested, free GitHub accounts had
-no Actions usage limits for public repositories.
+A GitHub account is required. When the demo was last tested, "GitHub Free"
+accounts had no Actions usage limits for public repositories[^5].
-Using private GitHub repositories is not recommended because the Flat Viewer
-cannot access private repositories.
+Private GitHub repositories can be used for processing data, but the Flat Viewer
+will not be able to display private data.
:::
@@ -143,12 +143,12 @@ for more details.
The first argument to the post-processing script is the filename.
-The SheetJS `readFile` method[^5] will read the file and generate a SheetJS
-workbook object[^6]. After extracting the first worksheet, `sheet_to_csv`[^7]
+The SheetJS `readFile` method[^6] will read the file and generate a SheetJS
+workbook object[^7]. After extracting the first worksheet, `sheet_to_csv`[^8]
generates a CSV string.
After generating a CSV string, the string should be written to the filesystem
-using `Deno.writeFileSync`[^8]. By convention, the CSV should preserve the file
+using `Deno.writeFileSync`[^9]. By convention, the CSV should preserve the file
name stem and replace the extension with `.csv`:
{`\
@@ -179,7 +179,7 @@ Deno.writeFileSync(out_file, new TextEncoder().encode(csv));`}
## Complete Example
-:::note
+:::note Tested Deployments
This was last tested by SheetJS users on 2023 September 24 using the GitHub UI.
@@ -321,7 +321,8 @@ jobs:
[^2]: See [`githubocto/flat`](https://github.com/githubocto/flat) repo on GitHub.
[^3]: See [`githubocto/flat-postprocessing`](https://github.com/githubocto/flat-postprocessing) repo on GitHub.
[^4]: The hosted version is available at
-[^5]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
-[^6]: See ["Workbook Object"](/docs/csf/book)
-[^7]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
-[^8]: See [`Deno.writeFileSync`](https://deno.land/api?s=Deno.writeFileSync) in the Deno Runtime APIs documentation.
\ No newline at end of file
+[^5]: See ["About billing for GitHub Actions"](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions) in the GitHub documentation.
+[^6]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
+[^7]: See ["Workbook Object"](/docs/csf/book)
+[^8]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
+[^9]: See [`Deno.writeFileSync`](https://deno.land/api?s=Deno.writeFileSync) in the Deno Runtime APIs documentation.
\ No newline at end of file
diff --git a/docz/docs/03-demos/09-cloud/19-deno.md b/docz/docs/03-demos/30-cloud/19-deno.md
similarity index 95%
rename from docz/docs/03-demos/09-cloud/19-deno.md
rename to docz/docs/03-demos/30-cloud/19-deno.md
index 8eb9005..cab3826 100644
--- a/docz/docs/03-demos/09-cloud/19-deno.md
+++ b/docz/docs/03-demos/30-cloud/19-deno.md
@@ -16,8 +16,8 @@ data from spreadsheets.
This demo covers integration details. We'll explore how to load and use SheetJS
scripts in Deno Deploy functions.
-The ["Demo"](#demo) section includes build a sample service that converts XLSX
-and other types of spreadsheets to HTML tables and CSV rows.
+The ["Demo"](#demo) section builds a sample service that converts XLSX and other
+types of spreadsheets to HTML tables and CSV rows.
:::caution pass
@@ -25,7 +25,7 @@ When the demo was last tested, Deno Deploy required a GitHub account.
:::
-:::note
+:::note Tested Deployments
This demo was last tested by SheetJS users on 2023 October 18.
diff --git a/docz/docs/03-demos/09-cloud/21-gsheet.md b/docz/docs/03-demos/30-cloud/21-gsheet.md
similarity index 95%
rename from docz/docs/03-demos/09-cloud/21-gsheet.md
rename to docz/docs/03-demos/30-cloud/21-gsheet.md
index dd7f49f..ffa781c 100644
--- a/docz/docs/03-demos/09-cloud/21-gsheet.md
+++ b/docz/docs/03-demos/30-cloud/21-gsheet.md
@@ -54,8 +54,8 @@ referenced APIs will be available in the future.
This demo uses the following NodeJS modules:
-- `google-auth-library`[^1] to authenticate with Google APIs
-- `node-google-spreadsheet`[^2] to interact with Google Sheets v4 API
+- `google-auth-library`[^1] simplifies authentication with Google APIs
+- `node-google-spreadsheet`[^2] interacts with Google Sheets v4 API
:::info Initial Setup
@@ -70,7 +70,10 @@ It is strongly recommended to use a service account for Google API operations.
The ["Service Account Setup" section](#service-account-setup) covers how to
create a service account and generate a JSON key file.
-```js title="Authenticate using a JSON key file"
+The generated JSON key file includes `client_email` and `private_key` fields.
+These fields can be used in JWT authentication:
+
+```js title="JWT Authentication using a JSON key file"
import { JWT } from 'google-auth-library'
import { GoogleSpreadsheet } from 'google-spreadsheet';
@@ -331,7 +334,7 @@ At this point `wb` is a SheetJS workbook object[^7].
## Complete Example
-:::note
+:::note Tested Deployments
This demo was last tested on 2023 September 17 using `google-auth-library` for
authentication (`v8.9.0`) and `google-spreadsheet` for API access (`v4.1.0`).
diff --git a/docz/docs/03-demos/09-cloud/22-airtable.md b/docz/docs/03-demos/30-cloud/22-airtable.md
similarity index 57%
rename from docz/docs/03-demos/09-cloud/22-airtable.md
rename to docz/docs/03-demos/30-cloud/22-airtable.md
index 0e0f576..6ed06c5 100644
--- a/docz/docs/03-demos/09-cloud/22-airtable.md
+++ b/docz/docs/03-demos/30-cloud/22-airtable.md
@@ -24,44 +24,85 @@ libraries and appended to a dataset in Airtable
## NodeJS Integration
-Airtable recommends Personal Access Tokens for interacting with their API. When
-fetching data from the API, the result will include an array of row objects that
-can be converted to a worksheet with `XLSX.utils.json_to_sheet`. The API methods
-to write data will accept row objects generated by `XLSX.utils.sheet_to_json`.
+### Installation
-The main module is `airtable` and can be installed with `npm`:
+The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
+required in NodeJS scripts that interact with Airtable.
+
+The Airtable connector module is `airtable` and can be installed with `npm`:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz airtable`}
-To obtain a reference to a table, code needs a [PAT](#personal-access-token),
-the name of the workspace (typically starting with `app`), and the name of the
-desired table (the Excel import typically supports the worksheet name):
+### Authentication
+
+Airtable recommends Personal Access Tokens ("PAT") for interacting with the API.
+
+:::note pass
+
+The ["Personal Access Token"](#personal-access-token) section walks through the
+process of creating a PAT.
+
+:::
+
+The connector constructor accepts an options argument. The PAT should be passed
+using the `apiKey` property:
```js
-const Airtable = require("airtable"), XLSX = require("xlsx");
-/* query all records in a table */
-const conn = new Airtable({apiKey: "PAT...", /* and other options ... */});
-const table = conn.base("app...").table("tablename...");
+const Airtable = require("airtable");
+const apiKey = "PAT..."; // personal access token
+const conn = new Airtable({apiKey, /* see docs for other options ... */});
+```
+
+The `base` method opens a specified workspace. The internal workspace name is
+the first fragment in the Airtable URL, typically starts with "app":
+
+```js
+const base = conn.base("app...");
+```
+
+The `table` method of the workspace object opens a specified table:
+
+```js
+const table = base.table("tablename...");
```
### Exporting Data
When querying data, a result set will be a simple array of Record objects. The
-`fields` property is a simple JS object compatible with `json_to_sheet`:
+`fields` property of each record object is a simple JS object. Mapping over the
+result set and picking the `fields` field yields a standard array of objects:
```js
-/** Create SheetJS worksheet from Airtable table */
-async function airtable_to_worksheet(table) {
+/** Create array of objects from Airtable table */
+async function airtable_to_aoo(table) {
/* get all rows */
const result = await table.select().all();
/* pull raw objects from the result */
// highlight-next-line
const aoo = result.map(r => r.fields);
+ return aoo;
+}
+```
+
+The SheetJS `json_to_sheet` utility function[^1] can generate a worksheet object
+from the array of objects:
+
+```js
+const XLSX = require("xlsx");
+
+/** Create SheetJS worksheet from Airtable table */
+async function airtable_to_worksheet(table) {
+ /* get all rows */
+ const result = await table.select().all();
+
+ /* pull raw objects from the result */
+ const aoo = result.map(r => r.fields);
/* create a worksheet */
+ // highlight-next-line
const worksheet = XLSX.utils.json_to_sheet(aoo);
return worksheet;
}
@@ -74,17 +115,43 @@ for sorting by fields.
:::
-### Importing Data
-
-When inserting records, each object should be wrapped in a parent object with a
-single `fields` property:
+The worksheet object must be added to a new workbook object using the `book_new`
+and `book_append_sheet` helper functions[^2]:
```js
-/** Append records from a SheetJS worksheet to Airtable table */
-async function airtable_load_worksheet(table, worksheet) {
- /* suppose the field names */
- const aoo = XLSX.utils.sheet_to_json(worksheet);
+/** Create SheetJS workbook from Airtable table */
+async function airtable_to_workbook(table) {
+ /* generate worksheet */
+ const ws = await airtable_to_worksheet(table);
+ /* create a new workbook */
+ const wb = XLSX.utils.book_new();
+ /* add worksheet to workbook */
+ XLSX.utils.book_append_sheet(wb, ws, "ExportedData");
+ return wb;
+}
+```
+Local files can be created using the SheetJS `writeFile` method[^3]:
+
+```js
+(async() => {
+ /* generate SheetJS workbook */
+ const wb = await airtable_to_workbook(table);
+ /* write to XLSX */
+ XLSX.writeFile(wb, "SheetJSAirtableExport.xlsx");
+})();
+```
+
+### Importing Data
+
+The Airtable table `create` method expects an array of record objects. The
+`fields` property of each object is expected to contain the raw record data.
+
+Mapping over a standard array of objects can create Airtable-friendly data:
+
+```js
+/** Append records from an array of data objects to Airtable table */
+async function airtable_load_aoo(table, aoo) {
/* reshape to be compatible with Airtable API */
// highlight-next-line
const airtable_rows = aoo.map(fields => ({ fields }));
@@ -94,9 +161,50 @@ async function airtable_load_worksheet(table, worksheet) {
}
```
+Starting from a SheetJS worksheet object[^4], the `sheet_to_json` method[^5] can
+generate normal arrays of objects:
+
+```js
+const XLSX = require("xlsx");
+
+/** Append records from a SheetJS worksheet to Airtable table */
+async function airtable_load_worksheet(table, worksheet) {
+ /* generate normal array of objects */
+ // highlight-next-line
+ const aoo = XLSX.utils.sheet_to_json(worksheet);
+
+ /* upload data */
+ return await airtable_load_aoo(table, aoo);
+}
+```
+
+A SheetJS worksheet object can be extracted from a workbook object[^6]:
+
+```js
+/** Append records from the first worksheet of a workbook to Airtable table */
+async function airtable_load_workbook(table, workbook) {
+ /* pull first worksheet from workbook object */
+ // highlight-next-line
+ const first_sheet_name = workbook.SheetNames[0];
+ const ws = workbook.Sheets[first_sheet_name];
+
+ /* upload data */
+ return await airtable_load_worksheet(table, ws);
+}
+```
+
+Local files can be read using the SheetJS `readFile` method[^7]:
+
+```js
+const wb = XLSX.readFile("SheetJSAirtableTest.xlsb");
+(async() => {
+ await airtable_load_workbook(table, wb);
+});
+```
+
## Complete Example
-:::note
+:::note Tested Deployments
This demo was last tested on 2023 September 03. At the time, free accounts
included limited API access.
@@ -240,4 +348,12 @@ node SheetJSAirtableWrite.js
Open Airtable and verify the new row was added:
-![Final Result in Airtable](pathname:///airtable/post.png)
\ No newline at end of file
+![Final Result in Airtable](pathname:///airtable/post.png)
+
+[^1]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
+[^2]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
+[^3]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
+[^4]: See ["Sheet Objects"](/docs/csf/sheet) for more details/
+[^5]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
+[^6]: See ["Workbook Object"](/docs/csf/book)
+[^7]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
diff --git a/docz/docs/03-demos/09-cloud/31-dropbox.mdx b/docz/docs/03-demos/30-cloud/31-dropbox.mdx
similarity index 97%
rename from docz/docs/03-demos/09-cloud/31-dropbox.mdx
rename to docz/docs/03-demos/30-cloud/31-dropbox.mdx
index 028c225..97263c0 100644
--- a/docz/docs/03-demos/09-cloud/31-dropbox.mdx
+++ b/docz/docs/03-demos/30-cloud/31-dropbox.mdx
@@ -6,7 +6,7 @@ pagination_next: demos/extensions/index
---
-
+
[Dropbox](https://www.dropbox.com/) is a file hosting service that offers APIs
@@ -34,7 +34,7 @@ their Dropbox account. This demo will generate a XLS workbook using SheetJS.
The Dropbox API script is loaded in this page with
```html
-
+
```
The `data-app-key` used in this demo is a "Development" key associated with the
@@ -262,9 +262,9 @@ function SheetJSEnregistrez() {
## Dropbox App
-:::note
+:::note Tested Deployments
-This demo was last tested on 2023 August 26.
+This demo was last tested on 2023 November 30.
:::
diff --git a/docz/docs/03-demos/09-cloud/_category_.json b/docz/docs/03-demos/30-cloud/_category_.json
similarity index 64%
rename from docz/docs/03-demos/09-cloud/_category_.json
rename to docz/docs/03-demos/30-cloud/_category_.json
index 5d81b5a..e0abe14 100644
--- a/docz/docs/03-demos/09-cloud/_category_.json
+++ b/docz/docs/03-demos/30-cloud/_category_.json
@@ -1,4 +1,4 @@
{
"label": "Cloud Platforms",
- "position": 9
+ "position": 30
}
\ No newline at end of file
diff --git a/docz/docs/03-demos/09-cloud/index.md b/docz/docs/03-demos/30-cloud/index.md
similarity index 100%
rename from docz/docs/03-demos/09-cloud/index.md
rename to docz/docs/03-demos/30-cloud/index.md