init project with pixelfed fetcher

This commit is contained in:
Travis Shears 2024-06-24 15:42:35 +02:00
commit cf01dea155
12 changed files with 929 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
node_modules
.serverless
.env
.yarn/

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
v20

1
.yarnrc.yml Normal file
View file

@ -0,0 +1 @@
nodeLinker: "node-modules"

56
README.md Normal file
View file

@ -0,0 +1,56 @@
<!--
title: 'AWS Node Scheduled Cron example in NodeJS'
description: 'This is an example of creating a function that runs as a cron job using the serverless ''schedule'' event.'
layout: Doc
framework: v4
platform: AWS
language: nodeJS
priority: 1
authorLink: 'https://github.com/0dj0bz'
authorName: 'Rob Abbott'
authorAvatar: 'https://avatars3.githubusercontent.com/u/5679763?v=4&s=140'
-->
# Serverless Framework Node Scheduled Cron on AWS
This template demonstrates how to develop and deploy a simple cron-like service running on AWS Lambda using the Serverless Framework.
This examples defines a single function, `rateHandler` which is triggered by an event of `schedule` type at a rate of 1 per minute. For detailed information about `schedule` event, please refer to corresponding section of Serverless [docs](https://serverless.com/framework/docs/providers/aws/events/schedule/).
## Usage
### Deployment
In order to deploy the example, you need to run the following command:
```
serverless deploy
```
After running deploy, you should see output similar to:
```
Deploying "aws-node-scheduled-cron" to stage "dev" (us-east-1)
✔ Service deployed to stack aws-node-scheduled-cron-dev (151s)
functions:
rateHandler: aws-node-scheduled-cron-dev-rateHandler (2.3 kB)
```
There is no additional step required. Your defined schedules becomes active right away after deployment.
### Local development
The easiest way to develop and test your function is to use the `dev` command:
```
serverless dev
```
This will start a local emulator of AWS Lambda and tunnel your requests to and from AWS Lambda, allowing you to interact with your function as if it were running in the cloud.
Now you can invoke the function as before, but this time the function will be executed locally. Now you can develop your function locally, invoke it, and see the results immediately without having to re-deploy.
When you are done developing, don't forget to run `serverless deploy` to deploy the function to the cloud.

View file

@ -0,0 +1,17 @@
meta {
name: Get Pixelfed Feed
type: http
seq: 1
}
get {
url: https://gram.social/api/pixelfed/v1/accounts/703621281309160235/statuses?limit=9&only_media=true&min_id=1
body: none
auth: none
}
query {
limit: 9
only_media: true
min_id: 1
}

View file

@ -0,0 +1,9 @@
{
"version": "1",
"name": "MicroBlogFetchders",
"type": "collection",
"ignore": [
"node_modules",
".git"
]
}

14
package.json Normal file
View file

@ -0,0 +1,14 @@
{
"scripts": {
"deploy": "serverless deploy",
"dev": "serverless dev"
},
"devDependencies": {
"@types/node": "^20.14.8",
"prettier": "^3.3.2",
"serverless": "4"
},
"dependencies": {
"pocketbase": "^0.21.3"
}
}

20
serverless.yml Normal file
View file

@ -0,0 +1,20 @@
# "org" ensures this Service is used with the correct Serverless Framework Access Key.
org: travisshears
# "app" enables Serverless Framework Dashboard features and sharing them with other Services.
app: micro-blog
# "service" is the name of this project. This will also be added to your AWS resource names.
service: micro-blog-fetchers
provider:
name: aws
runtime: nodejs20.x
region: eu-central-1
environment:
POCKET_BASE_PW: ${env:POCKET_BASE_PW}
POCKET_BASE_USER: ${env:POCKET_BASE_USER}
functions:
pixelfed:
handler: src/pixelfed.run
events:
- schedule: rate(1 hour)

99
src/pixelfed.ts Normal file
View file

@ -0,0 +1,99 @@
const baseURL = `https://gram.social/api/pixelfed/v1/accounts/`;
const accountID = `703621281309160235`;
import { microBlogBackend as pb } from "./pocketbase";
type PixelFedPost = {
media_attachments: {
type: string; //'image',
url: string; // 'https://gram.social/storage/m/_v2/703621281309160235/530d83cd3-f15549/FR41GdSiUQY0/bNHMrzuQkuhXKKfR1zG4HHcjFTe6G2YF02SOr2zi.jpg',
description: string; // 'Blurry gate',
}[];
id: string;
content: string;
account: {
id: string;
};
created_at: string;
tags: { name: string }[];
};
const getPostUntilId = async ({
lastSavedId,
maxId,
carryPosts = [],
}: {
lastSavedId?: string;
maxId?: string;
carryPosts?: PixelFedPost[];
}): Promise<PixelFedPost[]> => {
const params = new URLSearchParams();
params.append("limit", "5");
params.append("only_media", "true");
if (maxId) {
params.append("max_id", maxId);
}
const urlWithParams = new URL(`${baseURL}${accountID}/statuses`);
urlWithParams.search = params.toString();
const res = await fetch(urlWithParams.toString());
const posts = (await res.json()) as PixelFedPost[];
const containsId = posts.some((post) => post.id === lastSavedId);
if (!containsId && posts.length >= 5) {
return getPostUntilId({
lastSavedId,
carryPosts: carryPosts?.concat(posts),
maxId: posts[posts.length - 1]?.id,
});
}
const allPosts = carryPosts?.concat(posts).reverse();
if (lastSavedId) {
const index = allPosts.findIndex((post) => post.id === lastSavedId);
return allPosts.slice(index + 1);
}
return allPosts;
};
const savePost = async (post: PixelFedPost) => {
const postData = {
remoteId: post.id,
authorId: post.account.id,
posted: post.created_at,
source: "pixelfed" as const,
fullPost: post,
};
return await pb.savePost(postData);
};
const saveTags = async (post: PixelFedPost, postId: string) => {
console.log({ tags: post.tags }, "saving tags");
for (const tag of post.tags) {
await pb.setTag(tag.name, postId);
}
};
const saveImages = async (post: PixelFedPost, postId: string) => {
console.log({ images: post.media_attachments }, "saving images");
for (const image of post.media_attachments) {
await pb.saveAndSetImage(
{ remoteURL: image.url, alt: image.description },
postId
);
}
};
exports.run = async () => {
const lastSavedPostId = await pb.getLatestPostId("pixelfed");
const posts = await getPostUntilId({ lastSavedId: lastSavedPostId });
const post = posts[0];
if (post) {
console.log({ post }, "saving post");
const savedNewPost = await savePost(post);
if (savedNewPost) {
await saveTags(post, savedNewPost.id);
await saveImages(post, savedNewPost.id);
}
}
};

202
src/pocketbase.ts Normal file
View file

@ -0,0 +1,202 @@
import PocketBase from "pocketbase";
export type MicroBlogPostImage = {
id: string;
collectionId: string;
image: string;
alt?: string;
remoteURL: string;
};
export type MicroBlogPostTag = {
id: string;
tag: string;
};
export type MicroBlogPostSource =
| "blue_sky"
| "mastodon"
| "pleroma"
| "pixelfed";
export type MicroBlogPost = {
source: MicroBlogPostSource;
fullPost: any;
remoteId: string;
authorId: string;
id: string;
expand: {
images?: MicroBlogPostImage[];
tags?: {
id: string;
}[];
};
};
class MicroBlogBackend {
private pb: PocketBase;
private clientSetTime?: Date;
constructor() {
this.pb = new PocketBase("https://personal-pocket-base.fly.dev");
}
private async login() {
const pw = process.env.POCKET_BASE_PW!;
const userName = process.env.POCKET_BASE_USER!;
console.log({ userName }, "Logging in to pocketbase");
await this.pb.collection("users").authWithPassword(userName, pw);
this.clientSetTime = new Date();
}
private async checkLogin() {
if (!this.clientSetTime) {
await this.login();
return;
}
const now = new Date();
const diff = now.getTime() - this.clientSetTime.getTime();
const day = 86_400_000;
if (diff > day) {
await this.login();
return;
}
}
public async getLatestPostId(
postSource: MicroBlogPostSource
): Promise<string | undefined> {
await this.checkLogin();
try {
const post = await this.pb
.collection<MicroBlogPost>("micro_blog_posts")
.getFirstListItem(`source = '${postSource}'`, { sort: "-posted" });
return post.id;
} catch (error: any) {
if (error.status === 404) {
return undefined;
}
throw error;
}
}
async getTag(tag: string): Promise<MicroBlogPostTag | undefined> {
await this.checkLogin();
try {
const remoteTag = await this.pb
.collection<MicroBlogPostTag>("micro_blog_tags")
.getFirstListItem(`tag = '${tag}'`);
return remoteTag;
} catch (e: any) {
if (e.status === 404) {
return undefined;
}
throw e;
}
}
async getImageByRemoteURL(
remoteURL: string
): Promise<MicroBlogPostImage | undefined> {
await this.checkLogin();
try {
const remoteImage = await this.pb
.collection<MicroBlogPostImage>("micro_blog_images")
.getFirstListItem(`remoteURL = '${remoteURL}'`);
return remoteImage;
} catch (e: any) {
if (e.status === 404) {
return undefined;
}
throw e;
}
}
private async checkForPost(
remoteId: string
): Promise<MicroBlogPost | undefined> {
await this.checkLogin();
try {
return await this.pb
.collection<MicroBlogPost>("micro_blog_posts")
.getFirstListItem(`remoteId = '${remoteId}'`);
} catch (e: any) {
if (e.status === 404) {
return undefined;
}
throw e;
}
}
public async savePost(
post: Omit<MicroBlogPost, "id" | "expand">
): Promise<MicroBlogPost> {
const existingPost = await this.checkForPost(post.remoteId);
if (!existingPost) {
return await this.pb
.collection<MicroBlogPost>("micro_blog_posts")
.create(post);
}
return existingPost;
}
public async setTag(rawTag: string, postId: string) {
let tag = await this.getTag(rawTag);
if (!tag) {
tag = await this.pb
.collection<MicroBlogPostTag>("micro_blog_tags")
.create({ tag: rawTag });
}
if (!tag) {
throw new Error("Failed to create tag");
}
await this.pb.collection("micro_blog_posts").update(postId, {
"tags+": tag.id,
});
}
public async saveAndSetImage(
imageToSave: Omit<MicroBlogPostImage, "id" | "image" | "collectionId">,
postId: string
) {
let image = await this.getImageByRemoteURL(imageToSave.remoteURL);
if (!image) {
const imageResponse = await fetch(imageToSave.remoteURL);
if (!imageResponse.ok) {
throw new Error("Failed to download image");
}
const imageBlob = await imageResponse.blob();
const imageFile = new File([imageBlob], "image.jpg", {
type: imageBlob.type,
});
const data = {
...imageToSave,
image: imageFile,
};
image = await this.pb
.collection<MicroBlogPostTag>("micro_blog_images")
.create(data);
}
if (!image) {
throw new Error("Failed to create image");
}
await this.pb.collection("micro_blog_posts").update(postId, {
"images+": image.id,
});
}
public async getPosts(page: number, limit = 20) {
await this.checkLogin();
const resultList = await this.pb
.collection<MicroBlogPost>("micro_blog_posts")
.getList(page, limit, {
sort: "-posted",
expand: "images,tags",
filter: `(source = "blue_sky" || source = "pleroma")`,
// filter: 'source = "pleroma"',
});
return resultList;
}
}
export const microBlogBackend = new MicroBlogBackend();

27
tsconfig.json Normal file
View file

@ -0,0 +1,27 @@
{
"compilerOptions": {
"esModuleInterop": true,
"skipLibCheck": true,
"target": "es2022",
"allowJs": true,
"resolveJsonModule": true,
"moduleDetection": "force",
"isolatedModules": true,
"verbatimModuleSyntax": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"module": "preserve",
"noEmit": true,
"lib": [
"es2022"
]
},
"include": [
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}

479
yarn.lock Normal file
View file

@ -0,0 +1,479 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0
"@isaacs/cliui@npm:^8.0.2":
version: 8.0.2
resolution: "@isaacs/cliui@npm:8.0.2"
dependencies:
string-width: "npm:^5.1.2"
string-width-cjs: "npm:string-width@^4.2.0"
strip-ansi: "npm:^7.0.1"
strip-ansi-cjs: "npm:strip-ansi@^6.0.1"
wrap-ansi: "npm:^8.1.0"
wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0"
checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e
languageName: node
linkType: hard
"@pkgjs/parseargs@npm:^0.11.0":
version: 0.11.0
resolution: "@pkgjs/parseargs@npm:0.11.0"
checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd
languageName: node
linkType: hard
"@types/node@npm:^20.14.8":
version: 20.14.8
resolution: "@types/node@npm:20.14.8"
dependencies:
undici-types: "npm:~5.26.4"
checksum: 10c0/06d4643fa3b179b41fe19f9c75c240278ca1f7a313b3b837bc36ea119499c7ad77f06bbe72694ac04aa91ec77fe747baa09b889f4c435450c1724a26bd55f160
languageName: node
linkType: hard
"ansi-regex@npm:^5.0.1":
version: 5.0.1
resolution: "ansi-regex@npm:5.0.1"
checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737
languageName: node
linkType: hard
"ansi-regex@npm:^6.0.1":
version: 6.0.1
resolution: "ansi-regex@npm:6.0.1"
checksum: 10c0/cbe16dbd2c6b2735d1df7976a7070dd277326434f0212f43abf6d87674095d247968209babdaad31bb00882fa68807256ba9be340eec2f1004de14ca75f52a08
languageName: node
linkType: hard
"ansi-styles@npm:^4.0.0":
version: 4.3.0
resolution: "ansi-styles@npm:4.3.0"
dependencies:
color-convert: "npm:^2.0.1"
checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041
languageName: node
linkType: hard
"ansi-styles@npm:^6.1.0":
version: 6.2.1
resolution: "ansi-styles@npm:6.2.1"
checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c
languageName: node
linkType: hard
"asynckit@npm:^0.4.0":
version: 0.4.0
resolution: "asynckit@npm:0.4.0"
checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d
languageName: node
linkType: hard
"axios-proxy-builder@npm:^0.1.2":
version: 0.1.2
resolution: "axios-proxy-builder@npm:0.1.2"
dependencies:
tunnel: "npm:^0.0.6"
checksum: 10c0/8724099b72efa1f114b1edf9b6dba7a5ea7518b30d0bdef93b5107ae147afb1bd94c10817580e7b53bfc675b37fe99c5c784bb9fe13481ebf9d9560c1ff68591
languageName: node
linkType: hard
"axios@npm:^1.6.0":
version: 1.7.2
resolution: "axios@npm:1.7.2"
dependencies:
follow-redirects: "npm:^1.15.6"
form-data: "npm:^4.0.0"
proxy-from-env: "npm:^1.1.0"
checksum: 10c0/cbd47ce380fe045313364e740bb03b936420b8b5558c7ea36a4563db1258c658f05e40feb5ddd41f6633fdd96d37ac2a76f884dad599c5b0224b4c451b3fa7ae
languageName: node
linkType: hard
"balanced-match@npm:^1.0.0":
version: 1.0.2
resolution: "balanced-match@npm:1.0.2"
checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee
languageName: node
linkType: hard
"brace-expansion@npm:^2.0.1":
version: 2.0.1
resolution: "brace-expansion@npm:2.0.1"
dependencies:
balanced-match: "npm:^1.0.0"
checksum: 10c0/b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f
languageName: node
linkType: hard
"color-convert@npm:^2.0.1":
version: 2.0.1
resolution: "color-convert@npm:2.0.1"
dependencies:
color-name: "npm:~1.1.4"
checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7
languageName: node
linkType: hard
"color-name@npm:~1.1.4":
version: 1.1.4
resolution: "color-name@npm:1.1.4"
checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95
languageName: node
linkType: hard
"combined-stream@npm:^1.0.8":
version: 1.0.8
resolution: "combined-stream@npm:1.0.8"
dependencies:
delayed-stream: "npm:~1.0.0"
checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5
languageName: node
linkType: hard
"cross-spawn@npm:^7.0.0":
version: 7.0.3
resolution: "cross-spawn@npm:7.0.3"
dependencies:
path-key: "npm:^3.1.0"
shebang-command: "npm:^2.0.0"
which: "npm:^2.0.1"
checksum: 10c0/5738c312387081c98d69c98e105b6327b069197f864a60593245d64c8089c8a0a744e16349281210d56835bb9274130d825a78b2ad6853ca13cfbeffc0c31750
languageName: node
linkType: hard
"delayed-stream@npm:~1.0.0":
version: 1.0.0
resolution: "delayed-stream@npm:1.0.0"
checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19
languageName: node
linkType: hard
"eastasianwidth@npm:^0.2.0":
version: 0.2.0
resolution: "eastasianwidth@npm:0.2.0"
checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39
languageName: node
linkType: hard
"emoji-regex@npm:^8.0.0":
version: 8.0.0
resolution: "emoji-regex@npm:8.0.0"
checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010
languageName: node
linkType: hard
"emoji-regex@npm:^9.2.2":
version: 9.2.2
resolution: "emoji-regex@npm:9.2.2"
checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639
languageName: node
linkType: hard
"follow-redirects@npm:^1.15.6":
version: 1.15.6
resolution: "follow-redirects@npm:1.15.6"
peerDependenciesMeta:
debug:
optional: true
checksum: 10c0/9ff767f0d7be6aa6870c82ac79cf0368cd73e01bbc00e9eb1c2a16fbb198ec105e3c9b6628bb98e9f3ac66fe29a957b9645bcb9a490bb7aa0d35f908b6b85071
languageName: node
linkType: hard
"foreground-child@npm:^3.1.0":
version: 3.2.1
resolution: "foreground-child@npm:3.2.1"
dependencies:
cross-spawn: "npm:^7.0.0"
signal-exit: "npm:^4.0.1"
checksum: 10c0/9a53a33dbd87090e9576bef65fb4a71de60f6863a8062a7b11bc1cbe3cc86d428677d7c0b9ef61cdac11007ac580006f78bd5638618d564cfd5e6fd713d6878f
languageName: node
linkType: hard
"form-data@npm:^4.0.0":
version: 4.0.0
resolution: "form-data@npm:4.0.0"
dependencies:
asynckit: "npm:^0.4.0"
combined-stream: "npm:^1.0.8"
mime-types: "npm:^2.1.12"
checksum: 10c0/cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e
languageName: node
linkType: hard
"glob@npm:^10.3.7":
version: 10.4.2
resolution: "glob@npm:10.4.2"
dependencies:
foreground-child: "npm:^3.1.0"
jackspeak: "npm:^3.1.2"
minimatch: "npm:^9.0.4"
minipass: "npm:^7.1.2"
package-json-from-dist: "npm:^1.0.0"
path-scurry: "npm:^1.11.1"
bin:
glob: dist/esm/bin.mjs
checksum: 10c0/2c7296695fa75a935f3ad17dc62e4e170a8bb8752cf64d328be8992dd6ad40777939003754e10e9741ff8fbe43aa52fba32d6930d0ffa0e3b74bc3fb5eebaa2f
languageName: node
linkType: hard
"is-fullwidth-code-point@npm:^3.0.0":
version: 3.0.0
resolution: "is-fullwidth-code-point@npm:3.0.0"
checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc
languageName: node
linkType: hard
"isexe@npm:^2.0.0":
version: 2.0.0
resolution: "isexe@npm:2.0.0"
checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d
languageName: node
linkType: hard
"jackspeak@npm:^3.1.2":
version: 3.4.0
resolution: "jackspeak@npm:3.4.0"
dependencies:
"@isaacs/cliui": "npm:^8.0.2"
"@pkgjs/parseargs": "npm:^0.11.0"
dependenciesMeta:
"@pkgjs/parseargs":
optional: true
checksum: 10c0/7e42d1ea411b4d57d43ea8a6afbca9224382804359cb72626d0fc45bb8db1de5ad0248283c3db45fe73e77210750d4fcc7c2b4fe5d24fda94aaa24d658295c5f
languageName: node
linkType: hard
"lru-cache@npm:^10.2.0":
version: 10.2.2
resolution: "lru-cache@npm:10.2.2"
checksum: 10c0/402d31094335851220d0b00985084288136136992979d0e015f0f1697e15d1c86052d7d53ae86b614e5b058425606efffc6969a31a091085d7a2b80a8a1e26d6
languageName: node
linkType: hard
"mime-db@npm:1.52.0":
version: 1.52.0
resolution: "mime-db@npm:1.52.0"
checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa
languageName: node
linkType: hard
"mime-types@npm:^2.1.12":
version: 2.1.35
resolution: "mime-types@npm:2.1.35"
dependencies:
mime-db: "npm:1.52.0"
checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2
languageName: node
linkType: hard
"minimatch@npm:^9.0.4":
version: 9.0.4
resolution: "minimatch@npm:9.0.4"
dependencies:
brace-expansion: "npm:^2.0.1"
checksum: 10c0/2c16f21f50e64922864e560ff97c587d15fd491f65d92a677a344e970fe62aafdbeafe648965fa96d33c061b4d0eabfe0213466203dd793367e7f28658cf6414
languageName: node
linkType: hard
"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.1.2":
version: 7.1.2
resolution: "minipass@npm:7.1.2"
checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557
languageName: node
linkType: hard
"package-json-from-dist@npm:^1.0.0":
version: 1.0.0
resolution: "package-json-from-dist@npm:1.0.0"
checksum: 10c0/e3ffaf6ac1040ab6082a658230c041ad14e72fabe99076a2081bb1d5d41210f11872403fc09082daf4387fc0baa6577f96c9c0e94c90c394fd57794b66aa4033
languageName: node
linkType: hard
"path-key@npm:^3.1.0":
version: 3.1.1
resolution: "path-key@npm:3.1.1"
checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c
languageName: node
linkType: hard
"path-scurry@npm:^1.11.1":
version: 1.11.1
resolution: "path-scurry@npm:1.11.1"
dependencies:
lru-cache: "npm:^10.2.0"
minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0"
checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d
languageName: node
linkType: hard
"pocketbase@npm:^0.21.3":
version: 0.21.3
resolution: "pocketbase@npm:0.21.3"
checksum: 10c0/8753b3a577f1b205d2639630b6a0808ef10ab66982a67ef7cfeaa5c069f3674e04690f92c09297da8876a66370dbb5735831098fd570c54dd3ad158386e70bc2
languageName: node
linkType: hard
"prettier@npm:^3.3.2":
version: 3.3.2
resolution: "prettier@npm:3.3.2"
bin:
prettier: bin/prettier.cjs
checksum: 10c0/39ed27d17f0238da6dd6571d63026566bd790d3d0edac57c285fbab525982060c8f1e01955fe38134ab10f0951a6076da37f015db8173c02f14bc7f0803a384c
languageName: node
linkType: hard
"proxy-from-env@npm:^1.1.0":
version: 1.1.0
resolution: "proxy-from-env@npm:1.1.0"
checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b
languageName: node
linkType: hard
"rimraf@npm:^5.0.5":
version: 5.0.7
resolution: "rimraf@npm:5.0.7"
dependencies:
glob: "npm:^10.3.7"
bin:
rimraf: dist/esm/bin.mjs
checksum: 10c0/bd6dbfaa98ae34ce1e54d1e06045d2d63e8859d9a1979bb4a4628b652b459a2d17b17dc20ee072b034bd2d09bd691e801d24c4d9cfe94e16fdbcc8470a1d4807
languageName: node
linkType: hard
"root-workspace-0b6124@workspace:.":
version: 0.0.0-use.local
resolution: "root-workspace-0b6124@workspace:."
dependencies:
"@types/node": "npm:^20.14.8"
pocketbase: "npm:^0.21.3"
prettier: "npm:^3.3.2"
serverless: "npm:4"
languageName: unknown
linkType: soft
"serverless@npm:4":
version: 4.1.5
resolution: "serverless@npm:4.1.5"
dependencies:
axios: "npm:^1.6.0"
axios-proxy-builder: "npm:^0.1.2"
rimraf: "npm:^5.0.5"
bin:
serverless: run.js
sls: run.js
checksum: 10c0/e7e1ef19f303b26b333c0ebd22833dc66d8c4415aaa62ee4838c92806c50a56c9cdc4285a48bae2eb94df260dd43403751db5865a97b1abff0d71a8143965f59
languageName: node
linkType: hard
"shebang-command@npm:^2.0.0":
version: 2.0.0
resolution: "shebang-command@npm:2.0.0"
dependencies:
shebang-regex: "npm:^3.0.0"
checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e
languageName: node
linkType: hard
"shebang-regex@npm:^3.0.0":
version: 3.0.0
resolution: "shebang-regex@npm:3.0.0"
checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690
languageName: node
linkType: hard
"signal-exit@npm:^4.0.1":
version: 4.1.0
resolution: "signal-exit@npm:4.1.0"
checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83
languageName: node
linkType: hard
"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0":
version: 4.2.3
resolution: "string-width@npm:4.2.3"
dependencies:
emoji-regex: "npm:^8.0.0"
is-fullwidth-code-point: "npm:^3.0.0"
strip-ansi: "npm:^6.0.1"
checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b
languageName: node
linkType: hard
"string-width@npm:^5.0.1, string-width@npm:^5.1.2":
version: 5.1.2
resolution: "string-width@npm:5.1.2"
dependencies:
eastasianwidth: "npm:^0.2.0"
emoji-regex: "npm:^9.2.2"
strip-ansi: "npm:^7.0.1"
checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca
languageName: node
linkType: hard
"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1":
version: 6.0.1
resolution: "strip-ansi@npm:6.0.1"
dependencies:
ansi-regex: "npm:^5.0.1"
checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952
languageName: node
linkType: hard
"strip-ansi@npm:^7.0.1":
version: 7.1.0
resolution: "strip-ansi@npm:7.1.0"
dependencies:
ansi-regex: "npm:^6.0.1"
checksum: 10c0/a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4
languageName: node
linkType: hard
"tunnel@npm:^0.0.6":
version: 0.0.6
resolution: "tunnel@npm:0.0.6"
checksum: 10c0/e27e7e896f2426c1c747325b5f54efebc1a004647d853fad892b46d64e37591ccd0b97439470795e5262b5c0748d22beb4489a04a0a448029636670bfd801b75
languageName: node
linkType: hard
"undici-types@npm:~5.26.4":
version: 5.26.5
resolution: "undici-types@npm:5.26.5"
checksum: 10c0/bb673d7876c2d411b6eb6c560e0c571eef4a01c1c19925175d16e3a30c4c428181fb8d7ae802a261f283e4166a0ac435e2f505743aa9e45d893f9a3df017b501
languageName: node
linkType: hard
"which@npm:^2.0.1":
version: 2.0.2
resolution: "which@npm:2.0.2"
dependencies:
isexe: "npm:^2.0.0"
bin:
node-which: ./bin/node-which
checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f
languageName: node
linkType: hard
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version: 7.0.0
resolution: "wrap-ansi@npm:7.0.0"
dependencies:
ansi-styles: "npm:^4.0.0"
string-width: "npm:^4.1.0"
strip-ansi: "npm:^6.0.0"
checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da
languageName: node
linkType: hard
"wrap-ansi@npm:^8.1.0":
version: 8.1.0
resolution: "wrap-ansi@npm:8.1.0"
dependencies:
ansi-styles: "npm:^6.1.0"
string-width: "npm:^5.0.1"
strip-ansi: "npm:^7.0.1"
checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60
languageName: node
linkType: hard