소스 검색

AI docs, needs work

binwiederhier 1 개월 전
부모
커밋
2e39a1329c
5개의 변경된 파일175개의 추가작업 그리고 35개의 파일을 삭제
  1. 2 2
      docs/faq.md
  2. 145 16
      docs/publish.md
  3. 10 0
      docs/releases.md
  4. 15 14
      docs/subscribe/api.md
  5. 3 3
      web/src/app/Notifier.js

+ 2 - 2
docs/faq.md

@@ -96,8 +96,8 @@ appreciated.
 ## Can I email you? Can I DM you on Discord/Matrix?
 For community support, please use the public channels listed on the [contact page](contact.md). I generally 
 **do not respond to direct messages** about ntfy, unless you are paying for a [ntfy Pro](https://ntfy.sh/#pricing) 
-plan (see [paid support](contact.md#paid-support-ntfy-pro-subscribers)), or you are inquiring about business 
-opportunities (see [general inquiries](contact.md#general-inquiries)).
+plan (see [paid support](contact.md#paid-support)), or you are inquiring about business 
+opportunities (see [other inquiries](contact.md#other-inquiries)).
 
 I am sorry, but answering individual questions about ntfy on a 1-on-1 basis is not scalable. Answering your questions 
 in public forums benefits others, since I can link to the discussion at a later point in time, or other users

+ 145 - 16
docs/publish.md

@@ -1418,22 +1418,23 @@ The JSON message format closely mirrors the format of the message you can consum
 (see [JSON message format](subscribe/api.md#json-message-format) for details), but is not exactly identical. Here's an overview of
 all the supported fields:
 
-| Field      | Required | Type                             | Example                                   | Description                                                           |
-|------------|----------|----------------------------------|-------------------------------------------|-----------------------------------------------------------------------|
-| `topic`    | ✔️       | *string*                         | `topic1`                                  | Target topic name                                                     |
-| `message`  | -        | *string*                         | `Some message`                            | Message body; set to `triggered` if empty or not passed               |
-| `title`    | -        | *string*                         | `Some title`                              | Message [title](#message-title)                                       |
-| `tags`     | -        | *string array*                   | `["tag1","tag2"]`                         | List of [tags](#tags-emojis) that may or not map to emojis            |
-| `priority` | -        | *int (one of: 1, 2, 3, 4, or 5)* | `4`                                       | Message [priority](#message-priority) with 1=min, 3=default and 5=max |
-| `actions`  | -        | *JSON array*                     | *(see [action buttons](#action-buttons))* | Custom [user action buttons](#action-buttons) for notifications       |
-| `click`    | -        | *URL*                            | `https://example.com`                     | Website opened when notification is [clicked](#click-action)          |
-| `attach`   | -        | *URL*                            | `https://example.com/file.jpg`            | URL of an attachment, see [attach via URL](#attach-file-from-a-url)   |
-| `markdown` | -        | *bool*                           | `true`                                    | Set to true if the `message` is Markdown-formatted                    |
-| `icon`     | -        | *string*                         | `https://example.com/icon.png`            | URL to use as notification [icon](#icons)                             |
-| `filename` | -        | *string*                         | `file.jpg`                                | File name of the attachment                                           |
-| `delay`    | -        | *string*                         | `30min`, `9am`                            | Timestamp or duration for delayed delivery                            |
-| `email`    | -        | *e-mail address*                 | `phil@example.com`                        | E-mail address for e-mail notifications                               |
-| `call`     | -        | *phone number or 'yes'*          | `+1222334444` or `yes`                    | Phone number to use for [voice call](#phone-calls)                    |
+| Field         | Required | Type                             | Example                                   | Description                                                                               |
+|---------------|----------|----------------------------------|-------------------------------------------|-------------------------------------------------------------------------------------------|
+| `topic`       | ✔️       | *string*                         | `topic1`                                  | Target topic name                                                                         |
+| `message`     | -        | *string*                         | `Some message`                            | Message body; set to `triggered` if empty or not passed                                   |
+| `title`       | -        | *string*                         | `Some title`                              | Message [title](#message-title)                                                           |
+| `tags`        | -        | *string array*                   | `["tag1","tag2"]`                         | List of [tags](#tags-emojis) that may or not map to emojis                                |
+| `priority`    | -        | *int (one of: 1, 2, 3, 4, or 5)* | `4`                                       | Message [priority](#message-priority) with 1=min, 3=default and 5=max                     |
+| `actions`     | -        | *JSON array*                     | *(see [action buttons](#action-buttons))* | Custom [user action buttons](#action-buttons) for notifications                           |
+| `click`       | -        | *URL*                            | `https://example.com`                     | Website opened when notification is [clicked](#click-action)                              |
+| `attach`      | -        | *URL*                            | `https://example.com/file.jpg`            | URL of an attachment, see [attach via URL](#attach-file-from-a-url)                       |
+| `markdown`    | -        | *bool*                           | `true`                                    | Set to true if the `message` is Markdown-formatted                                        |
+| `icon`        | -        | *string*                         | `https://example.com/icon.png`            | URL to use as notification [icon](#icons)                                                 |
+| `filename`    | -        | *string*                         | `file.jpg`                                | File name of the attachment                                                               |
+| `delay`       | -        | *string*                         | `30min`, `9am`                            | Timestamp or duration for delayed delivery                                                |
+| `email`       | -        | *e-mail address*                 | `phil@example.com`                        | E-mail address for e-mail notifications                                                   |
+| `call`        | -        | *phone number or 'yes'*          | `+1222334444` or `yes`                    | Phone number to use for [voice call](#phone-calls)                                        |
+| `sequence_id` | -        | *string*                         | `my-sequence-123`                         | Sequence ID for [updating/deleting notifications](#updating-deleting-notifications)   |
 
 ## Action buttons
 _Supported on:_ :material-android: :material-apple: :material-firefox:
@@ -2694,6 +2695,134 @@ Here's an example that will open Reddit when the notification is clicked:
     ]));
     ```
 
+## Updating + deleting notifications
+_Supported on:_ :material-android: :material-firefox:
+
+You can update, clear (mark as read), or delete notifications that have already been delivered. This is useful for scenarios 
+like download progress updates, replacing outdated information, or dismissing notifications that are no longer relevant.
+
+The key concept is the **sequence ID** (`sequence_id` or `sid`): notifications with the same sequence ID are treated as 
+belonging to the same sequence, and clients will update/replace the notification accordingly.
+
+### Updating notifications
+To update an existing notification, publish a new message with the same sequence ID. Clients will replace the previous 
+notification with the new one.
+
+You can either:
+
+1. **Use the message ID**: First publish without a sequence ID, then use the returned message `id` as the sequence ID for updates
+2. **Use a custom sequence ID**: Publish directly to `/<topic>/<sequence_id>` with your own identifier
+
+=== "Using the message ID"
+    ```bash
+    # First, publish a message and capture the message ID
+    $ curl -d "Downloading file..." ntfy.sh/mytopic
+    {"id":"xE73Iyuabi","time":1673542291,...}
+    
+    # Then use the message ID to update it
+    $ curl -d "Download complete!" ntfy.sh/mytopic/xE73Iyuabi
+    ```
+
+=== "Using a custom sequence ID"
+    ```bash
+    # Publish with a custom sequence ID
+    $ curl -d "Downloading file..." ntfy.sh/mytopic/my-download-123
+    
+    # Update using the same sequence ID  
+    $ curl -d "Download complete!" ntfy.sh/mytopic/my-download-123
+    ```
+
+=== "Using the X-Sequence-ID header"
+    ```bash
+    # Publish with a sequence ID via header
+    $ curl -H "X-Sequence-ID: my-download-123" -d "Downloading..." ntfy.sh/mytopic
+    
+    # Update using the same sequence ID
+    $ curl -H "X-Sequence-ID: my-download-123" -d "Done!" ntfy.sh/mytopic
+    ```
+
+You can also set the sequence ID via the `sid` query parameter or when [publishing as JSON](#publish-as-json) using the 
+`sequence_id` field.
+
+### Clearing notifications
+To clear a notification (mark it as read and dismiss it from the notification drawer), send a PUT request to 
+`/<topic>/<sequence_id>/clear` (or `/<topic>/<sequence_id>/read` as an alias):
+
+=== "Command line (curl)"
+    ```bash
+    curl -X PUT ntfy.sh/mytopic/my-download-123/clear
+    ```
+
+=== "HTTP"
+    ```http
+    PUT /mytopic/my-download-123/clear HTTP/1.1
+    Host: ntfy.sh
+    ```
+
+This publishes a `message_clear` event, which tells clients to:
+
+- Mark the notification as read in the app
+- Dismiss the browser/Android notification
+
+### Deleting notifications
+To delete a notification entirely, send a DELETE request to `/<topic>/<sequence_id>`:
+
+=== "Command line (curl)"
+    ```bash
+    curl -X DELETE ntfy.sh/mytopic/my-download-123
+    ```
+
+=== "HTTP"
+    ```http
+    DELETE /mytopic/my-download-123 HTTP/1.1
+    Host: ntfy.sh
+    ```
+
+This publishes a `message_delete` event, which tells clients to:
+
+- Delete the notification from the database
+- Dismiss the browser/Android notification
+
+!!! info
+    Deleted sequences can be revived by publishing a new message with the same sequence ID. The notification will 
+    reappear as a new message.
+
+### Full example
+Here's a complete example showing the lifecycle of a notification with updates, clearing, and deletion:
+
+```bash
+# 1. Create a notification with a custom sequence ID
+$ curl -d "Starting backup..." ntfy.sh/mytopic/backup-2024
+
+# 2. Update the notification with progress
+$ curl -d "Backup 50% complete..." ntfy.sh/mytopic/backup-2024
+
+# 3. Update again when complete
+$ curl -d "Backup finished successfully!" ntfy.sh/mytopic/backup-2024
+
+# 4. Clear the notification (dismiss from notification drawer)
+$ curl -X PUT ntfy.sh/mytopic/backup-2024/clear
+
+# 5. Later, delete the notification entirely
+$ curl -X DELETE ntfy.sh/mytopic/backup-2024
+```
+
+When polling the topic, you'll see the complete sequence of events:
+
+```bash
+$ curl -s "ntfy.sh/mytopic/json?poll=1&since=all" | jq .
+```
+
+```json
+{"id":"abc123","time":1673542291,"event":"message","topic":"mytopic","sequence_id":"backup-2024","message":"Starting backup..."}
+{"id":"def456","time":1673542295,"event":"message","topic":"mytopic","sequence_id":"backup-2024","message":"Backup 50% complete..."}
+{"id":"ghi789","time":1673542300,"event":"message","topic":"mytopic","sequence_id":"backup-2024","message":"Backup finished successfully!"}
+{"id":"jkl012","time":1673542305,"event":"message_clear","topic":"mytopic","sequence_id":"backup-2024"}
+{"id":"mno345","time":1673542400,"event":"message_delete","topic":"mytopic","sequence_id":"backup-2024"}
+```
+
+Clients process these events in order, keeping only the latest state for each sequence ID.
+
 ## Attachments
 _Supported on:_ :material-android: :material-firefox:
 

+ 10 - 0
docs/releases.md

@@ -1599,12 +1599,22 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
 
 ## Not released yet
 
+### ntfy server v2.16.x (UNRELEASED)
+
+**Features:**
+
+* Support for [updating and deleting notifications](publish.md#updating-deleting-notifications): You can now update, 
+  clear (mark as read), or delete notifications using a sequence ID. This enables use cases like progress updates, 
+  replacing outdated notifications, or dismissing notifications from all clients.
+
 ### ntfy Android app v1.22.x (UNRELEASED)
 
 **Features:**
 
 * Support for self-signed certs and client certs for mTLS (#215, #530, ntfy-android#149)
 * Connection error dialog to help diagnose connection issues
+* Support for [updating and deleting notifications](publish.md#updating-deleting-notifications): Notifications with
+  the same sequence ID are updated in place, and `message_delete`/`message_clear` events dismiss notifications
 
 **Bug fixes + maintenance:**
 

+ 15 - 14
docs/subscribe/api.md

@@ -324,20 +324,21 @@ format of the message. It's very straight forward:
 
 **Message**:
 
-| Field        | Required | Type                                              | Example                                               | Description                                                                                                                          |
-|--------------|----------|---------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
-| `id`         | ✔️       | *string*                                          | `hwQ2YpKdmg`                                          | Randomly chosen message identifier                                                                                                   |
-| `time`       | ✔️       | *number*                                          | `1635528741`                                          | Message date time, as Unix time stamp                                                                                                |  
-| `expires`    | (✔)️     | *number*                                          | `1673542291`                                          | Unix time stamp indicating when the message will be deleted, not set if `Cache: no` is sent                                          |  
-| `event`      | ✔️       | `open`, `keepalive`, `message`, or `poll_request` | `message`                                             | Message type, typically you'd be only interested in `message`                                                                        |
-| `topic`      | ✔️       | *string*                                          | `topic1,topic2`                                       | Comma-separated list of topics the message is associated with; only one for all `message` events, but may be a list in `open` events |
-| `message`    | -        | *string*                                          | `Some message`                                        | Message body; always present in `message` events                                                                                     |
-| `title`      | -        | *string*                                          | `Some title`                                          | Message [title](../publish.md#message-title); if not set defaults to `ntfy.sh/<topic>`                                               |
-| `tags`       | -        | *string array*                                    | `["tag1","tag2"]`                                     | List of [tags](../publish.md#tags-emojis) that may or not map to emojis                                                              |
-| `priority`   | -        | *1, 2, 3, 4, or 5*                                | `4`                                                   | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max                                                   |
-| `click`      | -        | *URL*                                             | `https://example.com`                                 | Website opened when notification is [clicked](../publish.md#click-action)                                                            |
-| `actions`    | -        | *JSON array*                                      | *see [actions buttons](../publish.md#action-buttons)* | [Action buttons](../publish.md#action-buttons) that can be displayed in the notification                                             |
-| `attachment` | -        | *JSON object*                                     | *see below*                                           | Details about an attachment (name, URL, size, ...)                                                                                   |
+| Field         | Required | Type                                                                            | Example                                               | Description                                                                                                                          |
+|---------------|----------|---------------------------------------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
+| `id`          | ✔️       | *string*                                                                        | `hwQ2YpKdmg`                                          | Randomly chosen message identifier                                                                                                   |
+| `time`        | ✔️       | *number*                                                                        | `1635528741`                                          | Message date time, as Unix time stamp                                                                                                |  
+| `expires`     | (✔)️     | *number*                                                                        | `1673542291`                                          | Unix time stamp indicating when the message will be deleted, not set if `Cache: no` is sent                                          |  
+| `event`       | ✔️       | `open`, `keepalive`, `message`, `message_delete`, `message_clear`, `poll_request` | `message`                                             | Message type, typically you'd be only interested in `message`                                                                        |
+| `topic`       | ✔️       | *string*                                                                        | `topic1,topic2`                                       | Comma-separated list of topics the message is associated with; only one for all `message` events, but may be a list in `open` events |
+| `sequence_id` | -        | *string*                                                                        | `my-sequence-123`                                     | Sequence ID for [updating/deleting notifications](../publish.md#updating-deleting-notifications)                                 |
+| `message`     | -        | *string*                                                                        | `Some message`                                        | Message body; always present in `message` events                                                                                     |
+| `title`       | -        | *string*                                                                        | `Some title`                                          | Message [title](../publish.md#message-title); if not set defaults to `ntfy.sh/<topic>`                                               |
+| `tags`        | -        | *string array*                                                                  | `["tag1","tag2"]`                                     | List of [tags](../publish.md#tags-emojis) that may or not map to emojis                                                              |
+| `priority`    | -        | *1, 2, 3, 4, or 5*                                                              | `4`                                                   | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max                                                   |
+| `click`       | -        | *URL*                                                                           | `https://example.com`                                 | Website opened when notification is [clicked](../publish.md#click-action)                                                            |
+| `actions`     | -        | *JSON array*                                                                    | *see [actions buttons](../publish.md#action-buttons)* | [Action buttons](../publish.md#action-buttons) that can be displayed in the notification                                             |
+| `attachment`  | -        | *JSON object*                                                                   | *see below*                                           | Details about an attachment (name, URL, size, ...)                                                                                   |
 
 **Attachment** (part of the message, see [attachments](../publish.md#attachments) for details):
 

+ 3 - 3
web/src/app/Notifier.js

@@ -26,7 +26,7 @@ class Notifier {
         subscriptionId: subscription.id,
         message: notification,
         defaultTitle,
-        topicRoute: new URL(routes.forSubscription(subscription), window.location.origin).toString(),
+        topicRoute: new URL(routes.forSubscription(subscription), window.location.origin).toString()
       })
     );
   }
@@ -40,7 +40,7 @@ class Notifier {
       console.log(`[Notifier] Cancelling notification with ${tag}`);
       const registration = await this.serviceWorkerRegistration();
       const notifications = await registration.getNotifications({ tag });
-      notifications.forEach((notification) => notification.close());
+      notifications.forEach(n => n.close());
     } catch (e) {
       console.log(`[Notifier] Error cancelling notification`, e);
     }
@@ -72,7 +72,7 @@ class Notifier {
     if (hasWebPushTopics) {
       return pushManager.subscribe({
         userVisibleOnly: true,
-        applicationServerKey: urlB64ToUint8Array(config.web_push_public_key),
+        applicationServerKey: urlB64ToUint8Array(config.web_push_public_key)
       });
     }