From 5e1ec997b82db964fd13a1d2746ba0adfa411a1a Mon Sep 17 00:00:00 2001 From: Elmar Burke Date: Tue, 16 Dec 2025 16:08:26 +0100 Subject: [PATCH 1/5] Initialise typescript --- .github/workflows/pull_request.yml | 12 ++++++++++++ examples/csv-importer/package.json | 12 ++++++++++++ examples/csv-importer/test.ts | 1 + examples/csv-importer/tsconfig.json | 5 +++++ package-lock.json | 21 ++++++++++++++++++++- package.json | 3 ++- tsconfig.base.json | 14 ++++++++++++++ 7 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 examples/csv-importer/package.json create mode 100644 examples/csv-importer/test.ts create mode 100644 examples/csv-importer/tsconfig.json create mode 100644 tsconfig.base.json diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index c2563d9..64a7794 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -17,3 +17,15 @@ jobs: - run: npm ci - run: npm run check + typecheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-node@v6 + with: + node-version: 24 + cache: npm + + - run: npm ci + - run: npm run typecheck diff --git a/examples/csv-importer/package.json b/examples/csv-importer/package.json new file mode 100644 index 0000000..6004d14 --- /dev/null +++ b/examples/csv-importer/package.json @@ -0,0 +1,12 @@ +{ + "name": "csv-importer", + "version": "0.0.1", + "private": true, + "type": "module", + "scripts": { + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "typescript": "^5.9.3" + } +} diff --git a/examples/csv-importer/test.ts b/examples/csv-importer/test.ts new file mode 100644 index 0000000..91157fd --- /dev/null +++ b/examples/csv-importer/test.ts @@ -0,0 +1 @@ +const n: number = "1"; diff --git a/examples/csv-importer/tsconfig.json b/examples/csv-importer/tsconfig.json new file mode 100644 index 0000000..b5f893f --- /dev/null +++ b/examples/csv-importer/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["**/*.ts"] +} + diff --git a/package-lock.json b/package-lock.json index 083d654..02394a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,9 @@ }, "examples/csv-importer": { "version": "0.0.1", - "extraneous": true + "dependencies": { + "typescript": "^5.9.3" + } }, "node_modules/@biomejs/biome": { "version": "2.3.9", @@ -178,6 +180,23 @@ "engines": { "node": ">=14.21.3" } + }, + "node_modules/csv-importer": { + "resolved": "examples/csv-importer", + "link": true + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } } } } diff --git a/package.json b/package.json index 173d84d..d6eab62 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "scripts": { "format": "biome format --write", "lint": "biome lint --write", - "check": "biome check" + "check": "biome check", + "typecheck": "npm run typecheck --workspaces" } } diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..a029c0c --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "isolatedModules": true + } +} + From a479ccf1419946d8f2dedb4eb9ac8313c097783b Mon Sep 17 00:00:00 2001 From: Elmar Burke Date: Tue, 16 Dec 2025 16:10:39 +0100 Subject: [PATCH 2/5] Format code --- biome.json | 74 ++++++++++++++--------------- examples/csv-importer/package.json | 20 ++++---- examples/csv-importer/tsconfig.json | 5 +- package.json | 28 +++++------ tsconfig.base.json | 23 +++++---- 5 files changed, 74 insertions(+), 76 deletions(-) diff --git a/biome.json b/biome.json index cc3f8bf..c179ec2 100644 --- a/biome.json +++ b/biome.json @@ -1,40 +1,40 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.9/schema.json", - "vcs": { - "enabled": true, - "clientKind": "git", - "useIgnoreFile": true - }, - "files": { - "ignoreUnknown": false - }, - "formatter": { - "enabled": true, - "formatWithErrors": true, - "indentStyle": "space", - "indentWidth": 4, - "lineWidth": 120, - "lineEnding": "lf", - "attributePosition": "auto", + "$schema": "https://biomejs.dev/schemas/2.3.9/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "formatWithErrors": true, + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 120, + "lineEnding": "lf", + "attributePosition": "auto", "bracketSpacing": true - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - }, - "javascript": { - "formatter": { - "quoteStyle": "double" - } - }, - "assist": { - "enabled": true, - "actions": { - "source": { - "organizeImports": "on" - } - } - } + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } } diff --git a/examples/csv-importer/package.json b/examples/csv-importer/package.json index 6004d14..6f7a3f1 100644 --- a/examples/csv-importer/package.json +++ b/examples/csv-importer/package.json @@ -1,12 +1,12 @@ { - "name": "csv-importer", - "version": "0.0.1", - "private": true, - "type": "module", - "scripts": { - "typecheck": "tsc --noEmit" - }, - "dependencies": { - "typescript": "^5.9.3" - } + "name": "csv-importer", + "version": "0.0.1", + "private": true, + "type": "module", + "scripts": { + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "typescript": "^5.9.3" + } } diff --git a/examples/csv-importer/tsconfig.json b/examples/csv-importer/tsconfig.json index b5f893f..8cff07e 100644 --- a/examples/csv-importer/tsconfig.json +++ b/examples/csv-importer/tsconfig.json @@ -1,5 +1,4 @@ { - "extends": "../../tsconfig.base.json", - "include": ["**/*.ts"] + "extends": "../../tsconfig.base.json", + "include": ["**/*.ts"] } - diff --git a/package.json b/package.json index d6eab62..06b672a 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,16 @@ { - "name": "framer-server-api-examples", - "private": true, - "workspaces": [ - "examples/*" - ], - "devDependencies": { - "@biomejs/biome": "2.3.9" - }, - "scripts": { - "format": "biome format --write", - "lint": "biome lint --write", - "check": "biome check", - "typecheck": "npm run typecheck --workspaces" - } + "name": "framer-server-api-examples", + "private": true, + "workspaces": [ + "examples/*" + ], + "devDependencies": { + "@biomejs/biome": "2.3.9" + }, + "scripts": { + "format": "biome format --write", + "lint": "biome lint --write", + "check": "biome check", + "typecheck": "npm run typecheck --workspaces" + } } diff --git a/tsconfig.base.json b/tsconfig.base.json index a029c0c..24fbcdd 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,14 +1,13 @@ { - "compilerOptions": { - "target": "ES2022", - "module": "NodeNext", - "moduleResolution": "NodeNext", - "strict": true, - "noEmit": true, - "skipLibCheck": true, - "esModuleInterop": true, - "resolveJsonModule": true, - "isolatedModules": true - } + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "isolatedModules": true + } } - From ef2f2c57116be50f1328fe6e527039c2c2bb453c Mon Sep 17 00:00:00 2001 From: Elmar Burke Date: Tue, 16 Dec 2025 16:11:27 +0100 Subject: [PATCH 3/5] Fix ts error (used to validate failing CI) --- examples/csv-importer/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/csv-importer/test.ts b/examples/csv-importer/test.ts index 91157fd..28b51e1 100644 --- a/examples/csv-importer/test.ts +++ b/examples/csv-importer/test.ts @@ -1 +1 @@ -const n: number = "1"; +const _n: string = "1"; From 9b86c3033bbc492947518f9489828b919aa15130 Mon Sep 17 00:00:00 2001 From: Elmar Burke Date: Tue, 16 Dec 2025 17:59:49 +0100 Subject: [PATCH 4/5] Added CSV Importer example --- .env.example | 2 + README.md | 34 ++ biome.json | 3 +- examples/csv-importer/README.md | 13 + .../csv-importer/data/sample-products.csv | 9 + examples/csv-importer/package.json | 6 + .../csv-importer/src/csv-to-collection.ts | 92 +++ examples/csv-importer/src/load-csv.ts | 52 ++ examples/csv-importer/test.ts | 1 - package-lock.json | 525 +++++++++++------- tsconfig.base.json | 14 +- 11 files changed, 547 insertions(+), 204 deletions(-) create mode 100644 .env.example create mode 100644 README.md create mode 100644 examples/csv-importer/README.md create mode 100644 examples/csv-importer/data/sample-products.csv create mode 100644 examples/csv-importer/src/csv-to-collection.ts create mode 100644 examples/csv-importer/src/load-csv.ts delete mode 100644 examples/csv-importer/test.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c507ac5 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +EXAMPLE_PROJECT_URL=https://framer.com/projects/Sites--aabbccddeeff +FRAMER_API_KEY=12345678-1234-1234-1234-123456789 diff --git a/README.md b/README.md new file mode 100644 index 0000000..977e28a --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# Framer Server API Examples + +This repository contains examples for the Framer Server API. Each example is a standalone project that can be run independently. + +## How to run examples + +You need to obtain a Framer project URL and API key. You can get the API key from the Framer project settings and find the project URL in the browser URL bar. + +Then, you need to set the `EXAMPLE_PROJECT_URL` and `FRAMER_API_KEY` environment variables. + +## How to connect and get a framer client + +```ts +const projectUrl = "https://framer.com/projects/Sites--aabbccddeeff"; + +const framer = await connect(projectUrl, apiKey); +// ... your code here ... +await framer.disconnect(); +``` + +Starting with Node.js v24, you can use the `using` keyword to ensure that the Framer client is closed after the block is executed. + +```ts +using framer = await connect(projectUrl, apiKey); + +// ... your code here ... +// The disconnect is automatically called when the block is exited. +``` + +You can also use the environment variable `FRAMER_API_KEY` to set the API key and omit the API key parameter. + +```ts +using framer = await connect(projectUrl); +``` diff --git a/biome.json b/biome.json index c179ec2..bbcb9b0 100644 --- a/biome.json +++ b/biome.json @@ -21,7 +21,8 @@ "linter": { "enabled": true, "rules": { - "recommended": true + "recommended": true, + "useLiteralKeys": "off" } }, "javascript": { diff --git a/examples/csv-importer/README.md b/examples/csv-importer/README.md new file mode 100644 index 0000000..4e332a2 --- /dev/null +++ b/examples/csv-importer/README.md @@ -0,0 +1,13 @@ +# CSV Importer + +This example shows how to import a CSV file into a Framer collection. + +How to use: + +```bash +node --env-file=../../.env src/csv-to-collection.ts + +bun run src/csv-to-collection.ts + +deno run src/csv-to-collection.ts +``` diff --git a/examples/csv-importer/data/sample-products.csv b/examples/csv-importer/data/sample-products.csv new file mode 100644 index 0000000..0748d65 --- /dev/null +++ b/examples/csv-importer/data/sample-products.csv @@ -0,0 +1,9 @@ +slug,title,description,price,inStock,category +wireless-mouse,Wireless Mouse,Ergonomic wireless mouse with precision tracking,29.99,true,Electronics +mechanical-keyboard,Mechanical Keyboard,RGB mechanical keyboard with cherry switches,89.99,true,Electronics +usb-c-cable,USB-C Cable,Fast charging USB-C cable 6ft length,12.99,false,Accessories +monitor-stand,Monitor Stand,Adjustable aluminum monitor stand,49.99,true,Furniture +desk-lamp,LED Desk Lamp,Dimmable LED lamp with USB charging port,34.99,true,Lighting +webcam-hd,HD Webcam,1080p webcam with built-in microphone,59.99,true,Electronics +mouse-pad,Large Mouse Pad,Extended gaming mouse pad with stitched edges,19.99,true,Accessories +headphone-stand,Headphone Stand,Wooden headphone stand with cable holder,24.99,false,Furniture diff --git a/examples/csv-importer/package.json b/examples/csv-importer/package.json index 6f7a3f1..abda280 100644 --- a/examples/csv-importer/package.json +++ b/examples/csv-importer/package.json @@ -7,6 +7,12 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "framer-api": "^0.0.1-alpha.6", + "papaparse": "^5.5.3", "typescript": "^5.9.3" + }, + "devDependencies": { + "@types/node": "^22.10.2", + "@types/papaparse": "^5.3.15" } } diff --git a/examples/csv-importer/src/csv-to-collection.ts b/examples/csv-importer/src/csv-to-collection.ts new file mode 100644 index 0000000..18ff39e --- /dev/null +++ b/examples/csv-importer/src/csv-to-collection.ts @@ -0,0 +1,92 @@ +import assert from "node:assert"; +import path from "node:path"; +import { type CreateField, connect, type FieldDataEntryInput, type FieldDataInput } from "framer-api"; +import { type FieldType, loadCsv } from "./load-csv.ts"; + +// Configuration + +const projectUrl = process.env["EXAMPLE_PROJECT_URL"]; +assert(projectUrl, "EXAMPLE_PROJECT_URL environment variable is required"); + +const csvPath = process.env["CSV_PATH"] ?? path.join(import.meta.dirname, "../data/sample-products.csv"); +const collectionName = process.env["COLLECTION_NAME"] ?? "Products"; + +const { columns, rows, fieldTypes } = loadCsv(csvPath); + +assert(columns.includes("slug"), "CSV must contain a 'slug' column"); + +// The `using` keyword is used to ensure that the Framer client is closed after the block is executed. +// If you don't use the `using` keyword, you need to manually close the client using `await framer.disconnect()`. +// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using +using framer = await connect(projectUrl); + +// Find or Create Collection + +const existingCollections = await framer.getCollections(); +let collection = existingCollections.find((c) => c.name === collectionName); + +if (!collection) { + collection = await framer.createCollection(collectionName); +} + +// Add Missing Fields + +const existingFields = await collection.getFields(); +const existingFieldNames = new Set(existingFields.map((f) => f.name.toLowerCase())); + +const fieldsToCreate = columns + .filter((column) => column !== "slug" && !existingFieldNames.has(column.toLowerCase())) + .map( + (column): CreateField => ({ + type: fieldTypes.get(column) ?? "string", + name: column, + }), + ); + +if (fieldsToCreate.length > 0) { + await collection.addFields(fieldsToCreate); +} + +// Build Items & Import + +const fields = await collection.getFields(); +const fieldNameToId = new Map(fields.map((f) => [f.name.toLowerCase(), f.id])); + +const existingItems = await collection.getItems(); +const slugToExistingId = new Map(existingItems.map((item) => [item.slug, item.id])); + +const items = rows.map((row) => { + const fieldData: FieldDataInput = {}; + + for (const column of columns) { + if (column === "slug") continue; + + const fieldId = fieldNameToId.get(column.toLowerCase()); + if (!fieldId) continue; + + const value = row[column] ?? ""; + const fieldType = fieldTypes.get(column) ?? "string"; + fieldData[fieldId] = toFieldData(value, fieldType); + } + + const slug = row["slug"]; + assert(slug && slug.length > 0, "slug is required and must be non-empty"); + const existingId = slugToExistingId.get(slug); + + return { id: existingId, slug, fieldData }; +}); + +await collection.addItems(items); + +console.log(`Imported ${items.length} items`); + +function toFieldData(value: string, type: FieldType): FieldDataEntryInput { + switch (type) { + case "boolean": + return { type: "boolean" as const, value: value.toLowerCase() === "true" }; + case "number": + return { type: "number" as const, value: parseFloat(value) || 0 }; + case "string": + return { type: "string" as const, value }; + } +} diff --git a/examples/csv-importer/src/load-csv.ts b/examples/csv-importer/src/load-csv.ts new file mode 100644 index 0000000..11b2ada --- /dev/null +++ b/examples/csv-importer/src/load-csv.ts @@ -0,0 +1,52 @@ +import { readFileSync } from "node:fs"; +import Papa from "papaparse"; + +export type FieldType = "string" | "number" | "boolean"; + +export interface CsvData { + columns: string[]; + rows: Record[]; + fieldTypes: Map; +} + +export function loadCsv(path: string): CsvData { + const csvContent = readFileSync(path, "utf-8"); + const { data: rows, meta } = Papa.parse>(csvContent, { + header: true, + skipEmptyLines: true, + transformHeader: (header: string) => header.trim(), + transform: (value: string) => value.trim(), + }); + + if (!meta.fields) { + throw new Error("CSV file has no header row"); + } + + const fieldTypes = new Map(inferFieldTypes(rows, meta.fields)); + + return { columns: meta.fields, rows, fieldTypes }; +} + +function inferFieldType(values: string[]): FieldType { + const nonEmptyValues = values.filter((v) => v !== ""); + if (nonEmptyValues.length === 0) return "string"; + + const allBooleans = nonEmptyValues.every((v) => v === "true" || v === "false"); + if (allBooleans) return "boolean"; + + const allNumbers = nonEmptyValues.every((v) => !Number.isNaN(parseFloat(v)) && Number.isFinite(Number(v))); + if (allNumbers) return "number"; + + return "string"; +} + +/** + * Infer the field types from the data in the CSV file. + * Returns the column name and the inferred field type. + */ +function inferFieldTypes(rows: Record[], columns: string[]): [string, FieldType][] { + return columns.map((column) => { + const values = rows.map((row) => row[column] ?? ""); + return [column, inferFieldType(values)]; + }); +} diff --git a/examples/csv-importer/test.ts b/examples/csv-importer/test.ts deleted file mode 100644 index 28b51e1..0000000 --- a/examples/csv-importer/test.ts +++ /dev/null @@ -1 +0,0 @@ -const _n: string = "1"; diff --git a/package-lock.json b/package-lock.json index 02394a8..801d394 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,202 +1,329 @@ { - "name": "framer-server-api-examples", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "framer-server-api-examples", - "workspaces": [ - "examples/*" - ], - "devDependencies": { - "@biomejs/biome": "2.3.9" - } - }, - "examples/csv-importer": { - "version": "0.0.1", - "dependencies": { - "typescript": "^5.9.3" - } - }, - "node_modules/@biomejs/biome": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.9.tgz", - "integrity": "sha512-js+34KpnY65I00k8P71RH0Uh2rJk4BrpxMGM5m2nBfM9XTlKE5N1URn5ydILPRyXXq4ebhKCjsvR+txS+D4z2A==", - "dev": true, - "license": "MIT OR Apache-2.0", - "bin": { - "biome": "bin/biome" - }, - "engines": { - "node": ">=14.21.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/biome" - }, - "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.3.9", - "@biomejs/cli-darwin-x64": "2.3.9", - "@biomejs/cli-linux-arm64": "2.3.9", - "@biomejs/cli-linux-arm64-musl": "2.3.9", - "@biomejs/cli-linux-x64": "2.3.9", - "@biomejs/cli-linux-x64-musl": "2.3.9", - "@biomejs/cli-win32-arm64": "2.3.9", - "@biomejs/cli-win32-x64": "2.3.9" - } - }, - "node_modules/@biomejs/cli-darwin-arm64": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.9.tgz", - "integrity": "sha512-hHbYYnna/WBwem5iCpssQQLtm5ey8ADuDT8N2zqosk6LVWimlEuUnPy6Mbzgu4GWVriyL5ijWd+1zphX6ll4/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.9.tgz", - "integrity": "sha512-sKMW5fpvGDmPdqCchtVH5MVlbVeSU3ad4CuKS45x8VHt3tNSC8CZ2QbxffAOKYK9v/mAeUiPC6Cx6+wtyU1q7g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.9.tgz", - "integrity": "sha512-BXBB6HbAgZI6T6QB8q6NSwIapVngqArP6K78BqkMerht7YjL6yWctqfeTnJm0qGF2bKBYFexslrbV+VTlM2E6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.9.tgz", - "integrity": "sha512-JOHyG2nl8XDpncbMazm1uBSi1dPX9VbQDOjKcfSVXTqajD0PsgodMOKyuZ/PkBu5Lw877sWMTGKfEfpM7jE7Cw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.9.tgz", - "integrity": "sha512-PjYuv2WLmvf0WtidxAkFjlElsn0P6qcvfPijrqu1j+3GoW3XSQh3ywGu7gZ25J25zrYj3KEovUjvUZB55ATrGw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.9.tgz", - "integrity": "sha512-FUkb/5beCIC2trpqAbW9e095X4vamdlju80c1ExSmhfdrojLZnWkah/XfTSixKb/dQzbAjpD7vvs6rWkJ+P07Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.9.tgz", - "integrity": "sha512-w48Yh/XbYHO2cBw8B5laK3vCAEKuocX5ItGXVDAqFE7Ze2wnR00/1vkY6GXglfRDOjWHu2XtxI0WKQ52x1qxEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-x64": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.9.tgz", - "integrity": "sha512-90+J63VT7qImy9s3pkWL0ZX27VzVwMNCRzpLpe5yMzMYPbO1vcjL/w/Q5f/juAGMvP7a2Fd0H7IhAR6F7/i78A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/csv-importer": { - "resolved": "examples/csv-importer", - "link": true - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } + "name": "framer-server-api-examples", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "framer-server-api-examples", + "workspaces": [ + "examples/*" + ], + "devDependencies": { + "@biomejs/biome": "2.3.9" + } + }, + "examples/csv-importer": { + "version": "0.0.1", + "dependencies": { + "framer-api": "^0.0.1-alpha.6", + "papaparse": "^5.5.3", + "typescript": "^5.9.3" + }, + "devDependencies": { + "@types/node": "^22.10.2", + "@types/papaparse": "^5.3.15" + } + }, + "examples/csv-importer/node_modules/framer-api": { + "version": "0.0.1-alpha.6", + "resolved": "https://registry.npmjs.org/framer-api/-/framer-api-0.0.1-alpha.6.tgz", + "integrity": "sha512-hN4HtQlJzJ14n/ZApWHc7g1bfg7LNOV3ZfrzYm4n1l67WWag2Q/FJJJF/xZ7n085JNsVzWWNt18D80JFiYi6Iw==", + "dependencies": { + "devalue": "^5.4.2", + "unenv": "^2.0.0-rc.24", + "ws": "^8.18.0" + }, + "peerDependencies": { + "react": "^18.2.0", + "typescript": "^5.9.3" + } + }, + "node_modules/@biomejs/biome": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.9.tgz", + "integrity": "sha512-js+34KpnY65I00k8P71RH0Uh2rJk4BrpxMGM5m2nBfM9XTlKE5N1URn5ydILPRyXXq4ebhKCjsvR+txS+D4z2A==", + "dev": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "2.3.9", + "@biomejs/cli-darwin-x64": "2.3.9", + "@biomejs/cli-linux-arm64": "2.3.9", + "@biomejs/cli-linux-arm64-musl": "2.3.9", + "@biomejs/cli-linux-x64": "2.3.9", + "@biomejs/cli-linux-x64-musl": "2.3.9", + "@biomejs/cli-win32-arm64": "2.3.9", + "@biomejs/cli-win32-x64": "2.3.9" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.9.tgz", + "integrity": "sha512-hHbYYnna/WBwem5iCpssQQLtm5ey8ADuDT8N2zqosk6LVWimlEuUnPy6Mbzgu4GWVriyL5ijWd+1zphX6ll4/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.9.tgz", + "integrity": "sha512-sKMW5fpvGDmPdqCchtVH5MVlbVeSU3ad4CuKS45x8VHt3tNSC8CZ2QbxffAOKYK9v/mAeUiPC6Cx6+wtyU1q7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.9.tgz", + "integrity": "sha512-BXBB6HbAgZI6T6QB8q6NSwIapVngqArP6K78BqkMerht7YjL6yWctqfeTnJm0qGF2bKBYFexslrbV+VTlM2E6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.9.tgz", + "integrity": "sha512-JOHyG2nl8XDpncbMazm1uBSi1dPX9VbQDOjKcfSVXTqajD0PsgodMOKyuZ/PkBu5Lw877sWMTGKfEfpM7jE7Cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.9.tgz", + "integrity": "sha512-PjYuv2WLmvf0WtidxAkFjlElsn0P6qcvfPijrqu1j+3GoW3XSQh3ywGu7gZ25J25zrYj3KEovUjvUZB55ATrGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.9.tgz", + "integrity": "sha512-FUkb/5beCIC2trpqAbW9e095X4vamdlju80c1ExSmhfdrojLZnWkah/XfTSixKb/dQzbAjpD7vvs6rWkJ+P07Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.9.tgz", + "integrity": "sha512-w48Yh/XbYHO2cBw8B5laK3vCAEKuocX5ItGXVDAqFE7Ze2wnR00/1vkY6GXglfRDOjWHu2XtxI0WKQ52x1qxEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.9.tgz", + "integrity": "sha512-90+J63VT7qImy9s3pkWL0ZX27VzVwMNCRzpLpe5yMzMYPbO1vcjL/w/Q5f/juAGMvP7a2Fd0H7IhAR6F7/i78A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@types/node": { + "version": "22.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz", + "integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/papaparse": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.5.2.tgz", + "integrity": "sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/csv-importer": { + "resolved": "examples/csv-importer", + "link": true + }, + "node_modules/devalue": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.1.tgz", + "integrity": "sha512-jDwizj+IlEZBunHcOuuFVBnIMPAEHvTsJj0BcIp94xYguLRVBcXO853px/MyIJvbVzWdsGvrRweIUWJw8hBP7A==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/papaparse": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", + "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unenv": { + "version": "2.0.0-rc.24", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", + "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } } - } } diff --git a/tsconfig.base.json b/tsconfig.base.json index 24fbcdd..07b53c8 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -3,11 +3,19 @@ "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", - "strict": true, + "allowImportingTsExtensions": true, "noEmit": true, - "skipLibCheck": true, "esModuleInterop": true, "resolveJsonModule": true, - "isolatedModules": true + "isolatedModules": true, + + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noPropertyAccessFromIndexSignature": true } } From 889b5e7e863801015b9ab04ca51444fa98822b4d Mon Sep 17 00:00:00 2001 From: Elmar Burke Date: Tue, 16 Dec 2025 18:24:25 +0100 Subject: [PATCH 5/5] Disable 'useLiteralKeys' --- biome.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/biome.json b/biome.json index bbcb9b0..5defc99 100644 --- a/biome.json +++ b/biome.json @@ -22,7 +22,9 @@ "enabled": true, "rules": { "recommended": true, - "useLiteralKeys": "off" + "complexity": { + "useLiteralKeys": "off" + } } }, "javascript": {