dnotifier 1.1.14 copy "dnotifier: ^1.1.14" to clipboard
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, semantic search
  • 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

  • metadataDNotifierMessageMetadata (id, sender, timestamp, type)
  • payloadPayload

Payload

  • toJSON() — parse JSON body
  • toString() — string body
  • toBase64() — base64 string
  • raw() — raw bytes

DNotifierPlanLimits

  • messagesHardLimit, maxAIRequestsPerMonth, maxAIWordsPerMonth
  • knowledgeBaseMaxWords, aiEnabled, maxUsers, maxRowsPerUser

WorkflowRunResult

  • result — return value of the workflow entry function
  • state — final shared workflow state
  • executionId — present when observability: true

1
likes
95
points
113
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

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 code—works everywhere.

Homepage
Repository (GitHub)

License

unknown (license)

Dependencies

http, uuid, web_socket_channel

More

Packages that depend on dnotifier