dnotifier 1.1.14
dnotifier: ^1.1.14 copied to clipboard
Real-time notification and messaging SDK for Dart and Flutter. Use in Flutter (Android, iOS, Web) or pure Dart. WebSocket & HTTP, auth, binary frames, and optional AI integration. No platform-specific [...]
DNotifier Dart SDK #
DNotifier is a real-time notification and messaging SDK for Dart and Flutter (Android, iOS, Web). It supports WebSocket and HTTP transports, binary streaming, framed packets, an AI pipeline, knowledge-base (RAG) APIs, optional session logging, and multi-step workflows with agents and observability.
Features #
- WebSocket and HTTP transport
- Secure authentication handshake
- Real-time messaging (text and binary)
- Large payloads with automatic chunking and reassembly
- AI:
sendAI,fetchAIHistory, semanticsearch - Knowledge base: add, update, get, list, delete, and search documents
- Chat history fetch and delete
- Optional SDK session logging (
logs: true) - Workflows: named agents, sequential pipelines, dashboard observability
- Plan limits from auth (
getPlanLimits) - Pure Dart — no platform-specific code in the SDK
Installation #
Add to pubspec.yaml:
dependencies:
dnotifier: ^1.1.7
Then:
dart pub get
# or in Flutter:
flutter pub get
Quick start #
import 'package:dnotifier/dnotifier.dart';
Future<void> main() async {
final notifier = DNotifier(
appId: 'your-app-id',
secret: 'your-app-secret',
transport: 'ws', // or 'http'
userId: 'user-123',
onConnected: () => print('Connected'),
onMessage: (DNotifierMessage msg) {
print('From: ${msg.metadata.sender}');
print('Body: ${msg.payload.toJSON()}');
},
onDisconnected: ({code, reason}) => print('Disconnected: $reason'),
);
await notifier.connect();
notifier.send(
senderId: 'user-123',
receiverId: 'user-456',
data: {'type': 'text', 'text': 'Hello from DNotifier'},
);
}
Connection and configuration #
| Parameter | Type | Description |
|---|---|---|
appId |
String |
Your DNotifier application id |
secret |
String |
Application secret |
transport |
'ws' | 'http' |
'ws' for realtime messaging; 'http' for RPC-style AI/RAG |
userId |
String |
End-user or agent id for auth and routing |
logs |
bool |
When true, tracks AI sessions in the DNotifier logs dashboard |
url |
String? |
Optional custom WebSocket URL |
onConnected |
void Function()? |
Called when the client is ready |
onMessage |
void Function(DNotifierMessage)? |
Incoming messages |
onDisconnected |
void Function({int? code, String? reason})? |
Connection closed |
await notifier.connect();
final limits = notifier.getPlanLimits();
print('${limits?.aiEnabled}, ${limits?.maxAIRequestsPerMonth}');
After connect():
| Property | Description |
|---|---|
isConnected |
Whether the client is connected |
aiEnabled |
Whether AI is enabled for the current plan |
authToken |
Auth token from the last successful connect |
messageSizeLimit |
Max message size in bytes (from plan) |
Real-time messaging #
Text and structured messages #
Use any type in data that fits your app (text, image, audio, doc, etc.):
notifier.send(
senderId: userId,
receiverId: receiverId,
data: {
'type': 'text',
'text': 'hello from dnotifier sdk!',
},
);
Send to multiple receivers:
notifier.send(
senderId: userId,
receiverIds: ['user-456', 'user-789'],
data: {'type': 'text', 'text': 'Hello everyone'},
);
Images, audio, and binary #
Prefer send() with a typed payload. Large payloads are chunked automatically.
import 'dart:io';
final imageBytes = await File('path/to/photo.png').readAsBytes();
notifier.send(
senderId: userId,
receiverId: receiverId,
data: {
'type': 'image',
'content': imageBytes,
},
);
Handle incoming messages in onMessage:
onMessage: (msg) {
final body = msg.payload.toJSON();
if (body is Map && body['type'] == 'image') {
// handle image
} else if (body is Map && body['type'] == 'text') {
print(body['text']);
}
},
Raw binary (sendBinary) #
notifier.sendBinary(
senderId: userId,
receiverIds: [receiverId],
buffer: [0x00, 0x01, 0x02],
);
AI #
Requires aiEnabled on your plan. Use transport: 'http' for request/response AI calls.
Simple prompt #
final response = await notifier.sendAI(
senderId: userId,
message: {'text': 'Summarize our refund policy in two sentences.'},
);
Chat-style messages #
final response = await notifier.sendAI(
senderId: userId,
message: {
'useKnowledgeBase': true,
'messages': [
{'role': 'system', 'content': 'You are a helpful support agent.'},
{'role': 'user', 'content': 'How do I reset my password?'},
],
},
saveHistory: true,
);
Continue an existing session #
final first = await notifier.sendAI(
senderId: userId,
message: {'text': 'Start a new support session.'},
);
final sessionId = (first as Map)['metadata']?['packet']?['id']?.toString();
if (sessionId != null) {
await notifier.sendAI(
senderId: userId,
sessionId: sessionId,
message: {'text': 'Follow-up in the same session.'},
);
}
AI history #
final history = await notifier.fetchAIHistory(senderId: userId);
await notifier.deleteAIHistoryMessage(
senderId: userId,
messageId: 'message-id-to-delete',
);
Knowledge base (RAG) #
// Add
await notifier.addDocument(
senderId: userId,
recordId: 'doc-001',
content: 'Refund requests are processed within 5 business days.',
type: 'text',
metadata: {'source': 'help-center'},
);
// Update
await notifier.updateDocument(
senderId: userId,
recordId: 'doc-001',
content: 'Updated refund policy text...',
type: 'text',
);
// Get one document
final doc = await notifier.getDocument(
senderId: userId,
recordId: 'doc-001',
);
// List
final list = await notifier.listDocuments(
senderId: userId,
limit: 20,
offset: 0,
type: 'text',
);
// Semantic search
final hits = await notifier.search(
senderId: userId,
query: 'how long do refunds take',
limit: 5,
minSimilarity: 0.7,
filterbySource: 'help-center',
);
// Delete
await notifier.deleteDocument(
senderId: userId,
recordId: 'doc-001',
);
Chat history #
await notifier.fetchChatHistory(
senderId: userId,
receiverIds: [otherUserId],
);
// Server responds via onMessage with the history payload.
await notifier.deleteChatHistoryMessage(
senderId: userId,
messageId: 'message-id-to-delete',
);
Session logging #
Enable automatic AI session tracking in the DNotifier dashboard:
final notifier = DNotifier(
appId: 'your-app-id',
secret: 'your-app-secret',
transport: 'http',
userId: userId,
logs: true,
onConnected: () {},
onMessage: (_) {},
onDisconnected: ({code, reason}) {},
);
When logs: true, sendAI reports session start, completion, and token usage to DNotifier.
Workflows and agents #
Build deterministic, multi-step AI pipelines with named agents, shared workflow state, and optional observability (execution and step telemetry in the DNotifier workflow dashboard).
1. Define agents #
import 'package:dnotifier/dnotifier.dart';
final intentAgent = DNotifier.defineAgent(
name: 'intent-agent',
run: (ctx) async {
await ctx.sendAI(
message: {'text': 'Classify: search or general?'},
saveHistory: false,
label: 'Intent classification',
);
return {'intent': 'search'};
},
);
final generalAgent = DNotifier.defineAgent(
name: 'general-agent',
run: (ctx) async {
final input = ctx.input;
final question = input is Map ? input['question'] : input;
return {'answer': 'You asked: $question'};
},
);
2. Define a workflow #
final workflow = Workflow(
name: 'intent-router',
description: 'Route user input to search or general Q&A',
observability: true,
entry: (ctx) async {
final intentResult = await ctx.runAgent('intent-agent');
final intent = (intentResult as Map)['intent'];
if (intent == 'search') {
await ctx.search(
query: ctx.input.toString(),
limit: 5,
label: 'Knowledge search',
);
return {'branch': 'search'};
}
final answer = await ctx.runAgent(
'general-agent',
input: {'question': ctx.input},
);
return {'branch': 'general', 'answer': answer};
},
).registerAgents({
'intent-agent': intentAgent,
'general-agent': generalAgent,
});
3. Run the workflow #
final notifier = DNotifier(
appId: 'your-app-id',
secret: 'your-app-secret',
transport: 'http',
userId: userId,
onConnected: () {},
onMessage: (_) {},
onDisconnected: ({code, reason}) {},
);
await notifier.connect();
final run = await notifier.runWorkflow(
workflow: workflow,
input: 'How does messaging work?',
);
print(run.executionId); // present when observability: true
print(run.result);
print(run.state);
Multi-stage pipeline example #
final contentAgent = DNotifier.defineAgent(
name: 'content-creator',
run: (ctx) async {
final brief = ctx.input as Map<String, dynamic>;
final response = await ctx.sendAI(
message: {
'useKnowledgeBase': false,
'messages': [
{'role': 'system', 'content': 'Write a blog draft in markdown.'},
{'role': 'user', 'content': 'Topic: ${brief['topic']}'},
],
},
saveHistory: false,
label: 'Draft creation',
);
final content = (response as Map?)?['data']?['content']?.toString() ?? '';
ctx.state['draft'] = content;
return {'content': content};
},
);
final workflow = Workflow(
name: 'blog-article-writer',
description: 'Create, refine, and optimize a blog post',
observability: true,
entry: (ctx) async {
final draft = await ctx.runAgent('content-creator');
final refined = await ctx.runAgent(
'clarity-editor',
input: {'content': (draft as Map)['content']},
);
return {'article': (refined as Map)['content']};
},
).registerAgents({
'content-creator': contentAgent,
'clarity-editor': clarityEditorAgent,
});
WorkflowContext (inside entry and agent run) #
| Member / method | Description |
|---|---|
ctx.input |
Workflow input passed to runWorkflow (or overridden per runAgent) |
ctx.state |
Shared mutable map for the current execution |
ctx.agentName |
Name of the agent currently running (inside agent handlers) |
ctx.runAgent(name, {input}) |
Invoke a registered agent |
ctx.sendAI({message, saveHistory?, sessionId?, label?}) |
AI call; steps recorded when observability is on |
ctx.fetchAIHistory({label?}) |
Fetch AI history |
ctx.search({query, limit?, minSimilarity?, filterbySource?, label?}) |
Semantic search |
ctx.addDocument(...) |
Add knowledge-base document |
ctx.updateDocument(...) |
Update document |
ctx.deleteDocument(...) |
Delete document |
ctx.listDocuments(...) |
List documents |
ctx.getDocument(...) |
Get document by id |
ctx.recordStep({label, input?, output?, status?, type?}) |
Record a custom step when observability is enabled |
When observability: true on the workflow, SDK calls and recordStep are sent to the DNotifier workflow dashboard. No extra setup is required beyond connect().
API reference #
DNotifier #
| Method / property | Description |
|---|---|
connect() |
Authenticate and connect |
disconnect() |
Close the WebSocket connection |
getPlanLimits() |
Plan limits from last auth |
send(...) |
Send a message (senderId, receiverId / receiverIds, data) |
sendBinary(...) |
Send raw bytes |
sendAI(...) |
Send to AI pipeline |
fetchAIHistory(...) |
Fetch AI conversation history |
deleteAIHistoryMessage(...) |
Delete one AI history message |
fetchChatHistory(...) |
Request chat history (response via onMessage) |
deleteChatHistoryMessage(...) |
Delete one chat history message |
search(...) |
Semantic search over knowledge base |
addDocument(...) |
Add a document |
updateDocument(...) |
Update a document |
getDocument(...) |
Get a document |
listDocuments(...) |
List documents |
deleteDocument(...) |
Delete a document |
runWorkflow({workflow, input, senderId?}) |
Run a workflow after connect() |
sendWithOpenAI(...) |
Deprecated — use sendAI |
isConnected, aiEnabled, authToken, messageSizeLimit |
Connection and plan state |
Workflow exports #
| Export | Description |
|---|---|
defineAgent / DNotifier.defineAgent |
Create a named agent |
Agent |
Agent class |
Workflow |
Workflow definition (name, description, observability, entry, registerAgents) |
WorkflowContext |
Context passed to entry and agent run |
WorkflowRunResult |
Result of runWorkflow (result, state, executionId?) |
WorkflowError |
Workflow validation and runtime errors |
Use notifier.runWorkflow() to execute workflows. WorkflowRunner is available for advanced custom hosting but is not required for typical use.
Types #
DNotifierMessage
metadata—DNotifierMessageMetadata(id,sender,timestamp,type)payload—Payload
Payload
toJSON()— parse JSON bodytoString()— string bodytoBase64()— base64 stringraw()— raw bytes
DNotifierPlanLimits
messagesHardLimit,maxAIRequestsPerMonth,maxAIWordsPerMonthknowledgeBaseMaxWords,aiEnabled,maxUsers,maxRowsPerUser
WorkflowRunResult
result— return value of the workflowentryfunctionstate— final shared workflow stateexecutionId— present whenobservability: true
Links #
- Product: dnotifier.com
- Documentation: Product docs
- Package: pub.dev/packages/dnotifier