n8n-nodes-pb 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -0
- package/dist/credentials/PocketBaseApi.credentials.d.ts +9 -0
- package/dist/credentials/PocketBaseApi.credentials.js +60 -0
- package/dist/icons/pocketbase.svg +5 -0
- package/dist/nodes/PocketBase/GenericFunctions.d.ts +5 -0
- package/dist/nodes/PocketBase/GenericFunctions.js +47 -0
- package/dist/nodes/PocketBase/PocketBase.node.d.ts +5 -0
- package/dist/nodes/PocketBase/PocketBase.node.js +239 -0
- package/dist/nodes/PocketBase/descriptions/CollectionDescription.d.ts +3 -0
- package/dist/nodes/PocketBase/descriptions/CollectionDescription.js +48 -0
- package/dist/nodes/PocketBase/descriptions/FileDescription.d.ts +3 -0
- package/dist/nodes/PocketBase/descriptions/FileDescription.js +101 -0
- package/dist/nodes/PocketBase/descriptions/RecordDescription.d.ts +3 -0
- package/dist/nodes/PocketBase/descriptions/RecordDescription.js +222 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# n8n-nodes-pocketbase
|
|
2
|
+
|
|
3
|
+
This is an n8n community node for [PocketBase](https://pocketbase.io/) - an open-source backend with realtime database, authentication, and file storage.
|
|
4
|
+
|
|
5
|
+
[n8n](https://n8n.io/) is a [fair-code licensed](https://docs.n8n.io/reference/license/) workflow automation platform.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) in the n8n community nodes documentation.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install n8n-nodes-pocketbase
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
This node supports the following PocketBase API operations:
|
|
18
|
+
|
|
19
|
+
### Records
|
|
20
|
+
- **Get Many** - List records with filter, sort, and pagination
|
|
21
|
+
- **Get** - Get a single record by ID
|
|
22
|
+
- **Create** - Create a new record
|
|
23
|
+
- **Update** - Update an existing record
|
|
24
|
+
- **Delete** - Delete a record
|
|
25
|
+
|
|
26
|
+
### Collections
|
|
27
|
+
- **Get Many** - List all collections
|
|
28
|
+
- **Get** - Get collection details
|
|
29
|
+
|
|
30
|
+
### Files
|
|
31
|
+
- **Get URL** - Get file download URL with optional thumbnail
|
|
32
|
+
- **Get Token** - Get protected file access token
|
|
33
|
+
|
|
34
|
+
### Health
|
|
35
|
+
- **Check** - Check PocketBase server health status
|
|
36
|
+
|
|
37
|
+
## Credentials
|
|
38
|
+
|
|
39
|
+
To use this node, you need to configure the following credentials:
|
|
40
|
+
|
|
41
|
+
| Field | Description |
|
|
42
|
+
|-------|-------------|
|
|
43
|
+
| **PocketBase URL** | Your PocketBase instance URL (e.g., `https://your-pb.com`) |
|
|
44
|
+
| **Email** | Admin or user email |
|
|
45
|
+
| **Password** | Account password |
|
|
46
|
+
| **Auth Collection** | Authentication collection (default: `_superusers`) |
|
|
47
|
+
|
|
48
|
+
## Compatibility
|
|
49
|
+
|
|
50
|
+
- **PocketBase**: v0.22.0+
|
|
51
|
+
- **n8n**: v1.0.0+
|
|
52
|
+
|
|
53
|
+
## Resources
|
|
54
|
+
|
|
55
|
+
- [PocketBase Documentation](https://pocketbase.io/docs)
|
|
56
|
+
- [n8n Community Nodes](https://docs.n8n.io/integrations/community-nodes/)
|
|
57
|
+
|
|
58
|
+
## License
|
|
59
|
+
|
|
60
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class PocketBaseApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
authenticate: IAuthenticateGeneric;
|
|
8
|
+
test: ICredentialTestRequest;
|
|
9
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PocketBaseApi = void 0;
|
|
4
|
+
class PocketBaseApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'pocketBaseApi';
|
|
7
|
+
this.displayName = 'PocketBase API';
|
|
8
|
+
this.documentationUrl = 'https://pocketbase.io/docs';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'PocketBase URL',
|
|
12
|
+
name: 'url',
|
|
13
|
+
type: 'string',
|
|
14
|
+
default: 'http://127.0.0.1:8090',
|
|
15
|
+
placeholder: 'https://your-pocketbase.com',
|
|
16
|
+
description: 'The URL of your PocketBase instance',
|
|
17
|
+
required: true,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
displayName: 'Email',
|
|
21
|
+
name: 'email',
|
|
22
|
+
type: 'string',
|
|
23
|
+
default: '',
|
|
24
|
+
placeholder: 'admin@example.com',
|
|
25
|
+
description: 'Admin or user email for authentication',
|
|
26
|
+
required: true,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
displayName: 'Password',
|
|
30
|
+
name: 'password',
|
|
31
|
+
type: 'string',
|
|
32
|
+
typeOptions: {
|
|
33
|
+
password: true,
|
|
34
|
+
},
|
|
35
|
+
default: '',
|
|
36
|
+
description: 'Password for authentication',
|
|
37
|
+
required: true,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
displayName: 'Auth Collection',
|
|
41
|
+
name: 'authCollection',
|
|
42
|
+
type: 'string',
|
|
43
|
+
default: '_superusers',
|
|
44
|
+
description: 'The auth collection to authenticate against (e.g., _superusers, users)',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
this.authenticate = {
|
|
48
|
+
type: 'generic',
|
|
49
|
+
properties: {},
|
|
50
|
+
};
|
|
51
|
+
this.test = {
|
|
52
|
+
request: {
|
|
53
|
+
baseURL: '={{$credentials.url}}',
|
|
54
|
+
url: '/api/health',
|
|
55
|
+
method: 'GET',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.PocketBaseApi = PocketBaseApi;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" fill="none">
|
|
2
|
+
<rect width="128" height="128" rx="16" fill="#16161a"/>
|
|
3
|
+
<path d="M64 24C41.909 24 24 41.909 24 64s17.909 40 40 40 40-17.909 40-40S86.091 24 64 24zm0 64c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24z" fill="#3C82F6"/>
|
|
4
|
+
<circle cx="64" cy="64" r="12" fill="#3C82F6"/>
|
|
5
|
+
</svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import PocketBase from 'pocketbase';
|
|
2
|
+
import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-workflow';
|
|
3
|
+
export declare function getPocketBaseClient(this: IExecuteFunctions | ILoadOptionsFunctions): Promise<PocketBase>;
|
|
4
|
+
export declare function handlePocketBaseError(context: IExecuteFunctions, error: unknown, itemIndex: number): never;
|
|
5
|
+
export declare function clearTokenCache(): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getPocketBaseClient = getPocketBaseClient;
|
|
7
|
+
exports.handlePocketBaseError = handlePocketBaseError;
|
|
8
|
+
exports.clearTokenCache = clearTokenCache;
|
|
9
|
+
const pocketbase_1 = __importDefault(require("pocketbase"));
|
|
10
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
11
|
+
const tokenCache = new Map();
|
|
12
|
+
async function getPocketBaseClient() {
|
|
13
|
+
const credentials = await this.getCredentials('pocketBaseApi');
|
|
14
|
+
const url = credentials.url;
|
|
15
|
+
const email = credentials.email;
|
|
16
|
+
const password = credentials.password;
|
|
17
|
+
const authCollection = credentials.authCollection || '_superusers';
|
|
18
|
+
const pb = new pocketbase_1.default(url);
|
|
19
|
+
const cacheKey = `${url}:${email}`;
|
|
20
|
+
const cached = tokenCache.get(cacheKey);
|
|
21
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
22
|
+
pb.authStore.save(cached.token, null);
|
|
23
|
+
return pb;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const authData = await pb.collection(authCollection).authWithPassword(email, password);
|
|
27
|
+
tokenCache.set(cacheKey, {
|
|
28
|
+
token: authData.token,
|
|
29
|
+
expiresAt: Date.now() + 60 * 60 * 1000,
|
|
30
|
+
});
|
|
31
|
+
return pb;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
35
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: errorMessage }, {
|
|
36
|
+
message: 'PocketBase authentication failed',
|
|
37
|
+
description: `Failed to authenticate with ${authCollection}: ${errorMessage}`,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function handlePocketBaseError(context, error, itemIndex) {
|
|
42
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
43
|
+
throw new n8n_workflow_1.NodeApiError(context.getNode(), { message: errorMessage }, { itemIndex });
|
|
44
|
+
}
|
|
45
|
+
function clearTokenCache() {
|
|
46
|
+
tokenCache.clear();
|
|
47
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PocketBase = void 0;
|
|
4
|
+
const GenericFunctions_1 = require("./GenericFunctions");
|
|
5
|
+
const RecordDescription_1 = require("./descriptions/RecordDescription");
|
|
6
|
+
const CollectionDescription_1 = require("./descriptions/CollectionDescription");
|
|
7
|
+
const FileDescription_1 = require("./descriptions/FileDescription");
|
|
8
|
+
class PocketBase {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.description = {
|
|
11
|
+
displayName: 'PocketBase',
|
|
12
|
+
name: 'pocketBase',
|
|
13
|
+
icon: 'file:pocketbase.svg',
|
|
14
|
+
group: ['transform'],
|
|
15
|
+
version: 1,
|
|
16
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
17
|
+
description: 'Interact with PocketBase API',
|
|
18
|
+
defaults: {
|
|
19
|
+
name: 'PocketBase',
|
|
20
|
+
},
|
|
21
|
+
inputs: ['main'],
|
|
22
|
+
outputs: ['main'],
|
|
23
|
+
credentials: [
|
|
24
|
+
{
|
|
25
|
+
name: 'pocketBaseApi',
|
|
26
|
+
required: true,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
properties: [
|
|
30
|
+
{
|
|
31
|
+
displayName: 'Resource',
|
|
32
|
+
name: 'resource',
|
|
33
|
+
type: 'options',
|
|
34
|
+
noDataExpression: true,
|
|
35
|
+
options: [
|
|
36
|
+
{
|
|
37
|
+
name: 'Record',
|
|
38
|
+
value: 'record',
|
|
39
|
+
description: 'Work with records in a collection',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Collection',
|
|
43
|
+
value: 'collection',
|
|
44
|
+
description: 'Work with collections',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'File',
|
|
48
|
+
value: 'file',
|
|
49
|
+
description: 'Work with files',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'Health',
|
|
53
|
+
value: 'health',
|
|
54
|
+
description: 'Check server health',
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
default: 'record',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
displayName: 'Operation',
|
|
61
|
+
name: 'operation',
|
|
62
|
+
type: 'options',
|
|
63
|
+
noDataExpression: true,
|
|
64
|
+
displayOptions: {
|
|
65
|
+
show: {
|
|
66
|
+
resource: ['health'],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
options: [
|
|
70
|
+
{
|
|
71
|
+
name: 'Check',
|
|
72
|
+
value: 'check',
|
|
73
|
+
description: 'Check server health status',
|
|
74
|
+
action: 'Check health',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
default: 'check',
|
|
78
|
+
},
|
|
79
|
+
...RecordDescription_1.recordOperations,
|
|
80
|
+
...RecordDescription_1.recordFields,
|
|
81
|
+
...CollectionDescription_1.collectionOperations,
|
|
82
|
+
...CollectionDescription_1.collectionFields,
|
|
83
|
+
...FileDescription_1.fileOperations,
|
|
84
|
+
...FileDescription_1.fileFields,
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async execute() {
|
|
89
|
+
const items = this.getInputData();
|
|
90
|
+
const returnData = [];
|
|
91
|
+
const resource = this.getNodeParameter('resource', 0);
|
|
92
|
+
const operation = this.getNodeParameter('operation', 0);
|
|
93
|
+
const pb = await GenericFunctions_1.getPocketBaseClient.call(this);
|
|
94
|
+
for (let i = 0; i < items.length; i++) {
|
|
95
|
+
try {
|
|
96
|
+
let responseData;
|
|
97
|
+
if (resource === 'record') {
|
|
98
|
+
const collection = this.getNodeParameter('collection', i);
|
|
99
|
+
if (operation === 'getMany') {
|
|
100
|
+
const returnAll = this.getNodeParameter('returnAll', i);
|
|
101
|
+
const options = this.getNodeParameter('options', i, {});
|
|
102
|
+
const queryOptions = {};
|
|
103
|
+
if (options.filter)
|
|
104
|
+
queryOptions.filter = options.filter;
|
|
105
|
+
if (options.sort)
|
|
106
|
+
queryOptions.sort = options.sort;
|
|
107
|
+
if (options.expand)
|
|
108
|
+
queryOptions.expand = options.expand;
|
|
109
|
+
if (options.fields)
|
|
110
|
+
queryOptions.fields = options.fields;
|
|
111
|
+
if (returnAll) {
|
|
112
|
+
const records = await pb.collection(collection).getFullList(queryOptions);
|
|
113
|
+
responseData = records;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const limit = this.getNodeParameter('limit', i);
|
|
117
|
+
const result = await pb.collection(collection).getList(1, limit, queryOptions);
|
|
118
|
+
responseData = result.items;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (operation === 'get') {
|
|
122
|
+
const recordId = this.getNodeParameter('recordId', i);
|
|
123
|
+
const options = this.getNodeParameter('options', i, {});
|
|
124
|
+
const queryOptions = {};
|
|
125
|
+
if (options.expand)
|
|
126
|
+
queryOptions.expand = options.expand;
|
|
127
|
+
const record = await pb.collection(collection).getOne(recordId, queryOptions);
|
|
128
|
+
responseData = record;
|
|
129
|
+
}
|
|
130
|
+
if (operation === 'create') {
|
|
131
|
+
const fieldsInput = this.getNodeParameter('fields', i, {});
|
|
132
|
+
const options = this.getNodeParameter('options', i, {});
|
|
133
|
+
const data = {};
|
|
134
|
+
if (fieldsInput.field) {
|
|
135
|
+
for (const field of fieldsInput.field) {
|
|
136
|
+
try {
|
|
137
|
+
data[field.name] = JSON.parse(field.value);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
data[field.name] = field.value;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const queryOptions = {};
|
|
145
|
+
if (options.expand)
|
|
146
|
+
queryOptions.expand = options.expand;
|
|
147
|
+
const record = await pb.collection(collection).create(data, queryOptions);
|
|
148
|
+
responseData = record;
|
|
149
|
+
}
|
|
150
|
+
if (operation === 'update') {
|
|
151
|
+
const recordId = this.getNodeParameter('recordId', i);
|
|
152
|
+
const fieldsInput = this.getNodeParameter('fields', i, {});
|
|
153
|
+
const options = this.getNodeParameter('options', i, {});
|
|
154
|
+
const data = {};
|
|
155
|
+
if (fieldsInput.field) {
|
|
156
|
+
for (const field of fieldsInput.field) {
|
|
157
|
+
try {
|
|
158
|
+
data[field.name] = JSON.parse(field.value);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
data[field.name] = field.value;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const queryOptions = {};
|
|
166
|
+
if (options.expand)
|
|
167
|
+
queryOptions.expand = options.expand;
|
|
168
|
+
const record = await pb.collection(collection).update(recordId, data, queryOptions);
|
|
169
|
+
responseData = record;
|
|
170
|
+
}
|
|
171
|
+
if (operation === 'delete') {
|
|
172
|
+
const recordId = this.getNodeParameter('recordId', i);
|
|
173
|
+
await pb.collection(collection).delete(recordId);
|
|
174
|
+
responseData = { success: true, deleted: recordId };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (resource === 'collection') {
|
|
178
|
+
if (operation === 'getMany') {
|
|
179
|
+
const collections = await pb.collections.getFullList();
|
|
180
|
+
responseData = collections;
|
|
181
|
+
}
|
|
182
|
+
if (operation === 'get') {
|
|
183
|
+
const collectionId = this.getNodeParameter('collectionId', i);
|
|
184
|
+
const col = await pb.collections.getOne(collectionId);
|
|
185
|
+
responseData = col;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (resource === 'file') {
|
|
189
|
+
if (operation === 'getUrl') {
|
|
190
|
+
const collection = this.getNodeParameter('collection', i);
|
|
191
|
+
const recordId = this.getNodeParameter('recordId', i);
|
|
192
|
+
const filename = this.getNodeParameter('filename', i);
|
|
193
|
+
const options = this.getNodeParameter('options', i, {});
|
|
194
|
+
const record = await pb.collection(collection).getOne(recordId);
|
|
195
|
+
const urlOptions = {};
|
|
196
|
+
if (options.thumb)
|
|
197
|
+
urlOptions.thumb = options.thumb;
|
|
198
|
+
const fileUrl = pb.files.getURL(record, filename, urlOptions);
|
|
199
|
+
responseData = { url: fileUrl, filename, recordId, collection };
|
|
200
|
+
}
|
|
201
|
+
if (operation === 'getToken') {
|
|
202
|
+
const token = await pb.files.getToken();
|
|
203
|
+
responseData = { token };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (resource === 'health') {
|
|
207
|
+
if (operation === 'check') {
|
|
208
|
+
const health = await pb.health.check();
|
|
209
|
+
responseData = health;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (Array.isArray(responseData)) {
|
|
213
|
+
returnData.push(...responseData.map((item) => ({
|
|
214
|
+
json: item,
|
|
215
|
+
pairedItem: { item: i },
|
|
216
|
+
})));
|
|
217
|
+
}
|
|
218
|
+
else if (responseData) {
|
|
219
|
+
returnData.push({
|
|
220
|
+
json: responseData,
|
|
221
|
+
pairedItem: { item: i },
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
if (this.continueOnFail()) {
|
|
227
|
+
returnData.push({
|
|
228
|
+
json: { error: error.message },
|
|
229
|
+
pairedItem: { item: i },
|
|
230
|
+
});
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
(0, GenericFunctions_1.handlePocketBaseError)(this, error, i);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return [returnData];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
exports.PocketBase = PocketBase;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.collectionFields = exports.collectionOperations = void 0;
|
|
4
|
+
exports.collectionOperations = [
|
|
5
|
+
{
|
|
6
|
+
displayName: 'Operation',
|
|
7
|
+
name: 'operation',
|
|
8
|
+
type: 'options',
|
|
9
|
+
noDataExpression: true,
|
|
10
|
+
displayOptions: {
|
|
11
|
+
show: {
|
|
12
|
+
resource: ['collection'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
options: [
|
|
16
|
+
{
|
|
17
|
+
name: 'Get Many',
|
|
18
|
+
value: 'getMany',
|
|
19
|
+
description: 'Get all collections',
|
|
20
|
+
action: 'Get many collections',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'Get',
|
|
24
|
+
value: 'get',
|
|
25
|
+
description: 'Get a collection by ID or name',
|
|
26
|
+
action: 'Get a collection',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
default: 'getMany',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
exports.collectionFields = [
|
|
33
|
+
{
|
|
34
|
+
displayName: 'Collection ID or Name',
|
|
35
|
+
name: 'collectionId',
|
|
36
|
+
type: 'string',
|
|
37
|
+
required: true,
|
|
38
|
+
default: '',
|
|
39
|
+
placeholder: 'notes',
|
|
40
|
+
description: 'ID or name of the collection',
|
|
41
|
+
displayOptions: {
|
|
42
|
+
show: {
|
|
43
|
+
resource: ['collection'],
|
|
44
|
+
operation: ['get'],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
];
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fileFields = exports.fileOperations = void 0;
|
|
4
|
+
exports.fileOperations = [
|
|
5
|
+
{
|
|
6
|
+
displayName: 'Operation',
|
|
7
|
+
name: 'operation',
|
|
8
|
+
type: 'options',
|
|
9
|
+
noDataExpression: true,
|
|
10
|
+
displayOptions: {
|
|
11
|
+
show: {
|
|
12
|
+
resource: ['file'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
options: [
|
|
16
|
+
{
|
|
17
|
+
name: 'Get URL',
|
|
18
|
+
value: 'getUrl',
|
|
19
|
+
description: 'Get the URL of a file',
|
|
20
|
+
action: 'Get file URL',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'Get Token',
|
|
24
|
+
value: 'getToken',
|
|
25
|
+
description: 'Get a token for accessing protected files',
|
|
26
|
+
action: 'Get file token',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
default: 'getUrl',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
exports.fileFields = [
|
|
33
|
+
{
|
|
34
|
+
displayName: 'Collection Name',
|
|
35
|
+
name: 'collection',
|
|
36
|
+
type: 'string',
|
|
37
|
+
required: true,
|
|
38
|
+
default: '',
|
|
39
|
+
placeholder: 'notes',
|
|
40
|
+
description: 'Name of the collection',
|
|
41
|
+
displayOptions: {
|
|
42
|
+
show: {
|
|
43
|
+
resource: ['file'],
|
|
44
|
+
operation: ['getUrl'],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
displayName: 'Record ID',
|
|
50
|
+
name: 'recordId',
|
|
51
|
+
type: 'string',
|
|
52
|
+
required: true,
|
|
53
|
+
default: '',
|
|
54
|
+
placeholder: 'abc123xyz',
|
|
55
|
+
description: 'ID of the record',
|
|
56
|
+
displayOptions: {
|
|
57
|
+
show: {
|
|
58
|
+
resource: ['file'],
|
|
59
|
+
operation: ['getUrl'],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
displayName: 'Filename',
|
|
65
|
+
name: 'filename',
|
|
66
|
+
type: 'string',
|
|
67
|
+
required: true,
|
|
68
|
+
default: '',
|
|
69
|
+
placeholder: 'image.jpg',
|
|
70
|
+
description: 'Name of the file',
|
|
71
|
+
displayOptions: {
|
|
72
|
+
show: {
|
|
73
|
+
resource: ['file'],
|
|
74
|
+
operation: ['getUrl'],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
displayName: 'Options',
|
|
80
|
+
name: 'options',
|
|
81
|
+
type: 'collection',
|
|
82
|
+
placeholder: 'Add Option',
|
|
83
|
+
default: {},
|
|
84
|
+
displayOptions: {
|
|
85
|
+
show: {
|
|
86
|
+
resource: ['file'],
|
|
87
|
+
operation: ['getUrl'],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
options: [
|
|
91
|
+
{
|
|
92
|
+
displayName: 'Thumb',
|
|
93
|
+
name: 'thumb',
|
|
94
|
+
type: 'string',
|
|
95
|
+
default: '',
|
|
96
|
+
placeholder: '100x100',
|
|
97
|
+
description: 'Thumbnail size (e.g., 100x100, 0x300)',
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
];
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recordFields = exports.recordOperations = void 0;
|
|
4
|
+
exports.recordOperations = [
|
|
5
|
+
{
|
|
6
|
+
displayName: 'Operation',
|
|
7
|
+
name: 'operation',
|
|
8
|
+
type: 'options',
|
|
9
|
+
noDataExpression: true,
|
|
10
|
+
displayOptions: {
|
|
11
|
+
show: {
|
|
12
|
+
resource: ['record'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
options: [
|
|
16
|
+
{
|
|
17
|
+
name: 'Create',
|
|
18
|
+
value: 'create',
|
|
19
|
+
description: 'Create a new record',
|
|
20
|
+
action: 'Create a record',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'Delete',
|
|
24
|
+
value: 'delete',
|
|
25
|
+
description: 'Delete a record',
|
|
26
|
+
action: 'Delete a record',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'Get',
|
|
30
|
+
value: 'get',
|
|
31
|
+
description: 'Get a record by ID',
|
|
32
|
+
action: 'Get a record',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Get Many',
|
|
36
|
+
value: 'getMany',
|
|
37
|
+
description: 'Get many records',
|
|
38
|
+
action: 'Get many records',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'Update',
|
|
42
|
+
value: 'update',
|
|
43
|
+
description: 'Update a record',
|
|
44
|
+
action: 'Update a record',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
default: 'getMany',
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
exports.recordFields = [
|
|
51
|
+
{
|
|
52
|
+
displayName: 'Collection Name',
|
|
53
|
+
name: 'collection',
|
|
54
|
+
type: 'string',
|
|
55
|
+
required: true,
|
|
56
|
+
default: '',
|
|
57
|
+
placeholder: 'notes',
|
|
58
|
+
description: 'Name of the collection to operate on',
|
|
59
|
+
displayOptions: {
|
|
60
|
+
show: {
|
|
61
|
+
resource: ['record'],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
displayName: 'Record ID',
|
|
67
|
+
name: 'recordId',
|
|
68
|
+
type: 'string',
|
|
69
|
+
required: true,
|
|
70
|
+
default: '',
|
|
71
|
+
placeholder: 'abc123xyz',
|
|
72
|
+
description: 'ID of the record',
|
|
73
|
+
displayOptions: {
|
|
74
|
+
show: {
|
|
75
|
+
resource: ['record'],
|
|
76
|
+
operation: ['get', 'update', 'delete'],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
displayName: 'Fields',
|
|
82
|
+
name: 'fields',
|
|
83
|
+
type: 'fixedCollection',
|
|
84
|
+
typeOptions: {
|
|
85
|
+
multipleValues: true,
|
|
86
|
+
},
|
|
87
|
+
default: {},
|
|
88
|
+
placeholder: 'Add Field',
|
|
89
|
+
description: 'Fields to set on the record',
|
|
90
|
+
displayOptions: {
|
|
91
|
+
show: {
|
|
92
|
+
resource: ['record'],
|
|
93
|
+
operation: ['create', 'update'],
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
options: [
|
|
97
|
+
{
|
|
98
|
+
name: 'field',
|
|
99
|
+
displayName: 'Field',
|
|
100
|
+
values: [
|
|
101
|
+
{
|
|
102
|
+
displayName: 'Field Name',
|
|
103
|
+
name: 'name',
|
|
104
|
+
type: 'string',
|
|
105
|
+
default: '',
|
|
106
|
+
placeholder: 'title',
|
|
107
|
+
description: 'Name of the field',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
displayName: 'Field Value',
|
|
111
|
+
name: 'value',
|
|
112
|
+
type: 'string',
|
|
113
|
+
default: '',
|
|
114
|
+
placeholder: 'My Title',
|
|
115
|
+
description: 'Value of the field',
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
displayName: 'Return All',
|
|
123
|
+
name: 'returnAll',
|
|
124
|
+
type: 'boolean',
|
|
125
|
+
default: false,
|
|
126
|
+
description: 'Whether to return all results or only up to a given limit',
|
|
127
|
+
displayOptions: {
|
|
128
|
+
show: {
|
|
129
|
+
resource: ['record'],
|
|
130
|
+
operation: ['getMany'],
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
displayName: 'Limit',
|
|
136
|
+
name: 'limit',
|
|
137
|
+
type: 'number',
|
|
138
|
+
default: 50,
|
|
139
|
+
typeOptions: {
|
|
140
|
+
minValue: 1,
|
|
141
|
+
maxValue: 500,
|
|
142
|
+
},
|
|
143
|
+
description: 'Max number of results to return',
|
|
144
|
+
displayOptions: {
|
|
145
|
+
show: {
|
|
146
|
+
resource: ['record'],
|
|
147
|
+
operation: ['getMany'],
|
|
148
|
+
returnAll: [false],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
displayName: 'Options',
|
|
154
|
+
name: 'options',
|
|
155
|
+
type: 'collection',
|
|
156
|
+
placeholder: 'Add Option',
|
|
157
|
+
default: {},
|
|
158
|
+
displayOptions: {
|
|
159
|
+
show: {
|
|
160
|
+
resource: ['record'],
|
|
161
|
+
operation: ['getMany'],
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
options: [
|
|
165
|
+
{
|
|
166
|
+
displayName: 'Filter',
|
|
167
|
+
name: 'filter',
|
|
168
|
+
type: 'string',
|
|
169
|
+
default: '',
|
|
170
|
+
placeholder: "status = 'active' && created > '2024-01-01'",
|
|
171
|
+
description: 'Filter expression to apply',
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
displayName: 'Sort',
|
|
175
|
+
name: 'sort',
|
|
176
|
+
type: 'string',
|
|
177
|
+
default: '',
|
|
178
|
+
placeholder: '-created,title',
|
|
179
|
+
description: 'Sort order (use - for descending)',
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
displayName: 'Expand',
|
|
183
|
+
name: 'expand',
|
|
184
|
+
type: 'string',
|
|
185
|
+
default: '',
|
|
186
|
+
placeholder: 'author,tags',
|
|
187
|
+
description: 'Comma-separated list of relations to expand',
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
displayName: 'Fields',
|
|
191
|
+
name: 'fields',
|
|
192
|
+
type: 'string',
|
|
193
|
+
default: '',
|
|
194
|
+
placeholder: 'id,title,created',
|
|
195
|
+
description: 'Comma-separated list of fields to return',
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
displayName: 'Options',
|
|
201
|
+
name: 'options',
|
|
202
|
+
type: 'collection',
|
|
203
|
+
placeholder: 'Add Option',
|
|
204
|
+
default: {},
|
|
205
|
+
displayOptions: {
|
|
206
|
+
show: {
|
|
207
|
+
resource: ['record'],
|
|
208
|
+
operation: ['get', 'create', 'update'],
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
options: [
|
|
212
|
+
{
|
|
213
|
+
displayName: 'Expand',
|
|
214
|
+
name: 'expand',
|
|
215
|
+
type: 'string',
|
|
216
|
+
default: '',
|
|
217
|
+
placeholder: 'author,tags',
|
|
218
|
+
description: 'Comma-separated list of relations to expand',
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
},
|
|
222
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-pb",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "n8n community node for PocketBase - Open Source backend with realtime database, authentication, and file storage",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n",
|
|
8
|
+
"pocketbase",
|
|
9
|
+
"database",
|
|
10
|
+
"backend",
|
|
11
|
+
"api"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"homepage": "https://github.com/DuanPeng1314/n8n-nodes-pocketbase",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "DuanPeng1314"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/DuanPeng1314/n8n-nodes-pocketbase.git"
|
|
21
|
+
},
|
|
22
|
+
"main": "dist/index.js",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc && gulp build:icons",
|
|
25
|
+
"dev": "tsc --watch",
|
|
26
|
+
"lint": "eslint . --ext .ts",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"n8n": {
|
|
33
|
+
"n8nNodesApiVersion": 1,
|
|
34
|
+
"credentials": [
|
|
35
|
+
"dist/credentials/PocketBaseApi.credentials.js"
|
|
36
|
+
],
|
|
37
|
+
"nodes": [
|
|
38
|
+
"dist/nodes/PocketBase/PocketBase.node.js"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^20.10.0",
|
|
43
|
+
"gulp": "^4.0.2",
|
|
44
|
+
"n8n-workflow": "^1.0.0",
|
|
45
|
+
"typescript": "^5.3.0"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"pocketbase": "^0.25.0"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"n8n-workflow": "*"
|
|
52
|
+
}
|
|
53
|
+
}
|