first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,60 @@
import type {
IDataObject,
IExecuteFunctions,
IHttpRequestMethods,
ILoadOptionsFunctions,
IRequestOptions,
JsonObject,
} from 'n8n-workflow';
import { NodeApiError } from 'n8n-workflow';
export async function pushbulletApiRequest(
this: IExecuteFunctions | ILoadOptionsFunctions,
method: IHttpRequestMethods,
path: string,
body: any = {},
qs: IDataObject = {},
uri?: string,
option = {},
): Promise<any> {
const options: IRequestOptions = {
method,
body,
qs,
uri: uri || `https://api.pushbullet.com/v2${path}`,
json: true,
};
try {
if (Object.keys(body as IDataObject).length === 0) {
delete options.body;
}
if (Object.keys(option).length !== 0) {
Object.assign(options, option);
}
return await this.helpers.requestOAuth2.call(this, 'pushbulletOAuth2Api', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
}
export async function pushbulletApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: IHttpRequestMethods,
endpoint: string,
body: any = {},
query: IDataObject = {},
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
do {
responseData = await pushbulletApiRequest.call(this, method, endpoint, body, query);
returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]);
} while (responseData.cursor !== undefined);
return returnData;
}
@@ -0,0 +1,18 @@
{
"node": "n8n-nodes-base.pushbullet",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Communication"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/pushbullet/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.pushbullet/"
}
]
}
}
@@ -0,0 +1,511 @@
import moment from 'moment-timezone';
import type {
IDataObject,
IExecuteFunctions,
ILoadOptionsFunctions,
INodeExecutionData,
INodePropertyOptions,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { pushbulletApiRequest, pushbulletApiRequestAllItems } from './GenericFunctions';
export class Pushbullet implements INodeType {
description: INodeTypeDescription = {
displayName: 'Pushbullet',
name: 'pushbullet',
icon: 'file:pushbullet.svg',
group: ['input'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Pushbullet API',
defaults: {
name: 'Pushbullet',
},
usableAsTool: true,
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'pushbulletOAuth2Api',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Push',
value: 'push',
},
],
default: 'push',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['push'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a push',
action: 'Create a push',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a push',
action: 'Delete a push',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get many pushes',
action: 'Get many pushes',
},
{
name: 'Update',
value: 'update',
description: 'Update a push',
action: 'Update a push',
},
],
default: 'create',
},
{
displayName: 'Type',
name: 'type',
type: 'options',
options: [
{
name: 'File',
value: 'file',
},
{
name: 'Link',
value: 'link',
},
{
name: 'Note',
value: 'note',
},
],
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['create'],
},
},
default: 'note',
},
{
displayName: 'Title',
name: 'title',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['create'],
type: ['note', 'link'],
},
},
default: '',
description: 'Title of the push',
},
{
displayName: 'Body',
name: 'body',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['create'],
type: ['note', 'link', 'file'],
},
},
default: '',
description: 'Body of the push',
},
{
displayName: 'URL',
name: 'url',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['create'],
type: ['link'],
},
},
default: '',
description: 'URL of the push',
},
{
displayName: 'Input Binary Field',
name: 'binaryPropertyName',
type: 'string',
default: 'data',
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['create'],
type: ['file'],
},
},
placeholder: '',
hint: 'The name of the input binary field containing the file to be written',
},
{
displayName: 'Target',
name: 'target',
type: 'options',
options: [
{
name: 'Channel Tag',
value: 'channel_tag',
description: 'Send the push to all subscribers to your channel that has this tag',
},
{
name: 'Default',
value: 'default',
description: "Broadcast it to all of the user's devices",
},
{
name: 'Device ID',
value: 'device_iden',
description: 'Send the push to a specific device',
},
{
name: 'Email',
value: 'email',
description: 'Send the push to this email address',
},
],
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['create'],
},
},
default: 'default',
description: 'Define the medium that will be used to send the push',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['create'],
},
hide: {
target: ['default', 'device_iden'],
},
},
default: '',
description:
'The value to be set depending on the target selected. For example, if the target selected is email then this field would take the email address of the person you are trying to send the push to.',
},
{
displayName: 'Value Name or ID',
name: 'value',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getDevices',
},
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['create'],
target: ['device_iden'],
},
},
default: '',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
},
{
displayName: 'Push ID',
name: 'pushId',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['delete'],
},
},
default: '',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
operation: ['getAll'],
resource: ['push'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
operation: ['getAll'],
resource: ['push'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
maxValue: 500,
},
default: 100,
description: 'Max number of results to return',
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: ['push'],
operation: ['getAll'],
},
},
options: [
{
displayName: 'Active',
name: 'active',
type: 'boolean',
default: false,
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: "Don't return deleted pushes",
},
{
displayName: 'Modified After',
name: 'modified_after',
type: 'dateTime',
default: '',
description: 'Request pushes modified after this timestamp',
},
],
},
{
displayName: 'Push ID',
name: 'pushId',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['update'],
},
},
default: '',
},
{
displayName: 'Dismissed',
name: 'dismissed',
type: 'boolean',
required: true,
displayOptions: {
show: {
resource: ['push'],
operation: ['update'],
},
},
default: false,
description:
'Whether to mark a push as having been dismissed by the user, will cause any notifications for the push to be hidden if possible',
},
],
};
methods = {
loadOptions: {
async getDevices(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const { devices } = await pushbulletApiRequest.call(this, 'GET', '/devices');
for (const device of devices) {
returnData.push({
name: device.nickname,
value: device.iden,
});
}
return returnData;
},
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: INodeExecutionData[] = [];
const length = items.length;
const qs: IDataObject = {};
let responseData;
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
for (let i = 0; i < length; i++) {
try {
if (resource === 'push') {
if (operation === 'create') {
const type = this.getNodeParameter('type', i) as string;
const message = this.getNodeParameter('body', i) as string;
const target = this.getNodeParameter('target', i) as string;
const body: IDataObject = {
type,
body: message,
};
if (target !== 'default') {
const value = this.getNodeParameter('value', i) as string;
body[target] = value;
}
if (['note', 'link'].includes(type)) {
body.title = this.getNodeParameter('title', i) as string;
if (type === 'link') {
body.url = this.getNodeParameter('url', i) as string;
}
}
if (type === 'file') {
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', 0);
const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
//create upload url
const {
upload_url: uploadUrl,
file_name,
file_type,
file_url,
} = await pushbulletApiRequest.call(this, 'POST', '/upload-request', {
file_name: binaryData.fileName,
file_type: binaryData.mimeType,
});
//upload the file
await pushbulletApiRequest.call(this, 'POST', '', {}, {}, uploadUrl as string, {
formData: {
file: {
value: dataBuffer,
options: {
filename: binaryData.fileName,
},
},
},
json: false,
});
body.file_name = file_name;
body.file_type = file_type;
body.file_url = file_url;
}
responseData = await pushbulletApiRequest.call(this, 'POST', '/pushes', body);
}
if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', 0);
const filters = this.getNodeParameter('filters', i);
Object.assign(qs, filters);
if (qs.modified_after) {
qs.modified_after = moment(qs.modified_after as string).unix();
}
if (returnAll) {
responseData = await pushbulletApiRequestAllItems.call(
this,
'pushes',
'GET',
'/pushes',
{},
qs,
);
} else {
qs.limit = this.getNodeParameter('limit', 0);
responseData = await pushbulletApiRequest.call(this, 'GET', '/pushes', {}, qs);
responseData = responseData.pushes;
}
}
if (operation === 'delete') {
const pushId = this.getNodeParameter('pushId', i) as string;
responseData = await pushbulletApiRequest.call(this, 'DELETE', `/pushes/${pushId}`);
responseData = { success: true };
}
if (operation === 'update') {
const pushId = this.getNodeParameter('pushId', i) as string;
const dismissed = this.getNodeParameter('dismissed', i) as boolean;
responseData = await pushbulletApiRequest.call(this, 'POST', `/pushes/${pushId}`, {
dismissed,
});
}
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...executionData);
} catch (error) {
if (this.continueOnFail()) {
const executionErrorData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ error: error.message }),
{ itemData: { item: i } },
);
returnData.push(...executionErrorData);
continue;
}
throw error;
}
}
return [returnData];
}
}
@@ -0,0 +1,48 @@
{
"type": "object",
"properties": {
"active": {
"type": "boolean"
},
"body": {
"type": "string"
},
"client_iden": {
"type": "string"
},
"created": {
"type": "number"
},
"direction": {
"type": "string"
},
"dismissed": {
"type": "boolean"
},
"iden": {
"type": "string"
},
"modified": {
"type": "number"
},
"receiver_email": {
"type": "string"
},
"receiver_email_normalized": {
"type": "string"
},
"receiver_iden": {
"type": "string"
},
"sender_name": {
"type": "string"
},
"title": {
"type": "string"
},
"type": {
"type": "string"
}
},
"version": 1
}
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256" style="-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)" transform="rotate(360)"><defs><linearGradient id="c" x1="8.59%" x2="77.471%" y1="1.954%" y2="73.896%"><stop offset="0%" stop-color="#4CB36B"/><stop offset="100%" stop-color="#3EA16F"/></linearGradient><path id="a" d="M256 128c0 70.692-57.308 128-128 128S0 198.692 0 128 57.308 0 128 0s128 57.308 128 128"/></defs><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><use xlink:href="#a" fill="#67BF79"/><path fill="#67BF79" d="M256 128c0 70.692-57.308 128-128 128S0 198.692 0 128 57.308 0 128 0s128 57.308 128 128" mask="url(#b)"/><path fill="url(#c)" d="M63.111 187.022 96.178 72l64.533 60.978L200 90.133l87.533 86.289-110.844 124.889z" mask="url(#b)"/><path fill="#FFF" d="M77 189.6c-16.733 0-16.733 0-16.733-16.733V81c0-16.733 0-16.733 16.733-16.733h3.334c16.733 0 16.733 0 16.733 16.733v91.867c0 16.733 0 16.733-16.733 16.733zm44.041 0c-5.699 0-8.508-2.809-8.508-8.508V72.774c0-5.698 2.809-8.507 8.508-8.507h37.537c32.178 0 52.628 32.273 52.628 63.025S190.578 189.6 158.578 189.6z" mask="url(#b)"/><path fill="rgba(0, 0, 0, 0)" d="M0 0h256v256H0z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB