diff --git a/docz/docs/03-demos/04-static/01-lume.md b/docz/docs/03-demos/04-static/01-lume.md
index ffab21a..97b1842 100644
--- a/docz/docs/03-demos/04-static/01-lume.md
+++ b/docz/docs/03-demos/04-static/01-lume.md
@@ -129,7 +129,7 @@ site.use(sheets({
:::note
-This demo was last tested against `lume v1.17.5` on 2023 June 25.
+This demo was last tested against `lume v1.19.1` on 2023 October 14.
This example uses the Nunjucks template format. Lume plugins support additional
template formats, including Markdown and JSX.
@@ -195,7 +195,7 @@ page will show the contents of the spreadsheet.
5) While the server is still running, open `_data/pres.xlsx` in a spreadsheet
editor and add a new row at the bottom of the sheet.
-The page will refresh and show the new contents.
+After saving the spreadsheet, the page will refresh and show the new contents.
### Static Site
diff --git a/docz/docs/03-demos/06-desktop/06-reactnative.md b/docz/docs/03-demos/06-desktop/06-reactnative.md
index c4ab3e9..9c55954 100644
--- a/docz/docs/03-demos/06-desktop/06-reactnative.md
+++ b/docz/docs/03-demos/06-desktop/06-reactnative.md
@@ -47,7 +47,7 @@ This demo was tested in the following environments:
| OS and Version | Arch | RN Platform | Date |
|:---------------|:-----|:------------|:-----------|
| Windows 10 | x64 | `v0.71.25` | 2023-07-24 |
-| Windows 11 | x64 | `v0.71.11` | 2023-05-11 |
+| Windows 11 | x64 | `v0.72.12` | 2023-10-14 |
| Windows 11 | ARM | `v0.72.9` | 2023-09-18 |
| MacOS 12.6 | x64 | `v0.71.26` | 2023-07-23 |
| MacOS 13.5.2 | ARM | `v0.72.4` | 2023-09-18 |
@@ -394,16 +394,30 @@ been tested against both application types.
:::
-0) Follow the ["Getting Started" guide](https://microsoft.github.io/react-native-windows/docs/getting-started)
+0) Install the [development dependencies](https://microsoft.github.io/react-native-windows/docs/rnw-dependencies).
:::caution pass
-At the time of testing, NodeJS `v16` was required. A tool like
+In earlier versions of React Native, NodeJS `v16` was required. A tool like
[`nvm-windows`](https://github.com/coreybutler/nvm-windows/releases) should be
used to switch the NodeJS version.
:::
+Installation Notes (click to show)
+
+When the demo was last tested, a PowerShell script installed dependencies:
+
+```powershell
+Set-ExecutionPolicy Unrestricted -Scope Process -Force;
+iex (New-Object System.Net.WebClient).DownloadString('https://aka.ms/rnw-vs2022-deps.ps1');
+```
+
+If any step fails to install, open the dependencies page and expand "Manual
+setup instructions" to find instructions for manual installation.
+
+
+
### Project Setup
1) Create a new project using React Native `0.72`:
@@ -578,7 +592,7 @@ curl -LO https://docs.sheetjs.com/reactnative/rnw/App.tsx
-8) Test the app again:
+8) Launch the app again:
@@ -611,10 +625,10 @@ When this demo was last tested on Windows 11 ARM, the build failed.
-Download .
+9) Download .
-Click "Click here to Open File!" and use the file picker to select `pres.xlsx` .
-The app will refresh and display the data from the file.
+10) In the app, click "Click here to Open File!" and use the file picker to
+select `pres.xlsx` . The app will refresh and display the data from the file.
## macOS Demo
diff --git a/docz/docs/03-demos/06-desktop/09-cli.md b/docz/docs/03-demos/06-desktop/09-cli.md
index 34045bd..82825f8 100644
--- a/docz/docs/03-demos/06-desktop/09-cli.md
+++ b/docz/docs/03-demos/06-desktop/09-cli.md
@@ -242,7 +242,7 @@ This demo was last tested in the following deployments:
| `darwin-x64` | `11.8.172.13` | `0.79.2` | 2023-10-12 |
| `darwin-arm` | `11.4.183.2` | `0.71.2` | 2023-05-22 |
| `win10-x64` | `11.8.172.13` | `0.79.2` | 2023-10-09 |
-| `win11-x64` | `11.7.439.6` | `0.75.1` | 2023-08-31 |
+| `win11-x64` | `11.8.172.13` | `0.79.2` | 2023-10-14 |
| `linux-x64` | `11.8.172.13` | `0.79.2` | 2023-10-11 |
| `linux-arm` | `11.7.439.6` | `0.75.1` | 2023-08-30 |
@@ -353,6 +353,7 @@ This demo was last tested in the following deployments:
| `darwin-x64` | `1.37.1` | 2023-10-12 |
| `darwin-arm` | `1.34.1` | 2023-06-05 |
| `win10-x64` | `1.37.1` | 2023-10-09 |
+| `win11-x64` | `1.37.2` | 2023-10-14 |
| `win11-arm` | `1.37.0` | 2023-09-26 |
| `linux-x64` | `1.37.1` | 2023-10-11 |
| `linux-arm` | `1.36.3` | 2023-08-30 |
diff --git a/docz/docs/03-demos/07-data/01-websql.md b/docz/docs/03-demos/07-data/01-websql.md
deleted file mode 100644
index 5ab6faa..0000000
--- a/docz/docs/03-demos/07-data/01-websql.md
+++ /dev/null
@@ -1,258 +0,0 @@
----
-title: WebSQL and SQLite
-pagination_prev: demos/desktop/index
-pagination_next: demos/local/index
-sidebar_custom_props:
- type: web
- sql: true
----
-
-import current from '/version.js';
-import CodeBlock from '@theme/CodeBlock';
-
-WebSQL is a popular SQL-based in-browser database available on Chrome. In
-practice, it is powered by SQLite, and most simple SQLite-compatible queries
-work as-is in WebSQL.
-
-The public demo generates a database from workbook.
-
-:::caution pass
-
-WebSQL is only supported in Chromium-based browsers including Chrome.
-
-Safari historically supported WebSQL but Safari 13 dropped support. Legacy
-browsers including Internet Explorer and Firefox never added support.
-
-:::
-
-## WebSQL Details
-
-Importing data from spreadsheets is straightforward using the `generate_sql`
-helper function from ["Generating Tables"](/docs/demos/data/sql#generating-tables).
-
-The Web SQL Database API is callback-based. The following snippet wraps
-transactions in Promise objects:
-
-```js
-const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
-const stmts = generate_sql(ws, wsname);
-
-// NOTE: tx.executeSql and db.transaction use callbacks. This wraps in Promises
-for(var stmt of stmts) await new Promise((res, rej) => {
- db.transaction(tx =>
- tx.executeSql(stmt, [],
- (tx, data) => res(data), // if the query is successful, return the data
- (tx, err) => rej(err) // if the query fails, reject with the error
- ));
-});
-```
-
-The result of a SQL SELECT statement is a `SQLResultSet`. The `rows` property
-is a `SQLResultSetRowList`. It is an "array-like" structure that has `length`
-and properties like `0`, `1`, etc. However, this is not a real Array object!
-
-A real Array can be created using `Array.from`:
-
-```js
-db.readTransaction(tx =>
- tx.executeSQL("SELECT * FROM DatabaseTable", [], (tx, data) => {
- // data.rows is "array-like", so `Array.from` can make it a real array
- const aoo = Array.from(data.rows);
- const ws = XLSX.utils.json_to_sheet(aoo);
- // ... perform an export here OR wrap in a Promise
- })
-);
-```
-
-### Live Demo
-
-:::note
-
-This browser demo was tested in the following environments:
-
-| Browser | Date |
-|:------------|:-----------|
-| Chrome 117 | 2023-10-11 |
-
-Some lesser-used browsers do not support WebSQL:
-
-| Browser | Date | Support |
-|:------------|:-----------|:------------------------------------|
-| Safari 17.0 | 2023-10-11 | Error `Web SQL is deprecated` |
-| Firefox 118 | 2023-10-11 | Error `openDatabase is not defined` |
-
-:::
-
-The following demo generates a database with 5 fixed SQL statements. Queries
-can be changed in the Live Editor. The WebSQL database can be inspected in the
-"WebSQL" section of the "Application" Tab of Developer Tools:
-
-![WebSQL view in Developer Tools](pathname:///files/websql.png)
-
-```jsx live
-function SheetQL() {
- const [out, setOut] = React.useState("");
- const queries = [
- 'DROP TABLE IF EXISTS Presidents',
- 'CREATE TABLE Presidents (Name TEXT, Idx REAL)',
- 'INSERT INTO Presidents (Name, Idx) VALUES ("Barack Obama", 44)',
- 'INSERT INTO Presidents (Name, Idx) VALUES ("Donald Trump", 45)',
- 'INSERT INTO Presidents (Name, Idx) VALUES ("Joseph Biden", 46)'
- ];
- const xport = React.useCallback(async() => {
- /* prep database */
- const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
-
- for(var q of queries) await new Promise((res, rej) => {
- db.transaction((tx) => {
- tx.executeSql(q, [], (tx, data) => res(data), (tx, err) => rej(err));
- });
- });
-
- /* pull data and generate rows */
- db.readTransaction(tx => {
- tx.executeSql("SELECT * FROM Presidents", [], (tx, data) => {
- const aoo = Array.from(data.rows);
- setOut("QUERY RESULT:\n" + aoo.map(r => JSON.stringify(r)).join("\n") + "\n")
- const ws = XLSX.utils.json_to_sheet(aoo);
- const wb = XLSX.utils.book_new();
- XLSX.utils.book_append_sheet(wb, ws, "Presidents");
- XLSX.writeFile(wb, "SheetQL.xlsx");
- });
- });
- });
- return (
{out}
);
-}
-```
-
-## Server-Side SQLite
-
-Most platforms offer a simple way to query SQLite database files.
-
-The following example shows how to query for each table in an SQLite database,
-query for the data for each table, add each non-empty table to a workbook, and
-export as XLSX.
-
-The Chinook database is a MIT-licensed sample database. The original source code
-repository `http://chinookdatabase.codeplex.com` is no longer available, so the
-[raw SQL queries are mirrored here](pathname:///sqlite/chinook.sql).
-
-:::note
-
-This demo was last tested on 2023 May 28
-
-:::
-
-### NodeJS
-
-The `better-sqlite3` module provides an API for working with SQLite databases.
-`Statement#all` runs a prepared statement and returns an array of objects:
-
-```js
-import Database from "better-sqlite3";
-import * as XLSX from "xlsx";
-
-/* open database */
-var db = Database("chinook.db");
-
-/* get data from the `Invoice` table */
-var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
-
-/* create worksheet from the row objects */
-var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
-```
-
-0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
-
-```bash
-curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
-sqlite3 chinook.db ".read chinook.sql"
-```
-
-1) Install the dependencies:
-
-{`\
-npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz better-sqlite3@8.1.0`}
-
-
-2) Download [`SheetJSQLiteNode.mjs`](pathname:///sqlite/SheetJSQLiteNode.mjs):
-
-```bash
-curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteNode.mjs
-```
-
-3) Run `node SheetJSQLiteNode.mjs` and open `SheetJSQLiteNode.xlsx`
-
-### Bun
-
-Bun ships with a built-in high-performance module `bun:sqlite`:
-
-```js
-import { Database } from "bun:sqlite";
-import * as XLSX from "xlsx";
-
-/* open database */
-var db = Database.open("chinook.db");
-
-/* get data from the `Invoice` table */
-var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
-
-/* create worksheet from the row objects */
-var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
-```
-
-0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
-
-```bash
-curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
-sqlite3 chinook.db ".read chinook.sql"
-```
-
-1) Install the dependencies:
-
-{`\
-npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
-
-
-2) Download [`SheetJSQLiteBun.mjs`](pathname:///sqlite/SheetJSQLiteBun.mjs):
-
-```bash
-curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteBun.mjs
-```
-
-3) Run `bun run SheetJSQLiteBun.mjs` and open `SheetJSQLiteBun.xlsx`
-
-### Deno
-
-Deno `sqlite` library returns raw arrays of arrays:
-
-{`\
-import { DB } from "https://deno.land/x/sqlite/mod.ts";
-// @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts"
-import * as XLSX from "https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs";
-\n\
-/* open database */
-var db = new DB("chinook.db");
-\n\
-/* get data from the \`Invoice\` table */
-var aoa = db.prepareQuery("SELECT * FROM 'Invoice' LIMIT 100000").all();
-\n\
-/* create worksheet from the row objects */
-var data = [query.columns().map(x => x.name)].concat(aoa);
-var ws = XLSX.utils.aoa_to_sheet(data, {dense: true});`}
-
-
-0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
-
-```bash
-curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
-sqlite3 chinook.db ".read chinook.sql"
-```
-
-1) Download [`SheetJSQLiteDeno.ts`](pathname:///sqlite/SheetJSQLiteDeno.ts):
-
-```bash
-curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteDeno.ts
-```
-
-2) Run `deno run --allow-read --allow-write SheetJSQLiteDeno.ts` and open `SheetJSQLiteDeno.xlsx`
diff --git a/docz/docs/03-demos/07-data/11-sqlite.md b/docz/docs/03-demos/07-data/11-sqlite.md
new file mode 100644
index 0000000..db761bd
--- /dev/null
+++ b/docz/docs/03-demos/07-data/11-sqlite.md
@@ -0,0 +1,314 @@
+---
+title: Sheets with SQLite
+sidebar_label: SQLite
+pagination_prev: demos/desktop/index
+pagination_next: demos/local/index
+sidebar_custom_props:
+ sql: true
+---
+
+
+
+
+
+import current from '/version.js';
+import CodeBlock from '@theme/CodeBlock';
+
+[SQLite](https://sqlite.org/) is a lightweight embeddable SQL database engine.
+There are connector libraries for many popular JavaScript server-side platforms.
+
+[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
+data from spreadsheets.
+
+This demo uses SQLite and SheetJS to exchange data between spreadsheets and SQL
+servers. We'll explore how to use save tables from a database to spreadsheets
+and how to add data from spreadsheets into a database.
+
+:::note
+
+This demo was last tested on 2023 October 13
+
+:::
+
+:::info pass
+
+This demo covers SQLite `.db` file processing.
+
+The [WebSQL demo](/docs/demos/local/websql) covers the Web SQL Database API, a
+SQLite-compatible database built into Chromium and Google Chrome.
+
+:::
+
+## Demo
+
+The following examples show how to query for each table in an SQLite database,
+query for the data for each table, add each non-empty table to a workbook, and
+export as XLSX.
+
+#### Sample Database
+
+The Chinook database is a MIT-licensed sample database. The original source code
+repository `http://chinookdatabase.codeplex.com` is no longer available, so the
+[raw SQL queries are mirrored here](pathname:///sqlite/chinook.sql).
+
+### Exporting Data
+
+Connector libraries typically provide a way to generate an array of objects from
+the result of a `SELECT` query. For example, using `better-sqlite3` in NodeJS:
+
+```js
+import Database from "better-sqlite3";
+
+/* open database */
+var db = Database("chinook.db");
+
+/* get data from the `Invoice` table */
+var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
+```
+
+The SheetJS `json_to_sheet` method[^1] can take the result and generate a
+worksheet object[^2]. The `book_new` and `book_append_sheet` methods[^3] help
+build a workbook object[^4]. The `writeFile` method[^5] generates a file:
+
+```js
+import * as XLSX from "xlsx";
+
+/* Create Worksheet from the row objects */
+var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
+
+/* Add to Workbook */
+XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
+
+/* Write File */
+XLSX.writeFile(wb, "SheetJSQLiteNode.xlsx");
+```
+
+### Importing Data
+
+The ["Generating Tables"](/docs/demos/data/sql#generating-tables) section
+includes a code snippet for generating SQLite-compatible SQL queries from a
+SheetJS worksheet object. Each query can be run sequentially.
+
+## Browser
+
+`sql.js`[^6] is a compiled version of SQLite into WebAssembly, making it usable
+in web browsers.
+
+SQLite database files can be `fetch`ed and loaded:
+
+```js
+/* Load sql.js library */
+const SQL = await initSqlJs(config);
+/* fetch sqlite database */
+const ab = await (await fetch("/sqlite/chinook.db")).arrayBuffer();
+/* connect to DB */
+const db = new SQL.Database(new Uint8Array(ab));
+```
+
+The `sql.js` connector library uses an iterator-like interface. After preparing
+a statement, `Statement#step` loops over the result and `Statement#getAsObject`
+pulls each row as a row object:
+
+```js
+/* perform query and get iterator */
+const sql = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
+
+/* create worksheet from the row objects */
+let ws;
+
+while(sql.step()) {
+ const row = sql.getAsObject();
+
+ if(!ws) ws = XLSX.utils.json_to_sheet([row], {dense: true, header});
+ else XLSX.utils.sheet_add_json(ws, [row], { header, origin: -1, skipHeader: true});
+}
+```
+
+### Demo
+
+This demo fetches [`chinook.db`](pathname:///sqlite/chinook.db), loads into the
+SQLite engine and performs a series of queries to extract the data. Worksheets
+are created from the data. A workbook is created from the worksheets and
+exported to a XLSX file.
+
+```jsx live
+function SheetJSQLJS() { return () }
+```
+
+## Server-Side Platforms
+
+### NodeJS
+
+The `better-sqlite3`[^7] native module embeds the SQLite C library.
+`Statement#all` runs a prepared statement and returns an array of objects:
+
+```js
+import Database from "better-sqlite3";
+import * as XLSX from "xlsx";
+
+/* open database */
+var db = Database("chinook.db");
+
+/* get data from the `Invoice` table */
+var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
+
+/* create worksheet from the row objects */
+var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
+```
+
+0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
+
+```bash
+curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
+sqlite3 chinook.db ".read chinook.sql"
+```
+
+1) Install the dependencies:
+
+{`\
+npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz better-sqlite3@9.0.0`}
+
+
+2) Download [`SheetJSQLiteNode.mjs`](pathname:///sqlite/SheetJSQLiteNode.mjs):
+
+```bash
+curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteNode.mjs
+```
+
+3) Run the script:
+
+```bash
+node SheetJSQLiteNode.mjs
+```
+
+Open `SheetJSQLiteNode.xlsx` with a spreadsheet editor.
+
+### Bun
+
+Bun ships with a built-in high-performance module `bun:sqlite`[^8]:
+
+```js
+import { Database } from "bun:sqlite";
+import * as XLSX from "xlsx";
+
+/* open database */
+var db = Database.open("chinook.db");
+
+/* get data from the `Invoice` table */
+var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
+
+/* create worksheet from the row objects */
+var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
+```
+
+0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
+
+```bash
+curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
+sqlite3 chinook.db ".read chinook.sql"
+```
+
+1) Install the dependencies:
+
+{`\
+bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
+
+
+2) Download [`SheetJSQLiteBun.mjs`](pathname:///sqlite/SheetJSQLiteBun.mjs):
+
+```bash
+curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteBun.mjs
+```
+
+3) Run the script:
+
+```bash
+bun run SheetJSQLiteBun.mjs
+```
+
+Open `SheetJSQLiteBun.xlsx` with a spreadsheet editor.
+
+### Deno
+
+Deno `sqlite` library[^9] returns raw arrays of arrays:
+
+{`\
+import { DB } from "https://deno.land/x/sqlite/mod.ts";
+// @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts"
+import * as XLSX from "https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs";
+\n\
+/* open database */
+var db = new DB("chinook.db");
+\n\
+/* get data from the \`Invoice\` table */
+var aoa = db.prepareQuery("SELECT * FROM 'Invoice' LIMIT 100000").all();
+\n\
+/* create worksheet from the row objects */
+var data = [query.columns().map(x => x.name)].concat(aoa);
+var ws = XLSX.utils.aoa_to_sheet(data, {dense: true});`}
+
+
+0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
+
+```bash
+curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
+sqlite3 chinook.db ".read chinook.sql"
+```
+
+1) Download [`SheetJSQLiteDeno.ts`](pathname:///sqlite/SheetJSQLiteDeno.ts):
+
+```bash
+curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteDeno.ts
+```
+
+2) Run the script:
+
+```bash
+deno run --allow-read --allow-write SheetJSQLiteDeno.ts
+```
+
+Open `SheetJSQLiteDeno.xlsx` with a spreadsheet editor.
+
+[^1]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
+[^2]: See ["Sheet Objects"](/docs/csf/sheet) in "SheetJS Data Model" for more details.
+[^3]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
+[^4]: See ["Workbook Objects"](/docs/csf/book) in "SheetJS Data Model" for more details.
+[^5]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
+[^6]: See [the `sql.js` documentation](https://sql.js.org/documentation/)
+[^7]: The [documentation](https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md) can be found in the project repository.
+[^8]: See ["SQLite"](https://bun.sh/docs/api/sqlite) in the BunJS documentation.
+[^9]: See [the `sqlite` module](https://deno.land/x/sqlite) on the Deno module registry.
\ No newline at end of file
diff --git a/docz/docs/03-demos/07-data/index.md b/docz/docs/03-demos/07-data/index.md
index 68bbea1..d55842f 100644
--- a/docz/docs/03-demos/07-data/index.md
+++ b/docz/docs/03-demos/07-data/index.md
@@ -183,6 +183,7 @@ The following Web APIs are featured in separate demos:
{item.label}{item.customProps?.summary && (" - " + item.customProps.summary)}
);
})}
+
diff --git a/docz/docs/03-demos/08-local/01-websql.md b/docz/docs/03-demos/08-local/01-websql.md
new file mode 100644
index 0000000..97af103
--- /dev/null
+++ b/docz/docs/03-demos/08-local/01-websql.md
@@ -0,0 +1,217 @@
+---
+title: Sheets with WebSQL
+sidebar_label: Web SQL Database
+pagination_prev: demos/data/index
+pagination_next: demos/cloud/index
+sidebar_custom_props:
+ summary: Reading and writing data in an in-browser SQL database
+---
+
+import CodeBlock from '@theme/CodeBlock';
+
+WebSQL (formally "Web SQL Database") is a popular SQL-based in-browser database
+available in Chromium and related browsers including Google Chrome. In practice,
+it is powered by SQLite. Many SQLite-compatible queries work as-is in WebSQL.
+
+The public demo generates a database from workbook.
+
+:::caution pass
+
+WebSQL is only supported in Chromium-based browsers including Chrome.
+
+Safari historically supported WebSQL but Safari 13 dropped support.
+
+Legacy browsers including Internet Explorer and Firefox never added support.
+
+:::
+
+:::info pass
+
+WebSQL is not commonly available on server-side platforms. Typically scripts
+will directly query SQLite databases using connector modules.
+
+[The "SQLite" demo](/docs/demos/data/sqlite) covers NodeJS and other platforms.
+
+:::
+
+## Overview
+
+Environments that support WebSQL expose the `openDatabase` global method. It
+takes 4 arguments:
+- internal database name
+- version string (`1.0`)
+- public display name
+- database size (measured in bytes)
+
+The following command attempts to connect to the database named `sheetql`. If
+the database does not exist, it will create a new database with a hint to
+allocate 2MB of space.
+
+```js
+const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
+```
+
+### Transactions and Queries
+
+Queries are performed within transactions.
+
+`Database#transaction` passes a transaction object to the callback argument:
+
+```js
+db.transaction(function(tx) {
+ /* tx is a transaction object */
+});
+```
+
+Within a transaction, queries are performed with `Transaction#executeSql`. The
+method takes 4 arguments:
+- SQL statement stored in a string
+- Array of parameterized query arguments
+- Success callback
+- Error callback
+
+If the query succeeds, the success callback will be invoked with two arguments:
+- Transaction object
+- Result of the query
+
+If the query fails, the error callback will be invoked with two arguments:
+- Transaction object
+- Error information
+
+The Web SQL Database API is callback-based. The following snippet runs one query
+and wraps the execution in a promise that resolves to the query result or
+rejects with the error:
+
+```js
+function execute_simple_query(db, query) {
+ return new Promise((resolve, reject) => {
+ db.transaction(tx =>
+ tx.executeSQL(query, [],
+ (tx, data) => resolve(data),
+ (tx, err) => reject(err)
+ )
+ );
+ });
+}
+```
+
+### Importing Data
+
+Importing data from spreadsheets is straightforward using the `generate_sql`
+helper function from ["Generating Tables"](/docs/demos/data/sql#generating-tables)
+
+```js
+const stmts = generate_sql(ws, wsname);
+
+// NOTE: tx.executeSql and db.transaction use callbacks. This wraps in Promises
+for(var stmt of stmts) await new Promise((res, rej) => {
+ db.transaction(tx =>
+ tx.executeSql(stmt, [],
+ (tx, data) => res(data), // if the query is successful, return the data
+ (tx, err) => rej(err) // if the query fails, reject with the error
+ ));
+});
+```
+
+Typically worksheet objects are extracted from workbook objects[^1] generated
+from the SheetJS `read` or `readFile` methods[^2].
+
+### Exporting Data
+
+The result of a SQL SELECT statement is a `SQLResultSet`. The `rows` property
+is a `SQLResultSetRowList`. It is an "array-like" structure that has `length`
+and properties like `0`, `1`, etc. However, this is not a real Array object!
+
+A real Array can be created using `Array.from`. The SheetJS `json_to_sheet`
+method[^3] can generate a worksheet object[^4] from the real array:
+
+```js
+db.readTransaction(tx =>
+ tx.executeSQL("SELECT * FROM DatabaseTable", [], (tx, data) => {
+ // data.rows is "array-like", so `Array.from` can make it a real array
+ const aoo = Array.from(data.rows);
+ const ws = XLSX.utils.json_to_sheet(aoo);
+ // ... perform an export here OR wrap in a Promise
+ })
+);
+```
+
+Using `book_new` and `book_append_sheet`[^5], a workbook object can be created.
+This workbook is typically exported to the filesystem with `writeFile`[^6].
+
+
+
+
+## Live Demo
+
+:::note
+
+This browser demo was tested in the following environments:
+
+| Browser | Date |
+|:------------|:-----------|
+| Chrome 117 | 2023-10-13 |
+
+Some lesser-used browsers do not support WebSQL:
+
+| Browser | Date | Support |
+|:------------|:-----------|:------------------------------------|
+| Safari 17.0 | 2023-10-13 | Error `Web SQL is deprecated` |
+| Firefox 118 | 2023-10-13 | Error `openDatabase is not defined` |
+
+:::
+
+### Export Demo
+
+The following demo generates a database with 5 fixed SQL statements. Queries
+can be changed in the Live Editor. The WebSQL database can be inspected in the
+"WebSQL" section of the "Application" Tab of Developer Tools:
+
+![WebSQL view in Developer Tools](pathname:///files/websql.png)
+
+```jsx live
+function SheetQL() {
+ const [out, setOut] = React.useState("");
+ const queries = [
+ 'DROP TABLE IF EXISTS Presidents',
+ 'CREATE TABLE Presidents (Name TEXT, Idx REAL)',
+ 'INSERT INTO Presidents (Name, Idx) VALUES ("Barack Obama", 44)',
+ 'INSERT INTO Presidents (Name, Idx) VALUES ("Donald Trump", 45)',
+ 'INSERT INTO Presidents (Name, Idx) VALUES ("Joseph Biden", 46)'
+ ];
+ const xport = React.useCallback(async() => {
+ /* prep database */
+ const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
+
+ for(var q of queries) await new Promise((res, rej) => {
+ db.transaction((tx) => {
+ tx.executeSql(q, [], (tx, data) => res(data), (tx, err) => rej(err));
+ });
+ });
+
+ /* pull data and generate rows */
+ db.readTransaction(tx => {
+ tx.executeSql("SELECT * FROM Presidents", [], (tx, data) => {
+ const aoo = Array.from(data.rows);
+ setOut("QUERY RESULT:\n" + aoo.map(r => JSON.stringify(r)).join("\n") + "\n")
+ const ws = XLSX.utils.json_to_sheet(aoo);
+ const wb = XLSX.utils.book_new();
+ XLSX.utils.book_append_sheet(wb, ws, "Presidents");
+ XLSX.writeFile(wb, "SheetQL.xlsx");
+ });
+ });
+ });
+ return (
{out}
);
+}
+```
+
+## Server-Side SQLite
+
+**[The exposition has been moved to a separate page.](/docs/demos/data/sqlite)**
+
+[^1]: See ["Workbook Object"](/docs/csf/book)
+[^2]: See [`read` and `readFile` in "Reading Files"](/docs/api/parse-options)
+[^3]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
+[^4]: See ["Sheet Objects"](/docs/csf/sheet)
+[^5]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
+[^6]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
\ No newline at end of file
diff --git a/docz/docs/03-demos/32-extensions/02-chromium.md b/docz/docs/03-demos/32-extensions/02-chromium.md
index 6487a38..c15f66c 100644
--- a/docz/docs/03-demos/32-extensions/02-chromium.md
+++ b/docz/docs/03-demos/32-extensions/02-chromium.md
@@ -22,7 +22,7 @@ tables with a content script and a background script.
:::note
-This demo was last tested on 2023 June 06 against Chrome 114
+This demo was last tested on 2023 October 14 against Chrome 117.
:::
diff --git a/docz/docs/03-demos/42-engines/06-goja.md b/docz/docs/03-demos/42-engines/06-goja.md
index 001f13f..f94f8d6 100644
--- a/docz/docs/03-demos/42-engines/06-goja.md
+++ b/docz/docs/03-demos/42-engines/06-goja.md
@@ -94,7 +94,7 @@ This demo was tested in the following deployments:
| Architecture | Git Commit | Go version | Date |
|:-------------|:-----------|:-----------|:-----------|
-| `darwin-x64` | `28ee0ee` | `1.19.3` | 2023-06-05 |
+| `darwin-x64` | `873a149` | `1.21.3` | 2023-10-14 |
| `darwin-arm` | `28ee0ee` | `1.20.4` | 2023-06-05 |
| `win10-x64` | `81d7606` | `1.20.2` | 2023-08-27 |
| `win11-arm` | `fc55792` | `1.21.1` | 2023-09-25 |
diff --git a/docz/docs/09-miscellany/05-contributing.md b/docz/docs/09-miscellany/05-contributing.md
index ba3fae9..5b555bb 100644
--- a/docz/docs/09-miscellany/05-contributing.md
+++ b/docz/docs/09-miscellany/05-contributing.md
@@ -44,7 +44,7 @@ These instructions were tested on the following platforms:
| MacOS 10.13.6 (x64) | 2023-09-30 |
| MacOS 13.6 (ARM64) | 2023-09-30 |
| Windows 10 (x64) + WSL Ubuntu | 2023-07-23 |
-| Windows 11 (x64) + WSL Ubuntu | 2023-08-31 |
+| Windows 11 (x64) + WSL Ubuntu | 2023-10-14 |
| Windows 11 (ARM) + WSL Ubuntu | 2023-09-18 |
With some additional dependencies, the unminified scripts are reproducible and
@@ -64,7 +64,50 @@ import TabItem from '@theme/TabItem';
A) Ensure WSL ("WSL 2" in Windows 10) and the Ubuntu distribution are installed.
-B) Install mercurial and subversion:
+Installation Notes (click to hide)
+
+In "Turn Windows features on or off", the following features must be enabled:
+
+- "Hyper-V" (including every sub-feature)
+- "Virtual Machine Platform"
+- "Windows Hypervisor Platform"
+- "Windows Subsystem for Linux"
+
+The following command installs Ubuntu within WSL:
+
+```powershell
+wsl --install Ubuntu
+```
+
+:::caution pass
+
+In the last Windows 11 test, there was a `WSL_E_DEFAULT_DISTRO_NOT_FOUND` error.
+
+The resolution is to switch to WSL1, install, and switch back to WSL2:
+
+```
+wsl --set-default-version 1
+wsl --install Ubuntu
+wsl --set-default-version 2
+wsl --install Ubuntu
+```
+
+:::
+
+:::warning pass
+
+**WSL will not run in a Windows on ARM VM on computers with the M1 CPU**
+
+Apple Silicon M1 processors do not support nested virtualization.
+
+M2 processors do support nested virtualization. SheetJS users have reported
+success with Windows on ARM running on computers with the M2 Max CPU.
+
+:::
+
+
+
+B) Install mercurial and subversion from within WSL:
```bash
sudo apt-get update
@@ -93,7 +136,7 @@ sudo add-apt-repository --remove ppa:mercurial-ppa/releases
:::
-C) Install NodeJS
+C) Install NodeJS within WSL:
:::info pass
@@ -112,7 +155,9 @@ curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs
```
-Exit the WSL window and open a new one before proceeding:
+D) Exit the WSL session and start a new session
+
+E) Install the `n` package and switch NodeJS vesrions:
```bash
# Switch to `n`-managed NodeJS
@@ -130,12 +175,14 @@ sudo apt-get install -y npm
:::
-D) Test clone the [`js-crc32` repo](https://git.sheetjs.com/sheetjs/js-crc32)
+F) Clone the [`js-crc32` repo](https://git.sheetjs.com/sheetjs/js-crc32)
```bash
git clone https://git.sheetjs.com/sheetjs/js-crc32
```
+:::note pass
+
If this clone fails with an error message that mentions SSL or secure connection
or certificates, build and install a version of Git with proper SSL support:
@@ -146,7 +193,9 @@ chmod +x compile-git-with-openssl.sh
./compile-git-with-openssl.sh
```
-E) Set `git` config `core.autocrlf` setting to `false`. The following commands
+:::
+
+G) Set `git` config `core.autocrlf` setting to `false`. The following commands
should be run twice, once within PowerShell (if Git for Windows is installed)
and once within WSL bash:
@@ -155,10 +204,16 @@ git config --global --add core.autocrlf false
git config --global --unset core.autocrlf true
```
-F) Run `unzip`. If the program is missing, install manually:
+H) Run `unzip`. If the program is missing, install manually:
```bash
sudo apt-get install -y unzip
+```
+
+I) Run `make`. If the program is missing, install manually:
+
+```bash
+sudo apt-get install -y make
```
@@ -207,7 +262,7 @@ for "LTS" and "Current" releases. The "LTS" version should be installed.
In local testing, macOS 10.13 required NodeJS version `12.22.12`:
```bash
-curl -LO https://nodejs.org/download/release/v12.22.12/node-v12.22.12.pkg
+curl -LO https://nodejs.org/download/release/v12.22.12/node-v12.22.12.pkg
open node-v12.22.12.pkg
```
diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js
index bb7c94c..f201bf5 100644
--- a/docz/docusaurus.config.js
+++ b/docz/docusaurus.config.js
@@ -216,6 +216,7 @@ const config = {
{ from: '/docs/demos/localfile', to: '/docs/demos/local/file/' },
{ from: '/docs/demos/data/indexeddb', to: '/docs/demos/local/indexeddb/' },
{ from: '/docs/demos/data/storageapi', to: '/docs/demos/local/storageapi/' },
+ { from: '/docs/demos/data/websql', to: '/docs/demos/local/websql/' },
/* desktop */
{ from: '/docs/demos/cli', to: '/docs/demos/desktop/cli/' },
{ from: '/docs/getting-started/demos/cli', to: '/docs/demos/desktop/cli/' },
diff --git a/docz/static/sqlite/chinook.db b/docz/static/sqlite/chinook.db
new file mode 100644
index 0000000..f853411
Binary files /dev/null and b/docz/static/sqlite/chinook.db differ