Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
6d9d0fe
feat: retryNotify job
zasulskii Aug 13, 2024
f87cf29
feat: add logs
zasulskii Aug 13, 2024
aae9a93
feat: config validation, postinstall script
zasulskii Aug 13, 2024
0fb0171
chore: fix index to config rename
zasulskii Aug 13, 2024
89f3a90
fix: logger error message
zasulskii Aug 13, 2024
2a32735
feat: refactor notification service, remove DI
zasulskii Aug 14, 2024
c267081
chore: remove unused file
zasulskii Aug 14, 2024
ac109d9
feat: shutdown, event-based txs
zasulskii Aug 15, 2024
2ff63de
feat: fast transactions fetch after service is shutdown
zasulskii Aug 15, 2024
63c5a07
feat: remove transactions jobs, refactor to transaction channel
zasulskii Aug 16, 2024
2a68205
feat: transaction channel destroy
zasulskii Aug 19, 2024
60f456d
refactor: message to messageMany while processing txs to notify
zasulskii Aug 19, 2024
59defd6
fix: handle transaction ref to unsub from socket
zasulskii Aug 20, 2024
23feef3
docs(README.md): register/unregister device transaction payload
bludnic Dec 4, 2024
cccf684
chore(package.json): upgrade husky
bludnic Dec 4, 2024
1528248
chore: gitignore .env
bludnic Dec 4, 2024
0649db0
chore(package.json): upgrade dependencies
bludnic Dec 4, 2024
a249cf7
fix(build): disable DTS (build error)
bludnic Dec 4, 2024
a0866f6
Merge remote-tracking branch 'origin/dev' into dev
bludnic Dec 4, 2024
9077201
chore: gitignore package-lock.json
bludnic Dec 4, 2024
0432d7d
chore(Node): enable source map support for stack traces
bludnic Dec 6, 2024
71fd99b
chore: configure dotenv
bludnic Dec 6, 2024
d02b247
refactor: remove DATABASE_URL from config (use ENV instead)
bludnic Dec 6, 2024
d29d8b5
fix: unhandled error when processing a Signal Transaction
bludnic Dec 6, 2024
7ac2cc3
chore: configure Vitest
bludnic Dec 7, 2024
d3a103e
chore(prisma): `deviceId` should be provided by the client
bludnic Dec 7, 2024
3ad6f12
feat(zod): add runtime type for `SignalMessagePayload`
bludnic Dec 7, 2024
aa3c4d7
refactor: simplify fastify server
bludnic Dec 7, 2024
9bc5571
refactor: simplify logger
bludnic Dec 7, 2024
3f953dd
refactor(prisma): simplify `checkConnection()`
bludnic Dec 7, 2024
9173b16
refactor(config): prettify
bludnic Dec 7, 2024
d14ddda
refactor(prettier): print semicolons at the ends of statements
bludnic Dec 7, 2024
bb23787
refactor: organize gitignore
bludnic Dec 7, 2024
e04a87f
chore(TypeScript): enable JSON modules
bludnic Dec 7, 2024
dfeebc4
refactor: simplify the config
bludnic Dec 7, 2024
c557205
chore(npm): add `typecheck` command
bludnic Dec 7, 2024
7e88715
refactor(config): sort imports
bludnic Dec 7, 2024
46af467
docs(README.md): provider should be uppercased
bludnic Dec 7, 2024
fdc0777
chore: add .env.example
bludnic Dec 7, 2024
5d16a65
refactor(firebase): rename config example
bludnic Dec 7, 2024
4695e4d
chore: upgrade fastify
bludnic Dec 7, 2024
58599eb
chore(fastify): add zod validation
bludnic Dec 7, 2024
e5ffe76
refactor(TransactionsChannel): simplify
bludnic Dec 7, 2024
3af6933
refactor: improve TransactionChannel
bludnic Dec 8, 2024
2844196
feat(TransactionChannel): type on/emit methods
bludnic Dec 8, 2024
3a9edbf
feat: refactor service
bludnic Dec 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/adamant_ns?schema=public
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
# NPM
node_modules
package-lock.json
dist/

# Editors
.vscode
.idea

# Config
.env
config.json5
firebase-credentials.json

# Logs
logs/*
!/logs/.gitkeep



56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# ADAMANT Notification Service (ANS)

## Configuration

1. Fill `config5.json` file with configuration settings (`config.sample.json5` as an example)
2. Create `firebase-credentials.json` file (`firebase-credentials.example.json` as an example)
3. `pnpm install`
4. `export DATABASE_URL=$database-url`
5. `npx prisma migrate deploy`
6. `pnpm run build`
7. `pnpm run start`

## How it works

To deliver notifcations privately and secure, 4 parties are involved:
Expand Down Expand Up @@ -45,3 +55,49 @@ sequenceDiagram
APNS_FCM-->>UserDevice: Notify user's device
UserDevice->>UserDevice: Decrypt transaction using private key
```

## ANS

To register a token you must sign and send a signal transaction ([AIP-6: Signal Messages](https://aips.adamant.im/AIPS/aip-6)) to an ADAMANT node. You must set the `recipientId` of the current ANS service so the service can decode the transaction.

Payload format:

```ts
type SignalMessagePayload = {
token: string;
provider: "APNS" | "FCM";
action: "add" | "remove";
}
```

- `token`: User's device token
- `provider`: Push service provider
- `APNS`: Apple Push Notification service (for iOS app)
- `FCM`: Firebase Cloud Messaging (for Web/Android apps)
- `action`: Signal action
- `add`: Register new devise
- `remove`: Unregister device

### Register new device

The service will save the token to the database and start monitoring new messages on the blockchain. As soon as a new message arrives, a push notification will be sent.

```json
{
"token": "DeviceToken",
"provider": "FCM",
"action": "add"
}
```

### Unregister device

The service will remove the device token from the database and stop sending push notifications.

```json
{
"token": "DeviceToken",
"provider": "FCM",
"action": "remove"
}
```
70 changes: 0 additions & 70 deletions config.json5

This file was deleted.

61 changes: 61 additions & 0 deletions config.sample.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
app: {
/*
Server port with health check endpoint
*/
port: 3000
},

/*
The maximum number of hours after a transaction occurs during which a notification can be sent to the user.
If a transaction is older than the specified number of hours, the system will skip sending a notification for that transaction
*/
notificationExpiryHours: 24,

/*
List of nodes to fetch transactions.
If one becomes unavailable, the bot will choose a live one.
*/
admNodes: [
'https://bid.adamant.im',
'http://localhost:36666',
'https://endless.adamant.im',
'https://clown.adamant.im',
'https://unusual.adamant.im',
'https://debate.adamant.im',
'http://23.226.231.225:36666',
'http://78.47.205.206:36666',
'https://lake.adamant.im',
'https://sunshine.adamant.im'
],

/*
Pass phrase for the incoming transaction's bot
*/
passPhrase: '',

/*
Transaction types to notify:
0 - token transfer transaction
2 - delegate registration transaction
3 - vote for delegate transaction
8 - chat/message transaction
9 - store data in KVS transaction
*/
notifyTxTypes: [0, 8],

/*
If service notifies "8" type of transactions (chat/message transaction)
include subtypes to notify of these transactions:
1 - Basic encrypted messages
2 - Rich content messages
3 - Signal messages
*/
chatTxTypeIncludeSubtype: [1, 2],

/*
If the service has been shut down, it will process blocks from the moment of switching off.
The setting specifies how many last blocks to notify users about new transactions
*/
latestHeightToNotify: 500
}
17 changes: 9 additions & 8 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-check

import eslint from '@eslint/js'
import tseslint from 'typescript-eslint'
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';

export default tseslint.config({
files: ['src/**/*.ts'],
Expand All @@ -17,10 +17,11 @@ export default tseslint.config({
},
extends: [eslint.configs.recommended, ...tseslint.configs.recommended],
rules: {
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error'
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-explicit-any': 'off'
}
})
});
Empty file removed firebase-credentials-example.json
Empty file.
13 changes: 13 additions & 0 deletions firebase-credentials.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "firebase-project",
"private_key_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"private_key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"client_email": "[email protected]",
"client_id": "892364582347597234697234",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-project.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}
Loading