Skip to content

Commit fc621c6

Browse files
authored
Merge pull request #5 from ephemeraHQ/rygine/dev-tooling
Update prettier, add ESLint
2 parents e6c5c46 + f8d524a commit fc621c6

30 files changed

+1637
-356
lines changed

.eslintignore

-2
This file was deleted.

.prettierignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
CODEOWNERS
22
.yarn
3-
3+
.changeset/**/*.md

.prettierrc

-19
This file was deleted.

.prettierrc.cjs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
module.exports = {
2+
arrowParens: "always",
3+
bracketSameLine: true,
4+
bracketSpacing: true,
5+
embeddedLanguageFormatting: "auto",
6+
endOfLine: "lf",
7+
htmlWhitespaceSensitivity: "css",
8+
jsxSingleQuote: false,
9+
printWidth: 80,
10+
proseWrap: "preserve",
11+
quoteProps: "as-needed",
12+
semi: true,
13+
singleAttributePerLine: false,
14+
singleQuote: false,
15+
tabWidth: 2,
16+
trailingComma: "all",
17+
useTabs: false,
18+
plugins: [
19+
"prettier-plugin-packagejson",
20+
"@ianvs/prettier-plugin-sort-imports",
21+
],
22+
importOrder: [
23+
"<BUILTIN_MODULES>",
24+
"<THIRD_PARTY_MODULES>",
25+
"^@(/.*)$",
26+
"^@test(/.*)$",
27+
"^@bench(/.*)$",
28+
"^[.]",
29+
],
30+
importOrderTypeScriptVersion: "5.6.3",
31+
};

eslint.config.js

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import path from "node:path";
2+
import process from "node:process";
3+
import { fileURLToPath } from "node:url";
4+
import { includeIgnoreFile } from "@eslint/compat";
5+
import eslint from "@eslint/js";
6+
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
7+
import globals from "globals";
8+
import tseslint from "typescript-eslint";
9+
10+
const __filename = fileURLToPath(import.meta.url);
11+
const __dirname = path.dirname(__filename);
12+
const gitignorePath = path.resolve(__dirname, ".gitignore");
13+
14+
export default tseslint.config(
15+
includeIgnoreFile(gitignorePath),
16+
{
17+
ignores: [".yarn/**/*"],
18+
},
19+
eslint.configs.recommended,
20+
...tseslint.configs.strictTypeChecked,
21+
{
22+
languageOptions: {
23+
parserOptions: {
24+
projectService: {
25+
defaultProject: "tsconfig.json",
26+
},
27+
tsconfigRootDir: process.cwd(),
28+
},
29+
},
30+
},
31+
{
32+
rules: {
33+
"@typescript-eslint/consistent-type-exports": [
34+
"error",
35+
{
36+
fixMixedExportsWithInlineTypeSpecifier: false,
37+
},
38+
],
39+
"@typescript-eslint/consistent-type-imports": "error",
40+
"@typescript-eslint/no-deprecated": "warn",
41+
"@typescript-eslint/no-explicit-any": "warn",
42+
"@typescript-eslint/no-unused-vars": [
43+
"error",
44+
{
45+
argsIgnorePattern: "^_",
46+
destructuredArrayIgnorePattern: "^_",
47+
ignoreRestSiblings: true,
48+
varsIgnorePattern: "^_",
49+
},
50+
],
51+
"@typescript-eslint/restrict-template-expressions": [
52+
"error",
53+
{
54+
allowNumber: true,
55+
},
56+
],
57+
},
58+
},
59+
{
60+
files: ["**/*.cjs", "**/*.js"],
61+
extends: [tseslint.configs.disableTypeChecked],
62+
languageOptions: {
63+
globals: {
64+
...globals.node,
65+
},
66+
},
67+
rules: {
68+
"@typescript-eslint/no-require-imports": "off",
69+
},
70+
},
71+
{
72+
files: ["**/*.test.ts"],
73+
rules: {
74+
"@typescript-eslint/no-non-null-assertion": "off",
75+
},
76+
},
77+
eslintPluginPrettierRecommended,
78+
);

examples/express/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
"dependencies": {
1212
"@xmtp/agent-starter": "workspace:*",
1313
"axios": "^1.7.9",
14-
"express": "^4.21.2"
14+
"express": "^5.0.1"
1515
},
1616
"devDependencies": {
17-
"@types/express": "^4.17.21",
17+
"@types/express": "^5.0.0",
1818
"@types/node": "^22.10.9",
1919
"typescript": "^5.7.3"
2020
},

examples/express/src/index.ts

+20-19
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
1-
import express from "express";
1+
import { xmtpClient, type XMTP } from "@xmtp/agent-starter";
2+
import express, { type Request, type Response } from "express";
23
import fetch from "node-fetch";
3-
import { xmtpClient, XMTP } from "@xmtp/agent-starter";
44

55
async function createServer(port: number, agent: XMTP) {
66
const app = express();
77
app.use(express.json());
88

99
// Endpoint to RECEIVE encrypted messages
10-
app.post("/receive", async (req, res) => {
11-
try {
12-
const { nonce, ciphertext, fromAddress } = req.body;
13-
const decryptedMessage = await agent.decrypt(
14-
nonce,
15-
ciphertext,
16-
fromAddress,
17-
);
18-
19-
console.log(`Server on port ${port} decrypted:`, decryptedMessage);
20-
return res.json({ success: true, decryptedMessage });
21-
} catch (error) {
22-
console.error("Error in /receive:", error);
23-
return res.status(500).json({ error: (error as Error).message });
24-
}
10+
app.post("/receive", (req: Request, res: Response) => {
11+
const { nonce, ciphertext, fromAddress } = req.body as {
12+
nonce: string;
13+
ciphertext: string;
14+
fromAddress: string;
15+
};
16+
agent
17+
.decrypt(nonce, ciphertext, fromAddress)
18+
.then((decryptedMessage) => {
19+
console.log(`Server on port ${port} decrypted:`, decryptedMessage);
20+
res.json({ success: true, decryptedMessage });
21+
})
22+
.catch((error: unknown) => {
23+
console.error("Error in /receive:", error);
24+
res.status(500).json({ error: (error as Error).message });
25+
});
2526
});
2627

2728
return new Promise((resolve) => {
@@ -66,8 +67,8 @@ async function main() {
6667
method: "POST",
6768
headers: { "Content-Type": "application/json" },
6869
body: JSON.stringify({
69-
nonce: nonce as string,
70-
ciphertext: ciphertext as string,
70+
nonce: nonce,
71+
ciphertext: ciphertext,
7172
fromAddress: agentA.address as string, // the "sender"
7273
}),
7374
});

examples/gated-group/src/index.ts

+41-40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Client, Message, XMTP, xmtpClient } from "@xmtp/agent-starter";
2-
import express from "express";
1+
import { xmtpClient, type Client, type Message } from "@xmtp/agent-starter";
32
import { Alchemy, Network } from "alchemy-sdk";
3+
import express, { type Request, type Response } from "express";
44

55
const settings = {
66
apiKey: process.env.ALCHEMY_API_KEY, // Replace with your Alchemy API key
@@ -13,24 +13,26 @@ async function main() {
1313
onMessage: async (message: Message) => {
1414
if (message.typeId !== "text") return;
1515

16-
if (message?.content.text === "/create") {
16+
if (message.content.text === "/create") {
1717
console.log("Creating group");
1818
const group = await createGroup(
19-
agent?.client,
20-
message?.sender?.address as string,
21-
agent?.address as string,
19+
agent.client,
20+
message.sender.address,
21+
agent.address as string,
2222
);
2323
console.log("Group created", group?.id);
2424
await agent.send({
2525
message: `Group created!\n- ID: ${group?.id}\n- Group URL: https://converse.xyz/group/${group?.id}: \n- This url will deelink to the group inside Converse\n- Once in the other group you can share the invite with your friends.`,
2626
originalMessage: message,
27+
metadata: {},
2728
});
2829
return;
2930
} else {
3031
await agent.send({
3132
message:
3233
"👋 Welcome to the Gated Bot Group!\nTo get started, type /create to set up a new group. 🚀\nThis example will check if the user has a particular nft and add them to the group if they do.\nOnce your group is created, you'll receive a unique Group ID and URL.\nShare the URL with friends to invite them to join your group!",
3334
originalMessage: message,
35+
metadata: {},
3436
});
3537
}
3638
},
@@ -39,20 +41,23 @@ async function main() {
3941
// Endpoint to add wallet address to a group from an external source
4042
const app = express();
4143
app.use(express.json());
42-
app.post("/add-wallet", async (req, res) => {
43-
try {
44-
const { walletAddress, groupId } = req.body;
45-
const verified = true; // (await checkNft(walletAddress, "XMTPeople"));
46-
if (!verified) {
47-
console.log("User cant be added to the group");
48-
return;
49-
} else {
50-
await addToGroup(groupId, agent?.client as Client, walletAddress, true);
44+
app.post("/add-wallet", (req: Request, res: Response) => {
45+
const { walletAddress, groupId } = req.body as {
46+
walletAddress: string;
47+
groupId: string;
48+
};
49+
// const verified = true; // (await checkNft(walletAddress, "XMTPeople"));
50+
// if (!verified) {
51+
// console.log("User cant be added to the group");
52+
// return;
53+
// } else {
54+
addToGroup(groupId, agent.client as Client, walletAddress, true)
55+
.then(() => {
5156
res.status(200).send("success");
52-
}
53-
} catch (error: any) {
54-
res.status(400).send(error.message);
55-
}
57+
})
58+
.catch((error: unknown) => {
59+
res.status(400).send((error as Error).message);
60+
});
5661
});
5762
// Start the servfalcheer
5863
const PORT = process.env.PORT || 3000;
@@ -63,7 +68,7 @@ async function main() {
6368
);
6469
});
6570
console.log(
66-
`XMTP agent initialized on ${agent?.address}\nSend a message on https://xmtp.chat or https://converse.xyz/dm/${agent?.address}`,
71+
`XMTP agent initialized on ${agent.address}\nSend a message on https://xmtp.chat or https://converse.xyz/dm/${agent.address}`,
6772
);
6873
}
6974

@@ -80,15 +85,15 @@ export async function createGroup(
8085
try {
8186
let senderInboxId = "";
8287
await client.conversations.sync();
83-
const conversations = await client.conversations.list();
88+
const conversations = client.conversations.list();
8489
console.log("Conversations", conversations.length);
85-
const group = await client?.conversations.newGroup([
90+
const group = await client.conversations.newGroup([
8691
senderAddress,
8792
clientAddress,
8893
]);
89-
console.log("Group created", group?.id);
94+
console.log("Group created", group.id);
9095
const members = await group.members();
91-
const senderMember = members.find((member: any) =>
96+
const senderMember = members.find((member) =>
9297
member.accountAddresses.includes(senderAddress.toLowerCase()),
9398
);
9499
if (senderMember) {
@@ -98,10 +103,7 @@ export async function createGroup(
98103
console.log("Sender not found in members list");
99104
}
100105
await group.addSuperAdmin(senderInboxId);
101-
console.log(
102-
"Sender is superAdmin",
103-
await group.isSuperAdmin(senderInboxId),
104-
);
106+
console.log("Sender is superAdmin", group.isSuperAdmin(senderInboxId));
105107
await group.send(`Welcome to the new group!`);
106108
await group.send(`You are now the admin of this group as well as the bot`);
107109
return group;
@@ -117,15 +119,14 @@ export async function removeFromGroup(
117119
senderAddress: string,
118120
): Promise<void> {
119121
try {
120-
let lowerAddress = senderAddress.toLowerCase();
122+
const lowerAddress = senderAddress.toLowerCase();
121123
const isOnXMTP = await client.canMessage([lowerAddress]);
122124
console.warn("Checking if on XMTP: ", isOnXMTP);
123-
if (!isOnXMTP) {
125+
if (!isOnXMTP.get(lowerAddress)) {
124126
console.error("You don't seem to have a v3 identity ");
125127
return;
126128
}
127-
const conversation =
128-
await client.conversations.getConversationById(groupId);
129+
const conversation = client.conversations.getConversationById(groupId);
129130
console.warn("removing from group", conversation?.id);
130131
await conversation?.sync();
131132
await conversation?.removeMembers([lowerAddress]);
@@ -137,7 +138,7 @@ export async function removeFromGroup(
137138
let wasRemoved = true;
138139
if (members) {
139140
for (const member of members) {
140-
let lowerMemberAddress = member.accountAddresses[0].toLowerCase();
141+
const lowerMemberAddress = member.accountAddresses[0].toLowerCase();
141142
if (lowerMemberAddress === lowerAddress) {
142143
wasRemoved = false;
143144
break;
@@ -162,13 +163,13 @@ export async function addToGroup(
162163
asAdmin: boolean = false,
163164
): Promise<void> {
164165
try {
165-
let lowerAddress = address.toLowerCase();
166+
const lowerAddress = address.toLowerCase();
166167
const isOnXMTP = await client.canMessage([lowerAddress]);
167-
if (!isOnXMTP) {
168+
if (!isOnXMTP.get(lowerAddress)) {
168169
console.error("You don't seem to have a v3 identity ");
169170
return;
170171
}
171-
const group = await client.conversations.getConversationById(groupId);
172+
const group = client.conversations.getConversationById(groupId);
172173
console.warn("Adding to group", group?.id);
173174
await group?.sync();
174175
await group?.addMembers([lowerAddress]);
@@ -182,7 +183,7 @@ export async function addToGroup(
182183

183184
if (members) {
184185
for (const member of members) {
185-
let lowerMemberAddress = member.accountAddresses[0].toLowerCase();
186+
const lowerMemberAddress = member.accountAddresses[0].toLowerCase();
186187
if (lowerMemberAddress === lowerAddress) {
187188
console.warn("Member exists", lowerMemberAddress);
188189
return;
@@ -204,11 +205,11 @@ export async function checkNft(
204205
const nfts = await alchemy.nft.getNftsForOwner(walletAddress);
205206

206207
const ownsNft = nfts.ownedNfts.some(
207-
(nft: any) =>
208-
nft.contract.name.toLowerCase() === collectionSlug.toLowerCase(),
208+
(nft) =>
209+
nft.contract.name?.toLowerCase() === collectionSlug.toLowerCase(),
209210
);
210211
console.log("is the nft owned: ", ownsNft);
211-
return ownsNft as boolean;
212+
return ownsNft;
212213
} catch (error) {
213214
console.error("Error fetching NFTs from Alchemy:", error);
214215
}

0 commit comments

Comments
 (0)