Setting up more printful logic. Setting up db.
This commit is contained in:
@@ -1 +1,4 @@
|
||||
api
|
||||
node_modules/
|
||||
.env.*
|
||||
./database/data.db
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.2.11",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@types/bun": ["@types/bun@1.2.11", "", { "dependencies": { "bun-types": "1.2.11" } }, "sha512-ZLbbI91EmmGwlWTRWuV6J19IUiUC5YQ3TCEuSHI3usIP75kuoA8/0PVF+LTrbEnVc8JIhpElWOxv1ocI1fJBbw=="],
|
||||
|
||||
"@types/node": ["@types/node@22.15.3", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-dbkp5Lo8HDrXkLrONm6bk+yiiYQSntvFUzQp0v3pzTAsXk6FtgVMjdQ+lzFNVAmQFUkPQZ3WMZqH5tTo+Dp/IA=="],
|
||||
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
CREATE TABLE IF NOT EXISTS products (
|
||||
webflowProductId INTEGER NOT NULL,
|
||||
printfulProductId INTEGER NOT NULL,
|
||||
UNIQUE(webflowProductId, printfulProductId)
|
||||
)
|
||||
@@ -1 +1,33 @@
|
||||
console.log("Hello world");
|
||||
import { Printful } from "./printful.ts"
|
||||
import { ProductRecords } from "./storage.ts"
|
||||
|
||||
const productRecords = new ProductRecords();
|
||||
|
||||
const server = Bun.serve({
|
||||
routes: {
|
||||
"/webhook/printful": {
|
||||
async POST(req) {
|
||||
const payload: Printful.Webhook.EventPayload = await req.json()
|
||||
|
||||
switch (payload.type) {
|
||||
case Printful.Webhook.Event.ProductUpdated:
|
||||
const productRecord = productRecords.findFromPrintful(payload.data.sync_product.id)
|
||||
if (productRecord) {
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
break;
|
||||
case Printful.Webhook.Event.ProductDeleted:
|
||||
break;
|
||||
}
|
||||
|
||||
return Response.json("Hello world")
|
||||
}
|
||||
}
|
||||
},
|
||||
development: true
|
||||
})
|
||||
|
||||
console.log(`Listening on ${server.url}`);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.2.11"
|
||||
},
|
||||
"scripts": {
|
||||
"db:seed": "sqlite3 ./database/data.db < ./database/seed.sql"
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
export namespace Printful {
|
||||
const API_ROUTE = "https://api.printful.com/store";
|
||||
|
||||
export namespace Webhook {
|
||||
// meta
|
||||
interface MetaData {
|
||||
created: number;
|
||||
retries: number;
|
||||
store: number;
|
||||
}
|
||||
|
||||
export enum Event {
|
||||
ProductUpdated = "product_updated",
|
||||
ProductDeleted = "product_deleted"
|
||||
}
|
||||
|
||||
// product updated
|
||||
export interface ProductUpdated extends MetaData {
|
||||
type: Event.ProductUpdated,
|
||||
data: {
|
||||
sync_product: {
|
||||
id: number;
|
||||
external_id: string;
|
||||
name: string;
|
||||
variants: number;
|
||||
synced: number;
|
||||
thumbnail_url: string;
|
||||
is_ignored: boolean;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// product deleted
|
||||
export interface ProductDeleted extends MetaData {
|
||||
type: Event.ProductDeleted,
|
||||
data: {
|
||||
sync_product: {
|
||||
id: number;
|
||||
external_id: string;
|
||||
name: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export type EventPayload = ProductUpdated | ProductDeleted
|
||||
}
|
||||
|
||||
export namespace Products {
|
||||
interface MetaData<T = any> {
|
||||
code: number;
|
||||
result: T;
|
||||
}
|
||||
|
||||
interface Option {
|
||||
id: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface File {
|
||||
type: string;
|
||||
id: number;
|
||||
url: string;
|
||||
options: Option[];
|
||||
hash: string;
|
||||
filename: string;
|
||||
mime_type: string;
|
||||
size: number;
|
||||
width: number;
|
||||
height: number;
|
||||
dpi: number;
|
||||
status: string;
|
||||
created: number;
|
||||
thumbnail_url: string;
|
||||
preview_url: string;
|
||||
visible: boolean;
|
||||
is_temporary: boolean;
|
||||
stitch_count_tier: string;
|
||||
}
|
||||
|
||||
interface SyncProductData {
|
||||
id: number;
|
||||
external_id: string;
|
||||
sync_product_id: number;
|
||||
name: string;
|
||||
synced: boolean;
|
||||
variant_id: number;
|
||||
retail_price: string;
|
||||
currency: string;
|
||||
is_ignored: boolean;
|
||||
sku: string;
|
||||
product: {
|
||||
variant_id: number;
|
||||
product_id: number;
|
||||
image: string;
|
||||
name: string;
|
||||
};
|
||||
files: File[];
|
||||
options: Option[];
|
||||
main_category_id: number;
|
||||
warehouse_product_id: number;
|
||||
warehouse_product_variant_id: number;
|
||||
size: string;
|
||||
color: string;
|
||||
availability_status: string;
|
||||
}
|
||||
export type SyncProduct = MetaData<SyncProductData>;
|
||||
}
|
||||
|
||||
export async function getSyncProduct(syncProductId: String): Promise<Products.SyncProduct> {
|
||||
const payload: Products.SyncProduct = await (
|
||||
await fetch(`${API_ROUTE}/products/${syncProductId}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${Bun.env.PRINTFUL_AUTH}`,
|
||||
"X-PF-Store-Id": `${Bun.env.PRINTFUL_STORE_ID}`
|
||||
}
|
||||
})
|
||||
).json();
|
||||
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
interface ProductsRecord {
|
||||
webflowProductId: number;
|
||||
printfulProductId: number;
|
||||
}
|
||||
|
||||
export class ProductRecords {
|
||||
private db: Database;
|
||||
|
||||
constructor() {
|
||||
this.db = new Database("./database/data.db");
|
||||
}
|
||||
|
||||
findFromWebflow(webflowProductId: number): ProductsRecord | undefined {
|
||||
const row = this.db.query(`
|
||||
SELECT * FROM product_records WHERE webflowProductId = ?
|
||||
`).get(webflowProductId);
|
||||
|
||||
return row as ProductsRecord | undefined;
|
||||
}
|
||||
|
||||
findFromPrintful(printfulProductId: number): ProductsRecord | undefined {
|
||||
const row = this.db.query(`
|
||||
SELECT * FROM product_records WHERE printfulProductId = ?
|
||||
`).get(printfulProductId);
|
||||
|
||||
return row as ProductsRecord | undefined;
|
||||
}
|
||||
|
||||
add(record: ProductsRecord): void {
|
||||
this.db.run(`
|
||||
INSERT OR IGNORE INTO product_records (webflowProductId, printfulProductId)
|
||||
VALUES (?, ?)
|
||||
`, [record.webflowProductId, record.printfulProductId]);
|
||||
}
|
||||
|
||||
all(): ProductsRecord[] {
|
||||
return this.db.query(`SELECT * FROM product_records`).all() as ProductsRecord[];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user