-
Notifications
You must be signed in to change notification settings - Fork 0
Initialise TypeScript for packages and have first complex example #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| EXAMPLE_PROJECT_URL=https://framer.com/projects/Sites--aabbccddeeff | ||
| FRAMER_API_KEY=12345678-1234-1234-1234-123456789 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,40 +1,43 @@ | ||
| { | ||
| "$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, | ||
| "complexity": { | ||
| "useLiteralKeys": "off" | ||
| } | ||
| } | ||
| }, | ||
| "javascript": { | ||
| "formatter": { | ||
| "quoteStyle": "double" | ||
| } | ||
| }, | ||
| "assist": { | ||
| "enabled": true, | ||
| "actions": { | ||
| "source": { | ||
| "organizeImports": "on" | ||
| } | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| { | ||
| "name": "csv-importer", | ||
| "version": "0.0.1", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "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" | ||
| } | ||
| } |
elmarburke marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
elmarburke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // 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 }; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<string, string>[]; | ||
| fieldTypes: Map<string, FieldType>; | ||
| } | ||
|
|
||
| export function loadCsv(path: string): CsvData { | ||
| const csvContent = readFileSync(path, "utf-8"); | ||
| const { data: rows, meta } = Papa.parse<Record<string, string>>(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<string, string>[], columns: string[]): [string, FieldType][] { | ||
| return columns.map((column) => { | ||
| const values = rows.map((row) => row[column] ?? ""); | ||
| return [column, inferFieldType(values)]; | ||
| }); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "extends": "../../tsconfig.base.json", | ||
| "include": ["**/*.ts"] | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.