Compare commits

..

3 Commits

Author SHA1 Message Date
Rıdvan Akca
84ecf105c2 feat(bluesky): add search post by url action 2024-05-28 10:05:09 +02:00
Rıdvan Akca
c07a02ef31 feat(bluesky): add create post action 2024-05-28 10:04:19 +02:00
Rıdvan Akca
3c44f55f19 feat(bluesky): add bluesky integration 2024-05-28 10:03:49 +02:00
30 changed files with 322 additions and 806 deletions

View File

@@ -20,6 +20,7 @@
"db:migrate": "node ./bin/database/convert-migrations.js && knex migrate:latest"
},
"dependencies": {
"@atproto/api": "^0.12.13",
"@bull-board/express": "^3.10.1",
"@casl/ability": "^6.5.0",
"@graphql-tools/graphql-file-loader": "^7.3.4",

View File

@@ -0,0 +1,41 @@
import { BskyAgent, RichText } from '@atproto/api';
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create post',
key: 'createPost',
description: 'Creates a new post.',
arguments: [
{
label: 'Text',
key: 'text',
type: 'string',
required: true,
variables: true,
description: '',
},
],
async run($) {
const text = $.step.parameters.text;
const agent = new BskyAgent({ service: 'https://bsky.social/xrpc' });
const richText = new RichText({ text });
await richText.detectFacets(agent);
const body = {
repo: $.auth.data.did,
collection: 'app.bsky.feed.post',
record: {
$type: 'app.bsky.feed.post',
text: richText.text,
facets: richText.facets,
createdAt: new Date().toISOString(),
},
};
const { data } = await $.http.post('/com.atproto.repo.createRecord', body);
$.setActionItem({ raw: data });
},
});

View File

@@ -0,0 +1,4 @@
import createPost from './create-post/index.js';
import searchPostByUrl from './search-post-by-url/index.js';
export default [createPost, searchPostByUrl];

View File

@@ -0,0 +1,35 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Search post by url',
key: 'searchPostByUrl',
description: 'Searches a post in a thread by url.',
arguments: [
{
label: 'Post Url',
key: 'postUrl',
type: 'string',
required: true,
variables: true,
description: 'Enter whole post url here.',
},
],
async run($) {
const postUrl = $.step.parameters.postUrl;
const urlParts = postUrl.split('/');
const handle = urlParts[urlParts.length - 3];
const postId = urlParts[urlParts.length - 1];
const uri = `at://${handle}/app.bsky.feed.post/${postId}`;
const params = {
uri,
};
const { data } = await $.http.get('/app.bsky.feed.getPostThread', {
params,
});
$.setActionItem({ raw: data });
},
});

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-50 -50 430 390" fill="#1185fd" aria-hidden="true">
<path d="M180 141.964C163.699 110.262 119.308 51.1817 78.0347 22.044C38.4971 -5.86834 23.414 -1.03207 13.526 3.43594C2.08093 8.60755 0 26.1785 0 36.5164C0 46.8542 5.66748 121.272 9.36416 133.694C21.5786 174.738 65.0603 188.607 105.104 184.156C107.151 183.852 109.227 183.572 111.329 183.312C109.267 183.642 107.19 183.924 105.104 184.156C46.4204 192.847 -5.69621 214.233 62.6582 290.33C137.848 368.18 165.705 273.637 180 225.702C194.295 273.637 210.76 364.771 295.995 290.33C360 225.702 313.58 192.85 254.896 184.158C252.81 183.926 250.733 183.645 248.671 183.315C250.773 183.574 252.849 183.855 254.896 184.158C294.94 188.61 338.421 174.74 350.636 133.697C354.333 121.275 360 46.8568 360 36.519C360 26.1811 357.919 8.61012 346.474 3.43851C336.586 -1.02949 321.503 -5.86576 281.965 22.0466C240.692 51.1843 196.301 110.262 180 141.964Z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 956 B

View File

@@ -0,0 +1,34 @@
import verifyCredentials from './verify-credentials.js';
import isStillVerified from './is-still-verified.js';
import refreshToken from './refresh-token.js';
export default {
fields: [
{
key: 'handle',
label: 'Your Bluesky Handle',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: '',
clickToCopy: false,
},
{
key: 'password',
label: 'Your Bluesky Password',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: '',
clickToCopy: false,
},
],
verifyCredentials,
isStillVerified,
refreshToken,
};

View File

@@ -0,0 +1,8 @@
import getCurrentUser from '../common/get-current-user.js';
const isStillVerified = async ($) => {
const currentUser = await getCurrentUser($);
return !!currentUser.did;
};
export default isStillVerified;

View File

@@ -0,0 +1,24 @@
const refreshToken = async ($) => {
const { refreshJwt } = $.auth.data;
const { data } = await $.http.post(
'/com.atproto.server.refreshSession',
null,
{
headers: {
Authorization: `Bearer ${refreshJwt}`,
},
additionalProperties: {
skipAddingAuthHeader: true,
},
}
);
await $.auth.set({
accessJwt: data.accessJwt,
refreshJwt: data.refreshJwt,
did: data.did,
});
};
export default refreshToken;

View File

@@ -0,0 +1,20 @@
const verifyCredentials = async ($) => {
const handle = $.auth.data.handle;
const password = $.auth.data.password;
const body = {
identifier: handle,
password,
};
const { data } = await $.http.post('/com.atproto.server.createSession', body);
await $.auth.set({
accessJwt: data.accessJwt,
refreshJwt: data.refreshJwt,
did: data.did,
screenName: data.handle,
});
};
export default verifyCredentials;

View File

@@ -0,0 +1,12 @@
const addAuthHeader = ($, requestConfig) => {
if (requestConfig.additionalProperties?.skipAddingAuthHeader)
return requestConfig;
if ($.auth.data?.accessJwt) {
requestConfig.headers.Authorization = `Bearer ${$.auth.data.accessJwt}`;
}
return requestConfig;
};
export default addAuthHeader;

View File

@@ -0,0 +1,15 @@
const getCurrentUser = async ($) => {
const handle = $.auth.data.handle;
const params = {
actor: handle,
};
const { data: currentUser } = await $.http.get('/app.bsky.actor.getProfile', {
params,
});
return currentUser;
};
export default getCurrentUser;

View File

@@ -0,0 +1,18 @@
import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js';
import actions from './actions/index.js';
export default defineApp({
name: 'Bluesky',
key: 'bluesky',
iconUrl: '{BASE_URL}/apps/bluesky/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/bluesky/connection',
supportsConnections: true,
baseUrl: 'https://bluesky.app',
apiBaseUrl: 'https://bsky.social/xrpc',
primaryColor: '1185fd',
beforeRequest: [addAuthHeader],
auth,
actions,
});

View File

@@ -1,262 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
import isEmpty from 'lodash/isEmpty.js';
import omitBy from 'lodash/omitBy.js';
export default defineAction({
name: 'Create post',
key: 'createPost',
description: 'Creates a new post.',
arguments: [
{
label: 'Title',
key: 'title',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'Content',
key: 'content',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Excerpt',
key: 'excerpt',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Password',
key: 'password',
type: 'string',
required: false,
description: 'A password to protect access to the content and excerpt.',
variables: true,
},
{
label: 'Author',
key: 'author',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listUsers',
},
],
},
},
{
label: 'Featured Media',
key: 'featuredMedia',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listMedia',
},
],
},
},
{
label: 'Comment Status',
key: 'commentStatus',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'Open', value: 'open' },
{ label: 'Closed', value: 'closed' },
],
},
{
label: 'Ping Status',
key: 'pingStatus',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'Open', value: 'open' },
{ label: 'Closed', value: 'closed' },
],
},
{
label: 'Format',
key: 'format',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'Standard', value: 'standard' },
{ label: 'Aside', value: 'aside' },
{ label: 'Chat', value: 'chat' },
{ label: 'Gallery', value: 'gallery' },
{ label: 'Link', value: 'link' },
{ label: 'Image', value: 'image' },
{ label: 'Quote', value: 'quote' },
{ label: 'Status', value: 'status' },
{ label: 'Status', value: 'status' },
{ label: 'Video', value: 'video' },
{ label: 'Audio', value: 'audio' },
],
},
{
label: 'Sticky',
key: 'sticky',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'False', value: 'false' },
{ label: 'True', value: 'true' },
],
},
{
label: 'Categories',
key: 'categoryIds',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Category',
key: 'categoryId',
type: 'dropdown',
required: false,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listCategories',
},
],
},
},
],
},
{
label: 'Tags',
key: 'tagIds',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Tag',
key: 'tagId',
type: 'dropdown',
required: false,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listTags',
},
],
},
},
],
},
{
label: 'Status',
key: 'status',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listStatuses',
},
],
},
},
{
label: 'Date',
key: 'date',
type: 'string',
required: false,
description: "Post publish date in the site's timezone",
variables: true,
},
],
async run($) {
const {
title,
content,
excerpt,
password,
author,
featuredMedia,
commentStatus,
pingStatus,
format,
sticky,
categoryIds,
tagIds,
status,
date,
} = $.step.parameters;
const allCategoryIds = categoryIds
?.map((categoryId) => categoryId.categoryId)
.filter(Boolean);
const allTagIds = tagIds?.map((tagId) => tagId.tagId).filter(Boolean);
let body = {
title,
content,
excerpt,
password,
author,
featured_media: featuredMedia,
comment_status: commentStatus,
ping_status: pingStatus,
format,
sticky,
categories: allCategoryIds,
tags: allTagIds,
status,
date,
};
body = omitBy(body, isEmpty);
const response = await $.http.post('?rest_route=/wp/v2/posts', body);
$.setActionItem({ raw: response.data });
},
});

View File

@@ -1,35 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Find post',
key: 'findPost',
description: 'Finds a post.',
arguments: [
{
label: 'Post ID',
key: 'postId',
type: 'dropdown',
required: false,
description: 'Choose a post to update.',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listPosts',
},
],
},
},
],
async run($) {
const { postId } = $.step.parameters;
const response = await $.http.get(`?rest_route=/wp/v2/posts/${postId}`);
$.setActionItem({ raw: response.data });
},
});

View File

@@ -1,5 +0,0 @@
import createPost from './create-post/index.js';
import findPost from './find-post/index.js';
import updatePost from './update-post/index.js';
export default [createPost, findPost, updatePost];

View File

@@ -1,284 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
import isEmpty from 'lodash/isEmpty.js';
import omitBy from 'lodash/omitBy.js';
export default defineAction({
name: 'Update post',
key: 'updatePost',
description: 'Updates a post.',
arguments: [
{
label: 'Post',
key: 'postId',
type: 'dropdown',
required: false,
description: 'Choose a post to update.',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listPosts',
},
],
},
},
{
label: 'Title',
key: 'title',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'Content',
key: 'content',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Excerpt',
key: 'excerpt',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Password',
key: 'password',
type: 'string',
required: false,
description: 'A password to protect access to the content and excerpt.',
variables: true,
},
{
label: 'Author',
key: 'author',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listUsers',
},
],
},
},
{
label: 'Featured Media',
key: 'featuredMedia',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listMedia',
},
],
},
},
{
label: 'Comment Status',
key: 'commentStatus',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'Open', value: 'open' },
{ label: 'Closed', value: 'closed' },
],
},
{
label: 'Ping Status',
key: 'pingStatus',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'Open', value: 'open' },
{ label: 'Closed', value: 'closed' },
],
},
{
label: 'Format',
key: 'format',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'Standard', value: 'standard' },
{ label: 'Aside', value: 'aside' },
{ label: 'Chat', value: 'chat' },
{ label: 'Gallery', value: 'gallery' },
{ label: 'Link', value: 'link' },
{ label: 'Image', value: 'image' },
{ label: 'Quote', value: 'quote' },
{ label: 'Status', value: 'status' },
{ label: 'Status', value: 'status' },
{ label: 'Video', value: 'video' },
{ label: 'Audio', value: 'audio' },
],
},
{
label: 'Sticky',
key: 'sticky',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'False', value: 'false' },
{ label: 'True', value: 'true' },
],
},
{
label: 'Categories',
key: 'categoryIds',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Category',
key: 'categoryId',
type: 'dropdown',
required: false,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listCategories',
},
],
},
},
],
},
{
label: 'Tags',
key: 'tagIds',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Tag',
key: 'tagId',
type: 'dropdown',
required: false,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listTags',
},
],
},
},
],
},
{
label: 'Status',
key: 'status',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listStatuses',
},
],
},
},
{
label: 'Date',
key: 'date',
type: 'string',
required: false,
description: "Post publish date in the site's timezone",
variables: true,
},
],
async run($) {
const {
postId,
title,
content,
excerpt,
password,
author,
featuredMedia,
commentStatus,
pingStatus,
format,
sticky,
categoryIds,
tagIds,
status,
date,
} = $.step.parameters;
const allCategoryIds = categoryIds
?.map((categoryId) => categoryId.categoryId)
.filter(Boolean);
const allTagIds = tagIds?.map((tagId) => tagId.tagId).filter(Boolean);
let body = {
title,
content,
excerpt,
password,
author,
featured_media: featuredMedia,
comment_status: commentStatus,
ping_status: pingStatus,
format,
sticky,
categories: allCategoryIds,
tags: allTagIds,
status,
date,
};
body = omitBy(body, isEmpty);
const response = await $.http.post(
`?rest_route=/wp/v2/posts/${postId}`,
body
);
$.setActionItem({ raw: response.data });
},
});

View File

@@ -1,15 +1,3 @@
import listCategories from './list-categories/index.js';
import listMedia from './list-media/index.js';
import listPosts from './list-posts/index.js';
import listStatuses from './list-statuses/index.js';
import listTags from './list-tags/index.js';
import listUsers from './list-users/index.js';
export default [
listCategories,
listMedia,
listPosts,
listStatuses,
listTags,
listUsers,
];
export default [listStatuses];

View File

@@ -1,40 +0,0 @@
export default {
name: 'List categories',
key: 'listCategories',
async run($) {
const categories = {
data: [],
};
const params = {
page: 1,
per_page: 100,
order: 'desc',
};
let totalPages = 1;
do {
const { data, headers } = await $.http.get(
'?rest_route=/wp/v2/categories',
{
params,
}
);
params.page = params.page + 1;
totalPages = Number(headers['x-wp-totalpages']);
if (data) {
for (const category of data) {
categories.data.push({
value: category.id,
name: category.name,
});
}
}
} while (params.page <= totalPages);
return categories;
},
};

View File

@@ -1,37 +0,0 @@
export default {
name: 'List media',
key: 'listMedia',
async run($) {
const media = {
data: [],
};
const params = {
page: 1,
per_page: 100,
order: 'desc',
};
let totalPages = 1;
do {
const { data, headers } = await $.http.get('?rest_route=/wp/v2/media', {
params,
});
params.page = params.page + 1;
totalPages = Number(headers['x-wp-totalpages']);
if (data) {
for (const medium of data) {
media.data.push({
value: medium.id,
name: medium.slug,
});
}
}
} while (params.page <= totalPages);
return media;
},
};

View File

@@ -1,37 +0,0 @@
export default {
name: 'List posts',
key: 'listPosts',
async run($) {
const posts = {
data: [],
};
const params = {
page: 1,
per_page: 100,
order: 'desc',
};
let totalPages = 1;
do {
const { data, headers } = await $.http.get('?rest_route=/wp/v2/posts', {
params,
});
params.page = params.page + 1;
totalPages = Number(headers['x-wp-totalpages']);
if (data) {
for (const post of data) {
posts.data.push({
value: post.id,
name: post.title.rendered,
});
}
}
} while (params.page <= totalPages);
return posts;
},
};

View File

@@ -1,37 +0,0 @@
export default {
name: 'List tags',
key: 'listTags',
async run($) {
const tags = {
data: [],
};
const params = {
page: 1,
per_page: 100,
order: 'desc',
};
let totalPages = 1;
do {
const { data, headers } = await $.http.get('?rest_route=/wp/v2/tags', {
params,
});
params.page = params.page + 1;
totalPages = Number(headers['x-wp-totalpages']);
if (data) {
for (const tag of data) {
tags.data.push({
value: tag.id,
name: tag.name,
});
}
}
} while (params.page <= totalPages);
return tags;
},
};

View File

@@ -1,37 +0,0 @@
export default {
name: 'List users',
key: 'listUsers',
async run($) {
const users = {
data: [],
};
const params = {
page: 1,
per_page: 100,
order: 'desc',
};
let totalPages = 1;
do {
const { data, headers } = await $.http.get('?rest_route=/wp/v2/users', {
params,
});
params.page = params.page + 1;
totalPages = Number(headers['x-wp-totalpages']);
if (data) {
for (const user of data) {
users.data.push({
value: user.id,
name: user.name,
});
}
}
} while (params.page <= totalPages);
return users;
},
};

View File

@@ -4,7 +4,6 @@ import setBaseUrl from './common/set-base-url.js';
import auth from './auth/index.js';
import triggers from './triggers/index.js';
import dynamicData from './dynamic-data/index.js';
import actions from './actions/index.js';
export default defineApp({
name: 'WordPress',
@@ -19,5 +18,4 @@ export default defineApp({
auth,
triggers,
dynamicData,
actions,
});

View File

@@ -1,11 +0,0 @@
export async function up(knex) {
return knex.schema.alterTable('datastore', (table) => {
table.text('value').alter();
});
}
export async function down(knex) {
return knex.schema.alterTable('datastore', (table) => {
table.string('value').alter();
});
}

View File

@@ -50,6 +50,15 @@ export default defineConfig({
{ text: 'Connection', link: '/apps/appwrite/connection' },
],
},
{
text: 'Bluesky',
collapsible: true,
collapsed: true,
items: [
{ text: 'Actions', link: '/apps/bluesky/actions' },
{ text: 'Connection', link: '/apps/bluesky/connection' },
],
},
{
text: 'Carbone',
collapsible: true,
@@ -518,7 +527,6 @@ export default defineConfig({
collapsible: true,
collapsed: true,
items: [
{ text: 'Actions', link: '/apps/wordpress/actions' },
{ text: 'Triggers', link: '/apps/wordpress/triggers' },
{ text: 'Connection', link: '/apps/wordpress/connection' },
],

View File

@@ -1,12 +1,10 @@
---
favicon: /favicons/wordpress.svg
favicon: /favicons/bluesky.svg
items:
- name: Create post
desc: Creates a new post.
- name: Find post
desc: Finds a post.
- name: Update post
desc: Updates a post.
- name: Search post by url
desc: Searches a post in a thread by url.
---
<script setup>

View File

@@ -0,0 +1,10 @@
# Bluesky
:::info
This page explains the steps you need to follow to set up the Bluesky connection in Automatisch. If any of the steps are outdated, please let us know!
:::
1. Enter your `Bluesky Handle` from the page to the `Your Bluesky Handle` field on Automatisch.
1. Enter your `Bluesky Password` from the page to the `Your Bluesky Password` field on Automatisch.
1. Click **Submit** button on Automatisch.
1. Congrats! Start using your new Bluesky connection within the flows.

View File

@@ -4,6 +4,7 @@ The following integrations are currently supported by Automatisch.
- [Airtable](/apps/airtable/actions)
- [Appwrite](/apps/appwrite/triggers)
- [Bluesky](/apps/bluesky/actions)
- [Carbone](/apps/carbone/actions)
- [Datastore](/apps/datastore/actions)
- [DeepL](/apps/deepl/actions)

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-50 -50 430 390" fill="#1185fd" aria-hidden="true">
<path d="M180 141.964C163.699 110.262 119.308 51.1817 78.0347 22.044C38.4971 -5.86834 23.414 -1.03207 13.526 3.43594C2.08093 8.60755 0 26.1785 0 36.5164C0 46.8542 5.66748 121.272 9.36416 133.694C21.5786 174.738 65.0603 188.607 105.104 184.156C107.151 183.852 109.227 183.572 111.329 183.312C109.267 183.642 107.19 183.924 105.104 184.156C46.4204 192.847 -5.69621 214.233 62.6582 290.33C137.848 368.18 165.705 273.637 180 225.702C194.295 273.637 210.76 364.771 295.995 290.33C360 225.702 313.58 192.85 254.896 184.158C252.81 183.926 250.733 183.645 248.671 183.315C250.773 183.574 252.849 183.855 254.896 184.158C294.94 188.61 338.421 174.74 350.636 133.697C354.333 121.275 360 46.8568 360 36.519C360 26.1811 357.919 8.61012 346.474 3.43851C336.586 -1.02949 321.503 -5.86576 281.965 22.0466C240.692 51.1843 196.301 110.262 180 141.964Z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 956 B

View File

@@ -170,6 +170,52 @@
tslib "^2.3.0"
zen-observable-ts "~1.1.0"
"@atproto/api@^0.12.13":
version "0.12.13"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.13.tgz#269d6c57ea894e23f20b28bd3cbfed944bd28528"
integrity sha512-pRSID6w8AUiZJoCxgctMPRTSGVFHq7wphAnxEbRLBP3OQ1g+BRZUcqFw+e+17Pd3wrc8VImjiD4HCWtCJvCx3w==
dependencies:
"@atproto/common-web" "^0.3.0"
"@atproto/lexicon" "^0.4.0"
"@atproto/syntax" "^0.3.0"
"@atproto/xrpc" "^0.5.0"
multiformats "^9.9.0"
tlds "^1.234.0"
"@atproto/common-web@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@atproto/common-web/-/common-web-0.3.0.tgz#36da8c2c31d8cf8a140c3c8f03223319bf4430bb"
integrity sha512-67VnV6JJyX+ZWyjV7xFQMypAgDmjVaR9ZCuU/QW+mqlqI7fex2uL4Fv+7/jHadgzhuJHVd6OHOvNn0wR5WZYtA==
dependencies:
graphemer "^1.4.0"
multiformats "^9.9.0"
uint8arrays "3.0.0"
zod "^3.21.4"
"@atproto/lexicon@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.0.tgz#63e8829945d80c25524882caa8ed27b1151cc576"
integrity sha512-RvCBKdSI4M8qWm5uTNz1z3R2yIvIhmOsMuleOj8YR6BwRD+QbtUBy3l+xQ7iXf4M5fdfJFxaUNa6Ty0iRwdKqQ==
dependencies:
"@atproto/common-web" "^0.3.0"
"@atproto/syntax" "^0.3.0"
iso-datestring-validator "^2.2.2"
multiformats "^9.9.0"
zod "^3.21.4"
"@atproto/syntax@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@atproto/syntax/-/syntax-0.3.0.tgz#fafa2dbea9add37253005cb663e7373e05e618b3"
integrity sha512-Weq0ZBxffGHDXHl9U7BQc2BFJi/e23AL+k+i5+D9hUq/bzT4yjGsrCejkjq0xt82xXDjmhhvQSZ0LqxyZ5woxA==
"@atproto/xrpc@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.5.0.tgz#dacbfd8f7b13f0ab5bd56f8fdd4b460e132a6032"
integrity sha512-swu+wyOLvYW4l3n+VAuJbHcPcES+tin2Lsrp8Bw5aIXIICiuFn1YMFlwK9JwVUzTH21Py1s1nHEjr4CJeElJog==
dependencies:
"@atproto/lexicon" "^0.4.0"
zod "^3.21.4"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.8.3":
version "7.16.7"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz"
@@ -8939,6 +8985,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz"
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
graphemer@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
graphql-executor@0.0.18:
version "0.0.18"
resolved "https://registry.npmjs.org/graphql-executor/-/graphql-executor-0.0.18.tgz"
@@ -9876,6 +9927,11 @@ isexe@^3.1.1:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d"
integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==
iso-datestring-validator@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz#2daa80d2900b7a954f9f731d42f96ee0c19a6895"
integrity sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==
isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz"
@@ -11592,6 +11648,11 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1"
thunky "^1.0.2"
multiformats@^9.4.2, multiformats@^9.9.0:
version "9.9.0"
resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37"
integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==
multimatch@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz"
@@ -15574,6 +15635,11 @@ tinyspy@^2.2.0:
resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.0.tgz#9dc04b072746520b432f77ea2c2d17933de5d6ce"
integrity sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==
tlds@^1.234.0:
version "1.252.0"
resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.252.0.tgz#71d9617f4ef4cc7347843bee72428e71b8b0f419"
integrity sha512-GA16+8HXvqtfEnw/DTcwB0UU354QE1n3+wh08oFjr6Znl7ZLAeUgYzCcK+/CCrOyE0vnHR8/pu3XXG3vDijXpQ==
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz"
@@ -15823,6 +15889,13 @@ uid-number@0.0.6:
resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz"
integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=
uint8arrays@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.0.0.tgz#260869efb8422418b6f04e3fac73a3908175c63b"
integrity sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==
dependencies:
multiformats "^9.4.2"
umask@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz"
@@ -16948,3 +17021,8 @@ zen-observable@0.8.15:
version "0.8.15"
resolved "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz"
integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==
zod@^3.21.4:
version "3.23.8"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d"
integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==