feat: v1
This commit is contained in:
parent
7ba64d9945
commit
1c620b036f
19 changed files with 2745 additions and 91 deletions
1
.dockerignore
Normal file
1
.dockerignore
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules/
|
||||||
162
.eslintrc.js
Normal file
162
.eslintrc.js
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
👋 Hi! This file was autogenerated by tslint-to-eslint-config.
|
||||||
|
https://github.com/typescript-eslint/tslint-to-eslint-config
|
||||||
|
|
||||||
|
It represents the closest reasonable ESLint configuration to this
|
||||||
|
project's original TSLint configuration.
|
||||||
|
|
||||||
|
We recommend eventually switching this configuration to extend from
|
||||||
|
the recommended rulesets in typescript-eslint.
|
||||||
|
https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md
|
||||||
|
|
||||||
|
Happy linting! 💖
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es6: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||||
|
"prettier",
|
||||||
|
"prettier/@typescript-eslint",
|
||||||
|
],
|
||||||
|
parser: "@typescript-eslint/parser",
|
||||||
|
parserOptions: {
|
||||||
|
project: "tsconfig.json",
|
||||||
|
sourceType: "module",
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
"eslint-plugin-import",
|
||||||
|
"eslint-plugin-jsdoc",
|
||||||
|
"eslint-plugin-prefer-arrow",
|
||||||
|
"@typescript-eslint",
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
"@typescript-eslint/adjacent-overload-signatures": "error",
|
||||||
|
"@typescript-eslint/array-type": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
default: "array",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@typescript-eslint/ban-types": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
types: {
|
||||||
|
Object: {
|
||||||
|
message: "Avoid using the `Object` type. Did you mean `object`?",
|
||||||
|
},
|
||||||
|
Function: {
|
||||||
|
message:
|
||||||
|
"Avoid using the `Function` type. Prefer a specific function type, like `() => void`.",
|
||||||
|
},
|
||||||
|
Boolean: {
|
||||||
|
message: "Avoid using the `Boolean` type. Did you mean `boolean`?",
|
||||||
|
},
|
||||||
|
Number: {
|
||||||
|
message: "Avoid using the `Number` type. Did you mean `number`?",
|
||||||
|
},
|
||||||
|
String: {
|
||||||
|
message: "Avoid using the `String` type. Did you mean `string`?",
|
||||||
|
},
|
||||||
|
Symbol: {
|
||||||
|
message: "Avoid using the `Symbol` type. Did you mean `symbol`?",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@typescript-eslint/consistent-type-assertions": "error",
|
||||||
|
"@typescript-eslint/dot-notation": "error",
|
||||||
|
"@typescript-eslint/naming-convention": "error",
|
||||||
|
"@typescript-eslint/no-empty-function": "error",
|
||||||
|
"@typescript-eslint/no-empty-interface": "error",
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"@typescript-eslint/no-misused-new": "error",
|
||||||
|
"@typescript-eslint/no-namespace": "error",
|
||||||
|
"@typescript-eslint/no-parameter-properties": "off",
|
||||||
|
"@typescript-eslint/no-shadow": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
hoist: "all",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@typescript-eslint/no-unused-expressions": "error",
|
||||||
|
"@typescript-eslint/no-use-before-define": "off",
|
||||||
|
"@typescript-eslint/no-var-requires": "error",
|
||||||
|
"@typescript-eslint/prefer-for-of": "error",
|
||||||
|
"@typescript-eslint/prefer-function-type": "error",
|
||||||
|
"@typescript-eslint/prefer-namespace-keyword": "error",
|
||||||
|
"@typescript-eslint/triple-slash-reference": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
path: "always",
|
||||||
|
types: "prefer-import",
|
||||||
|
lib: "always",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@typescript-eslint/unified-signatures": "error",
|
||||||
|
"comma-dangle": "off",
|
||||||
|
complexity: "off",
|
||||||
|
"constructor-super": "error",
|
||||||
|
"dot-notation": "error",
|
||||||
|
eqeqeq: ["error", "smart"],
|
||||||
|
"guard-for-in": "error",
|
||||||
|
"id-blacklist": [
|
||||||
|
"error",
|
||||||
|
"any",
|
||||||
|
"Number",
|
||||||
|
"number",
|
||||||
|
"String",
|
||||||
|
"string",
|
||||||
|
"Boolean",
|
||||||
|
"boolean",
|
||||||
|
"Undefined",
|
||||||
|
"undefined",
|
||||||
|
],
|
||||||
|
"id-match": "error",
|
||||||
|
"import/order": "off",
|
||||||
|
"jsdoc/check-alignment": "error",
|
||||||
|
"jsdoc/check-indentation": "error",
|
||||||
|
"jsdoc/newline-after-description": "error",
|
||||||
|
"max-classes-per-file": "off",
|
||||||
|
"new-parens": "error",
|
||||||
|
"no-bitwise": "error",
|
||||||
|
"no-caller": "error",
|
||||||
|
"no-cond-assign": "error",
|
||||||
|
"no-console": "off",
|
||||||
|
"no-debugger": "error",
|
||||||
|
"no-empty": "error",
|
||||||
|
"no-empty-function": "error",
|
||||||
|
"no-eval": "error",
|
||||||
|
"no-fallthrough": "off",
|
||||||
|
"no-invalid-this": "off",
|
||||||
|
"no-new-wrappers": "error",
|
||||||
|
"no-shadow": "error",
|
||||||
|
"no-throw-literal": "error",
|
||||||
|
"no-trailing-spaces": "error",
|
||||||
|
"no-undef-init": "error",
|
||||||
|
"no-underscore-dangle": "error",
|
||||||
|
"no-unsafe-finally": "error",
|
||||||
|
"no-unused-expressions": "error",
|
||||||
|
"no-unused-labels": "error",
|
||||||
|
"no-use-before-define": "off",
|
||||||
|
"no-var": "error",
|
||||||
|
"object-shorthand": "error",
|
||||||
|
"one-var": ["error", "never"],
|
||||||
|
"prefer-arrow/prefer-arrow-functions": "error",
|
||||||
|
"prefer-const": "error",
|
||||||
|
radix: "error",
|
||||||
|
"spaced-comment": [
|
||||||
|
"error",
|
||||||
|
"always",
|
||||||
|
{
|
||||||
|
markers: ["/"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"use-isnan": "error",
|
||||||
|
"valid-typeof": "off",
|
||||||
|
},
|
||||||
|
};
|
||||||
110
.gitignore
vendored
110
.gitignore
vendored
|
|
@ -2,129 +2,57 @@
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
.pnpm-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
||||||
|
|
||||||
# Runtime data
|
# Runtime data
|
||||||
pids
|
pids
|
||||||
*.pid
|
*.pid
|
||||||
*.seed
|
*.seed
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
lib-cov
|
lib-cov
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
# Coverage directory used by tools like istanbul
|
||||||
coverage
|
coverage
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
# nyc test coverage
|
||||||
.nyc_output
|
.nyc_output
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
.grunt
|
.grunt
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
# node-waf configuration
|
||||||
.lock-wscript
|
.lock-wscript
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
build/Release
|
build/Release
|
||||||
|
|
||||||
# Dependency directories
|
# Dependency directories
|
||||||
node_modules/
|
node_modules
|
||||||
jspm_packages/
|
jspm_packages
|
||||||
|
|
||||||
# Snowpack dependency directory (https://snowpack.dev/)
|
|
||||||
web_modules/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
# Optional npm cache directory
|
||||||
.npm
|
.npm
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional stylelint cache
|
|
||||||
.stylelintcache
|
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
# Optional REPL history
|
||||||
.node_repl_history
|
.node_repl_history
|
||||||
|
|
||||||
# Output of 'npm pack'
|
# 0x
|
||||||
*.tgz
|
profile-*
|
||||||
|
|
||||||
# Yarn Integrity file
|
# mac files
|
||||||
.yarn-integrity
|
.DS_Store
|
||||||
|
|
||||||
# dotenv environment variable files
|
# vim swap files
|
||||||
.env
|
*.swp
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
.env.local
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
# webstorm
|
||||||
.cache
|
.idea
|
||||||
.parcel-cache
|
|
||||||
|
|
||||||
# Next.js build output
|
# vscode
|
||||||
.next
|
.vscode
|
||||||
out
|
*code-workspace
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
# clinic
|
||||||
.nuxt
|
profile*
|
||||||
dist
|
*clinic*
|
||||||
|
*flamegraph*
|
||||||
# Gatsby files
|
|
||||||
.cache/
|
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# vuepress v2.x temp and cache directory
|
|
||||||
.temp
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# Docusaurus cache and generated files
|
|
||||||
.docusaurus
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
# Stores VSCode versions used for testing VSCode extensions
|
|
||||||
.vscode-test
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/cache
|
|
||||||
.yarn/unplugged
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
||||||
|
|
|
||||||
8
.prettierrc
Executable file
8
.prettierrc
Executable file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"printWidth": 100,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": false,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"arrowParens": "always",
|
||||||
|
"jsxBracketSameLine": false
|
||||||
|
}
|
||||||
27
Dockerfile
Normal file
27
Dockerfile
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
FROM node:22.0.0
|
||||||
|
|
||||||
|
WORKDIR /api
|
||||||
|
|
||||||
|
|
||||||
|
## RUN apt-get update && \
|
||||||
|
## apt-get -y install xvfb gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 \
|
||||||
|
## libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 \
|
||||||
|
## libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 \
|
||||||
|
## libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 \
|
||||||
|
## libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget unzip graphicsmagick
|
||||||
|
##
|
||||||
|
## ## install chromium
|
||||||
|
## RUN wget -q 'https://playwright.azureedge.net/builds/chromium/1127/chromium-linux-arm64.zip'
|
||||||
|
## RUN unzip chromium-linux-arm64.zip
|
||||||
|
## RUN rm -f ./chromium-linux-arm64.zip
|
||||||
|
|
||||||
|
COPY package.json ./
|
||||||
|
COPY package-lock.json ./
|
||||||
|
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
CMD npm run start
|
||||||
26
Dockerfile.dev
Normal file
26
Dockerfile.dev
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
FROM node:22.0.0
|
||||||
|
# Create app directory
|
||||||
|
|
||||||
|
WORKDIR /api
|
||||||
|
|
||||||
|
|
||||||
|
## RUN apt-get update && \
|
||||||
|
## apt-get -y install xvfb gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 \
|
||||||
|
## libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 \
|
||||||
|
## libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 \
|
||||||
|
## libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 \
|
||||||
|
## libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget unzip graphicsmagick
|
||||||
|
##
|
||||||
|
## ## install chromium
|
||||||
|
## RUN wget -q 'https://playwright.azureedge.net/builds/chromium/1127/chromium-linux-arm64.zip'
|
||||||
|
## RUN unzip chromium-linux-arm64.zip
|
||||||
|
## RUN rm -f ./chromium-linux-arm64.zip
|
||||||
|
|
||||||
|
COPY *.json ./
|
||||||
|
COPY start.js ./
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
|
||||||
|
## Launch the wait tool and then your application
|
||||||
|
CMD npm run dev
|
||||||
16
docker-compose.prod.yaml
Normal file
16
docker-compose.prod.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "3010:3010"
|
||||||
|
volumes:
|
||||||
|
- ./src:/api/src/
|
||||||
|
environment:
|
||||||
|
NODE_ENV: "production"
|
||||||
|
TZ: Europe/Berlin
|
||||||
|
WAIT_HOSTS: mariadb:3306
|
||||||
|
SUPABASE_URL: https://bcgdtkjbsxloiqfhtcfa.supabase.co
|
||||||
|
SUPABASE_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJjZ2R0a2pic3hsb2lxZmh0Y2ZhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mjg3NDQ3MTAsImV4cCI6MjA0NDMyMDcxMH0.DxcwwyxU8_dfqBhBHnCYA7Cpciet9XGYg3jxmju9tLQ
|
||||||
|
|
||||||
21
docker-compose.yaml
Normal file
21
docker-compose.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
ports:
|
||||||
|
- "3010:3010"
|
||||||
|
volumes:
|
||||||
|
- ./src:/api/src/
|
||||||
|
environment:
|
||||||
|
NODE_ENV: "development"
|
||||||
|
TZ: Europe/Berlin
|
||||||
|
WAIT_HOSTS: mariadb:3306
|
||||||
|
MYSQL_HOST: mariadb
|
||||||
|
MYSQL_USER: docker
|
||||||
|
SUPABASE_URL: https://bcgdtkjbsxloiqfhtcfa.supabase.co
|
||||||
|
SUPABASE_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJjZ2R0a2pic3hsb2lxZmh0Y2ZhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mjg3NDQ3MTAsImV4cCI6MjA0NDMyMDcxMH0.DxcwwyxU8_dfqBhBHnCYA7Cpciet9XGYg3jxmju9tLQ
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
wool-mysql:
|
||||||
|
|
||||||
10
nodemon.json
Executable file
10
nodemon.json
Executable file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"watch": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"ext": "ts",
|
||||||
|
"exec": "ts-node --files ./src/app.ts",
|
||||||
|
"args": [
|
||||||
|
"--inspect=5858"
|
||||||
|
]
|
||||||
|
}
|
||||||
1798
package-lock.json
generated
Normal file
1798
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
30
package.json
Normal file
30
package.json
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "wooldatafetcher",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc -p tsconfig.json",
|
||||||
|
"start": "ts-node --files ./src/app.ts",
|
||||||
|
"dev": "nodemon"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/supabase-js": "^2.45.4",
|
||||||
|
"@types/uuid": "^10.0.0",
|
||||||
|
"axios": "^1.7.3",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
|
"fastify": "^5.0.0",
|
||||||
|
"jsdom": "^25.0.1",
|
||||||
|
"uuid": "^10.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jsdom": "^21.1.7",
|
||||||
|
"@types/node": "^22.7.5",
|
||||||
|
"nodemon": "^3.1.4",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.6.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/Helpers.ts
Normal file
3
src/Helpers.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const OnlyKeepDigits = (Input: string): string => {
|
||||||
|
return Input.replace(/\D/g, "");
|
||||||
|
};
|
||||||
352
src/LanaGrossaIntegration.ts
Normal file
352
src/LanaGrossaIntegration.ts
Normal file
|
|
@ -0,0 +1,352 @@
|
||||||
|
import axios from "axios";
|
||||||
|
import { JSDOM } from "jsdom";
|
||||||
|
import { OnlyKeepDigits } from "./Helpers";
|
||||||
|
import { SupabaseInstance } from "./Supabase";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
export type TWoolFetcherStats = {
|
||||||
|
FoundLinks: number;
|
||||||
|
Date: string;
|
||||||
|
UpdatedWools: number;
|
||||||
|
NewWools: number;
|
||||||
|
UpdatedVariants: number;
|
||||||
|
NewVariants: number;
|
||||||
|
Errors: number;
|
||||||
|
ErrorLinks: string[];
|
||||||
|
ErrorVariants: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class LanaGrossaIntegration {
|
||||||
|
public CurrentStats: TWoolFetcherStats = {
|
||||||
|
FoundLinks: 0,
|
||||||
|
Date: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
Errors: 0,
|
||||||
|
ErrorLinks: [],
|
||||||
|
ErrorVariants: 0,
|
||||||
|
UpdatedWools: 0,
|
||||||
|
NewWools: 0,
|
||||||
|
UpdatedVariants: 0,
|
||||||
|
NewVariants: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
public StatList: TWoolFetcherStats[] = [];
|
||||||
|
|
||||||
|
public LinkQueue: string[] = [];
|
||||||
|
|
||||||
|
private async FindLinks(): Promise<string[]> {
|
||||||
|
const Links: string[] = [];
|
||||||
|
|
||||||
|
let HasMore = true;
|
||||||
|
let Page = 1;
|
||||||
|
|
||||||
|
while (HasMore) {
|
||||||
|
const Params: any = {
|
||||||
|
action: "products-overview",
|
||||||
|
locale: "de_DE",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Page > 1) {
|
||||||
|
Params.pg = Page;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ParamsParts = [];
|
||||||
|
for (const Key of Object.keys(Params)) {
|
||||||
|
ParamsParts.push(`${Key}=${Params[Key]}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Response = await axios.get("https://www.lana-grossa.de/wp/wp-admin/admin-ajax.php", {
|
||||||
|
params: Params,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Response.data.items === "") {
|
||||||
|
HasMore = false;
|
||||||
|
} else {
|
||||||
|
Page += 1;
|
||||||
|
|
||||||
|
const LinkBase = "https://www.lana-grossa.de/garne/detail/";
|
||||||
|
|
||||||
|
const HTML: string = Response.data.items;
|
||||||
|
|
||||||
|
const Matches = HTML.match(/<a href="([^"]+)"/g);
|
||||||
|
|
||||||
|
if (Matches) {
|
||||||
|
for (const Match of Matches) {
|
||||||
|
const Link = Match.replace('<a href="', "").replace('"', "");
|
||||||
|
|
||||||
|
if (Link.startsWith(LinkBase)) {
|
||||||
|
Links.push(Link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Links;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async RunFetcher(): Promise<void> {
|
||||||
|
// refetch links if empty
|
||||||
|
if (this.LinkQueue.length === 0) {
|
||||||
|
this.LinkQueue = await this.FindLinks();
|
||||||
|
this.CurrentStats = {
|
||||||
|
FoundLinks: this.LinkQueue.length,
|
||||||
|
Date: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
Errors: 0,
|
||||||
|
ErrorLinks: [],
|
||||||
|
ErrorVariants: 0,
|
||||||
|
UpdatedWools: 0,
|
||||||
|
NewWools: 0,
|
||||||
|
UpdatedVariants: 0,
|
||||||
|
NewVariants: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// run through 10 links
|
||||||
|
const LinksToProcess = this.LinkQueue.splice(0, 10);
|
||||||
|
|
||||||
|
for (const Link of LinksToProcess) {
|
||||||
|
const Stats = await this.ExtractDataFromPage(Link);
|
||||||
|
|
||||||
|
if (Stats.IsError) {
|
||||||
|
this.CurrentStats.Errors += 1;
|
||||||
|
this.CurrentStats.ErrorLinks.push(Link);
|
||||||
|
}
|
||||||
|
if (Stats.IsNew) {
|
||||||
|
this.CurrentStats.NewWools += 1;
|
||||||
|
} else {
|
||||||
|
this.CurrentStats.UpdatedWools += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Stats.IsVariantError) {
|
||||||
|
this.CurrentStats.ErrorVariants += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.CurrentStats.UpdatedVariants += Stats.VariantsUpdated;
|
||||||
|
this.CurrentStats.NewVariants += Stats.VariantsNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.LinkQueue.length === 0) {
|
||||||
|
// add to top of list
|
||||||
|
this.StatList.unshift(this.CurrentStats);
|
||||||
|
|
||||||
|
// only keep 10 stats in statlist
|
||||||
|
if (this.StatList.length > 10) {
|
||||||
|
this.StatList.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ExtractDataFromPage(Link: string): Promise<{
|
||||||
|
IsNew: boolean;
|
||||||
|
IsVariantError: boolean;
|
||||||
|
IsError: boolean;
|
||||||
|
VariantsUpdated: number;
|
||||||
|
VariantsNew: number;
|
||||||
|
}> {
|
||||||
|
const Stats = {
|
||||||
|
IsNew: false,
|
||||||
|
IsError: false,
|
||||||
|
IsVariantError: false,
|
||||||
|
VariantsUpdated: 0,
|
||||||
|
VariantsNew: 0,
|
||||||
|
};
|
||||||
|
const PageResponse = await axios.get(Link);
|
||||||
|
|
||||||
|
if (PageResponse.status !== 200) {
|
||||||
|
Stats.IsError = true;
|
||||||
|
return Stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HTML: string = PageResponse.data;
|
||||||
|
|
||||||
|
const Dom = new JSDOM(HTML);
|
||||||
|
const Document = Dom.window.document;
|
||||||
|
|
||||||
|
// get name
|
||||||
|
const Name = Document.querySelector(".page-headline .text-title1").textContent;
|
||||||
|
|
||||||
|
// get weight
|
||||||
|
const WeightText = Document.querySelector(".details-list .weight").textContent;
|
||||||
|
let Weight: number = 0;
|
||||||
|
if (WeightText.toLocaleLowerCase().indexOf("kg") > 0) {
|
||||||
|
Weight = parseFloat(WeightText.replace("kg", "").trim()) * 1000;
|
||||||
|
} else if (WeightText.toLocaleLowerCase().indexOf("g") > 0) {
|
||||||
|
Weight = parseFloat(WeightText.replace("g", "").trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
// get run length
|
||||||
|
const RunLengthText = Document.querySelector(".details-list .length").textContent;
|
||||||
|
let RunLength: number = 0;
|
||||||
|
if (RunLengthText.toLocaleLowerCase().indexOf("m") > 0) {
|
||||||
|
RunLength = parseFloat(RunLengthText.replace("m", "").trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
// get needle size
|
||||||
|
let NeedleSizeMin: number | null = null;
|
||||||
|
let NeedleSizeMax: number | null = null;
|
||||||
|
|
||||||
|
if (Document.querySelector(".details-list .needle-size") != null) {
|
||||||
|
const NeedleSizeText = Document.querySelector(".details-list .needle-size").textContent;
|
||||||
|
|
||||||
|
if (NeedleSizeText.indexOf("-") > 0) {
|
||||||
|
const Parts = NeedleSizeText.split("-");
|
||||||
|
if (Parts.length === 2) {
|
||||||
|
NeedleSizeMin = parseFloat(Parts[0].replace(",", "."));
|
||||||
|
NeedleSizeMax = parseFloat(Parts[1].replace(",", "."));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NeedleSizeMin = parseFloat(NeedleSizeText.replace(",", "."));
|
||||||
|
NeedleSizeMax = parseFloat(NeedleSizeText.replace(",", "."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get stitch test
|
||||||
|
let StitchTestR: number | null = 0;
|
||||||
|
let StitchTestM: number | null = 0;
|
||||||
|
|
||||||
|
if (Document.querySelector(".details-list .mesh-probe") != null) {
|
||||||
|
const StitchTestText = Document.querySelector(".details-list .mesh-probe")?.textContent;
|
||||||
|
const StichTestParts = StitchTestText.split(",");
|
||||||
|
if (StichTestParts.length === 2) {
|
||||||
|
StitchTestR = parseFloat(OnlyKeepDigits(StichTestParts[0]));
|
||||||
|
StitchTestM = parseFloat(OnlyKeepDigits(StichTestParts[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get composition
|
||||||
|
const CompositionElements = Document.querySelectorAll(".module-material-details > .lc > p");
|
||||||
|
const Composition: string[] = [];
|
||||||
|
for (const Element of CompositionElements) {
|
||||||
|
Composition.push(Element.textContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Key = "LanaGrossa_" + Name + "_" + Weight;
|
||||||
|
|
||||||
|
// check if already exists
|
||||||
|
const Existing = await SupabaseInstance.from("Wool")
|
||||||
|
.select("id, updated_at", { count: "exact" })
|
||||||
|
.eq("key", Key);
|
||||||
|
|
||||||
|
let UUID = Existing.data[0]?.id;
|
||||||
|
|
||||||
|
if (Existing.count == null || Existing.count == 0) {
|
||||||
|
Stats.IsNew = true;
|
||||||
|
const Result = await SupabaseInstance.from("Wool")
|
||||||
|
.insert({
|
||||||
|
name: Name,
|
||||||
|
key: Key,
|
||||||
|
weight: Weight,
|
||||||
|
maker: "LanaGrossa",
|
||||||
|
run_length: RunLength,
|
||||||
|
composition: Composition,
|
||||||
|
needle_size_max: NeedleSizeMax,
|
||||||
|
needle_size_min: NeedleSizeMin,
|
||||||
|
stitch_test_m: StitchTestM,
|
||||||
|
stitch_test_r: StitchTestR,
|
||||||
|
})
|
||||||
|
.select("id");
|
||||||
|
|
||||||
|
UUID = Result.data[0].id;
|
||||||
|
} else {
|
||||||
|
// only if updated_at is older than 1 day
|
||||||
|
Stats.IsNew = false;
|
||||||
|
|
||||||
|
const UpdatedAt = Existing.data[0].updated_at;
|
||||||
|
if (dayjs().diff(dayjs(UpdatedAt), "day") < 1) {
|
||||||
|
console.log(
|
||||||
|
"Skipping",
|
||||||
|
Name,
|
||||||
|
"as it was updated less than a day ago, also skipping variants",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update
|
||||||
|
await SupabaseInstance.from("Wool")
|
||||||
|
.update({
|
||||||
|
maker: "LanaGrossa",
|
||||||
|
run_length: RunLength,
|
||||||
|
composition: Composition,
|
||||||
|
needle_size_max: NeedleSizeMax,
|
||||||
|
needle_size_min: NeedleSizeMin,
|
||||||
|
stitch_test_m: StitchTestM,
|
||||||
|
stitch_test_r: StitchTestR,
|
||||||
|
updated_at: dayjs().toISOString(),
|
||||||
|
})
|
||||||
|
.eq("key", Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract variants
|
||||||
|
const JavaScripts = Document.querySelectorAll("body > script");
|
||||||
|
|
||||||
|
let EanScript = null;
|
||||||
|
|
||||||
|
for (const ScriptObject of JavaScripts) {
|
||||||
|
const Script = ScriptObject.textContent;
|
||||||
|
|
||||||
|
if (Script.indexOf("eans") > -1) {
|
||||||
|
EanScript = Script;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EanScript != null) {
|
||||||
|
Dom.window.eval(EanScript.replaceAll("var ", ""));
|
||||||
|
|
||||||
|
const EANs: string[] = Dom.window.eval("eans") as any;
|
||||||
|
const ColorNames: string[] = Dom.window.eval("colorNames") as any;
|
||||||
|
const ColorCodes: string[] = Dom.window.eval("colorCodes") as any;
|
||||||
|
|
||||||
|
if (EANs.length !== ColorNames.length || EANs.length !== ColorCodes.length) {
|
||||||
|
console.error("Lengths do not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let Index = 0; Index < EANs.length; Index++) {
|
||||||
|
const EAN = EANs[Index];
|
||||||
|
const ColorName = ColorNames[Index];
|
||||||
|
const ColorCode = ColorCodes[Index];
|
||||||
|
|
||||||
|
const VariantKey = "LanaGrossa_" + Name + "_" + EAN;
|
||||||
|
|
||||||
|
const ExistingVariant = await SupabaseInstance.from("WoolVariants")
|
||||||
|
.select("id, updated_at", { count: "exact" })
|
||||||
|
.eq("key", VariantKey);
|
||||||
|
|
||||||
|
if (ExistingVariant.count == null || ExistingVariant.count == 0) {
|
||||||
|
Stats.VariantsNew += 1;
|
||||||
|
await SupabaseInstance.from("WoolVariants").insert({
|
||||||
|
key: VariantKey,
|
||||||
|
wool_id: UUID,
|
||||||
|
ean: EAN,
|
||||||
|
color_name: ColorName,
|
||||||
|
color_code: ColorCode,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Stats.VariantsUpdated += 1;
|
||||||
|
// only if updated_at is older than 1 day
|
||||||
|
const UpdatedAt = Existing.data[0].updated_at;
|
||||||
|
if (dayjs().diff(dayjs(UpdatedAt), "day") < 1) {
|
||||||
|
console.log("Skipping Variant", EAN, "as it was updated less than a day ago");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update
|
||||||
|
await SupabaseInstance.from("WoolVariants")
|
||||||
|
.update({
|
||||||
|
wool_id: UUID,
|
||||||
|
color: ColorName,
|
||||||
|
color_name: ColorName,
|
||||||
|
color_code: ColorCode,
|
||||||
|
updated_at: dayjs().toISOString(),
|
||||||
|
})
|
||||||
|
.eq("key", VariantKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Stats.IsVariantError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stats;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/Supabase.ts
Normal file
7
src/Supabase.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { createClient } from "@supabase/supabase-js";
|
||||||
|
import { Database } from "supabase";
|
||||||
|
|
||||||
|
export const SupabaseInstance = createClient<Database>(
|
||||||
|
process.env.SUPABASE_URL,
|
||||||
|
process.env.SUPABASE_KEY,
|
||||||
|
);
|
||||||
33
src/app.ts
Normal file
33
src/app.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import fastify from "fastify";
|
||||||
|
import LanaGrossaIntegration from "./LanaGrossaIntegration";
|
||||||
|
|
||||||
|
const server = fastify();
|
||||||
|
|
||||||
|
const LanaGrossaIntegrationInstance = new LanaGrossaIntegration();
|
||||||
|
|
||||||
|
// start update every 24 hours
|
||||||
|
setInterval(() => {
|
||||||
|
LanaGrossaIntegrationInstance.RunFetcher();
|
||||||
|
}, 1000 * 60 * 60 * 1);
|
||||||
|
LanaGrossaIntegrationInstance.RunFetcher();
|
||||||
|
|
||||||
|
server.get("/stats", async (request, reply) => {
|
||||||
|
const CurrentStats = LanaGrossaIntegrationInstance.CurrentStats;
|
||||||
|
const StatList = LanaGrossaIntegrationInstance.StatList;
|
||||||
|
|
||||||
|
const RemainingLinks = LanaGrossaIntegrationInstance.LinkQueue.length;
|
||||||
|
|
||||||
|
return {
|
||||||
|
RemainingLinks,
|
||||||
|
CurrentStats,
|
||||||
|
StatList,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen({ port: 3010, host: "0.0.0.0" }, (err, address) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`Server listening at ${address}`);
|
||||||
|
});
|
||||||
191
src/types/supabase.ts
Normal file
191
src/types/supabase.ts
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
export type Json =
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null
|
||||||
|
| { [key: string]: Json | undefined }
|
||||||
|
| Json[]
|
||||||
|
|
||||||
|
export type Database = {
|
||||||
|
public: {
|
||||||
|
Tables: {
|
||||||
|
Wool: {
|
||||||
|
Row: {
|
||||||
|
composition: string[] | null
|
||||||
|
created_at: string
|
||||||
|
id: string
|
||||||
|
key: string
|
||||||
|
maker: Database["public"]["Enums"]["WoolMaker"] | null
|
||||||
|
name: string
|
||||||
|
needle_size_max: number | null
|
||||||
|
needle_size_min: number | null
|
||||||
|
run_length: number | null
|
||||||
|
stitch_test_m: number | null
|
||||||
|
stitch_test_r: number | null
|
||||||
|
updated_at: string | null
|
||||||
|
weight: number | null
|
||||||
|
}
|
||||||
|
Insert: {
|
||||||
|
composition?: string[] | null
|
||||||
|
created_at?: string
|
||||||
|
id?: string
|
||||||
|
key: string
|
||||||
|
maker?: Database["public"]["Enums"]["WoolMaker"] | null
|
||||||
|
name?: string
|
||||||
|
needle_size_max?: number | null
|
||||||
|
needle_size_min?: number | null
|
||||||
|
run_length?: number | null
|
||||||
|
stitch_test_m?: number | null
|
||||||
|
stitch_test_r?: number | null
|
||||||
|
updated_at?: string | null
|
||||||
|
weight?: number | null
|
||||||
|
}
|
||||||
|
Update: {
|
||||||
|
composition?: string[] | null
|
||||||
|
created_at?: string
|
||||||
|
id?: string
|
||||||
|
key?: string
|
||||||
|
maker?: Database["public"]["Enums"]["WoolMaker"] | null
|
||||||
|
name?: string
|
||||||
|
needle_size_max?: number | null
|
||||||
|
needle_size_min?: number | null
|
||||||
|
run_length?: number | null
|
||||||
|
stitch_test_m?: number | null
|
||||||
|
stitch_test_r?: number | null
|
||||||
|
updated_at?: string | null
|
||||||
|
weight?: number | null
|
||||||
|
}
|
||||||
|
Relationships: []
|
||||||
|
}
|
||||||
|
WoolVariants: {
|
||||||
|
Row: {
|
||||||
|
color: string | null
|
||||||
|
created_at: string
|
||||||
|
ean: string | null
|
||||||
|
id: string
|
||||||
|
key: string | null
|
||||||
|
wool_id: string | null
|
||||||
|
}
|
||||||
|
Insert: {
|
||||||
|
color?: string | null
|
||||||
|
created_at?: string
|
||||||
|
ean?: string | null
|
||||||
|
id?: string
|
||||||
|
key?: string | null
|
||||||
|
wool_id?: string | null
|
||||||
|
}
|
||||||
|
Update: {
|
||||||
|
color?: string | null
|
||||||
|
created_at?: string
|
||||||
|
ean?: string | null
|
||||||
|
id?: string
|
||||||
|
key?: string | null
|
||||||
|
wool_id?: string | null
|
||||||
|
}
|
||||||
|
Relationships: [
|
||||||
|
{
|
||||||
|
foreignKeyName: "WoolVariants_wool_id_fkey"
|
||||||
|
columns: ["wool_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "Wool"
|
||||||
|
referencedColumns: ["id"]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Views: {
|
||||||
|
[_ in never]: never
|
||||||
|
}
|
||||||
|
Functions: {
|
||||||
|
[_ in never]: never
|
||||||
|
}
|
||||||
|
Enums: {
|
||||||
|
WoolMaker: "LanaGrossa"
|
||||||
|
}
|
||||||
|
CompositeTypes: {
|
||||||
|
[_ in never]: never
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PublicSchema = Database[Extract<keyof Database, "public">]
|
||||||
|
|
||||||
|
export type Tables<
|
||||||
|
PublicTableNameOrOptions extends
|
||||||
|
| keyof (PublicSchema["Tables"] & PublicSchema["Views"])
|
||||||
|
| { schema: keyof Database },
|
||||||
|
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
|
||||||
|
? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
|
||||||
|
Database[PublicTableNameOrOptions["schema"]]["Views"])
|
||||||
|
: never = never,
|
||||||
|
> = PublicTableNameOrOptions extends { schema: keyof Database }
|
||||||
|
? (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
|
||||||
|
Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends {
|
||||||
|
Row: infer R
|
||||||
|
}
|
||||||
|
? R
|
||||||
|
: never
|
||||||
|
: PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] &
|
||||||
|
PublicSchema["Views"])
|
||||||
|
? (PublicSchema["Tables"] &
|
||||||
|
PublicSchema["Views"])[PublicTableNameOrOptions] extends {
|
||||||
|
Row: infer R
|
||||||
|
}
|
||||||
|
? R
|
||||||
|
: never
|
||||||
|
: never
|
||||||
|
|
||||||
|
export type TablesInsert<
|
||||||
|
PublicTableNameOrOptions extends
|
||||||
|
| keyof PublicSchema["Tables"]
|
||||||
|
| { schema: keyof Database },
|
||||||
|
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
|
||||||
|
? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
|
||||||
|
: never = never,
|
||||||
|
> = PublicTableNameOrOptions extends { schema: keyof Database }
|
||||||
|
? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
|
||||||
|
Insert: infer I
|
||||||
|
}
|
||||||
|
? I
|
||||||
|
: never
|
||||||
|
: PublicTableNameOrOptions extends keyof PublicSchema["Tables"]
|
||||||
|
? PublicSchema["Tables"][PublicTableNameOrOptions] extends {
|
||||||
|
Insert: infer I
|
||||||
|
}
|
||||||
|
? I
|
||||||
|
: never
|
||||||
|
: never
|
||||||
|
|
||||||
|
export type TablesUpdate<
|
||||||
|
PublicTableNameOrOptions extends
|
||||||
|
| keyof PublicSchema["Tables"]
|
||||||
|
| { schema: keyof Database },
|
||||||
|
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
|
||||||
|
? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
|
||||||
|
: never = never,
|
||||||
|
> = PublicTableNameOrOptions extends { schema: keyof Database }
|
||||||
|
? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
|
||||||
|
Update: infer U
|
||||||
|
}
|
||||||
|
? U
|
||||||
|
: never
|
||||||
|
: PublicTableNameOrOptions extends keyof PublicSchema["Tables"]
|
||||||
|
? PublicSchema["Tables"][PublicTableNameOrOptions] extends {
|
||||||
|
Update: infer U
|
||||||
|
}
|
||||||
|
? U
|
||||||
|
: never
|
||||||
|
: never
|
||||||
|
|
||||||
|
export type Enums<
|
||||||
|
PublicEnumNameOrOptions extends
|
||||||
|
| keyof PublicSchema["Enums"]
|
||||||
|
| { schema: keyof Database },
|
||||||
|
EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database }
|
||||||
|
? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"]
|
||||||
|
: never = never,
|
||||||
|
> = PublicEnumNameOrOptions extends { schema: keyof Database }
|
||||||
|
? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName]
|
||||||
|
: PublicEnumNameOrOptions extends keyof PublicSchema["Enums"]
|
||||||
|
? PublicSchema["Enums"][PublicEnumNameOrOptions]
|
||||||
|
: never
|
||||||
14
start.js
Executable file
14
start.js
Executable file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Transpile all code following this line with babel and use '@babel/preset-env' (aka ES6) preset.
|
||||||
|
require("@babel/register")({
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
targets: { browsers: ["last 2 chrome versions"] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Import the rest of our application.
|
||||||
|
module.exports = require("./src/app.ts");
|
||||||
5
supabase-generate-types.sh
Executable file
5
supabase-generate-types.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
||||||
|
## Set access Token
|
||||||
|
export SUPABASE_ACCESS_TOKEN=sbp_9a95062bb5df26f382ea79d0d43c6570f4071af8
|
||||||
|
|
||||||
|
## Generate types
|
||||||
|
npx --yes supabase gen types typescript --project-id "bcgdtkjbsxloiqfhtcfa" --schema public >src/types/supabase.ts
|
||||||
22
tsconfig.json
Normal file
22
tsconfig.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "commonjs",
|
||||||
|
// "lib": [],
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"*": ["node_modules/*", "src/types/*"]
|
||||||
|
},
|
||||||
|
"typeRoots": ["src/types/"]
|
||||||
|
// "rootDirs": [],
|
||||||
|
// "typeRoots": [],
|
||||||
|
// "types": [],
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue