n8n-nodes-substack-new 0.0.1
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/LICENSE.md +19 -0
- package/README.md +139 -0
- package/dist/credentials/SubstackGatewayApi.credentials.d.ts +9 -0
- package/dist/credentials/SubstackGatewayApi.credentials.js +61 -0
- package/dist/credentials/SubstackGatewayApi.credentials.js.map +1 -0
- package/dist/nodes/SubstackGateway/Comment.fields.d.ts +2 -0
- package/dist/nodes/SubstackGateway/Comment.fields.js +36 -0
- package/dist/nodes/SubstackGateway/Comment.fields.js.map +1 -0
- package/dist/nodes/SubstackGateway/Comment.operations.d.ts +8 -0
- package/dist/nodes/SubstackGateway/Comment.operations.js +44 -0
- package/dist/nodes/SubstackGateway/Comment.operations.js.map +1 -0
- package/dist/nodes/SubstackGateway/Note.fields.d.ts +2 -0
- package/dist/nodes/SubstackGateway/Note.fields.js +150 -0
- package/dist/nodes/SubstackGateway/Note.fields.js.map +1 -0
- package/dist/nodes/SubstackGateway/Note.operations.d.ts +11 -0
- package/dist/nodes/SubstackGateway/Note.operations.js +109 -0
- package/dist/nodes/SubstackGateway/Note.operations.js.map +1 -0
- package/dist/nodes/SubstackGateway/Post.fields.d.ts +2 -0
- package/dist/nodes/SubstackGateway/Post.fields.js +66 -0
- package/dist/nodes/SubstackGateway/Post.fields.js.map +1 -0
- package/dist/nodes/SubstackGateway/Post.operations.d.ts +10 -0
- package/dist/nodes/SubstackGateway/Post.operations.js +74 -0
- package/dist/nodes/SubstackGateway/Post.operations.js.map +1 -0
- package/dist/nodes/SubstackGateway/Profile.fields.d.ts +2 -0
- package/dist/nodes/SubstackGateway/Profile.fields.js +61 -0
- package/dist/nodes/SubstackGateway/Profile.fields.js.map +1 -0
- package/dist/nodes/SubstackGateway/Profile.operations.d.ts +10 -0
- package/dist/nodes/SubstackGateway/Profile.operations.js +72 -0
- package/dist/nodes/SubstackGateway/Profile.operations.js.map +1 -0
- package/dist/nodes/SubstackGateway/Substack.node.d.ts +11 -0
- package/dist/nodes/SubstackGateway/Substack.node.js +148 -0
- package/dist/nodes/SubstackGateway/Substack.node.js.map +1 -0
- package/dist/nodes/SubstackGateway/Substack.node.json +22 -0
- package/dist/nodes/SubstackGateway/SubstackUtils.d.ts +12 -0
- package/dist/nodes/SubstackGateway/SubstackUtils.js +59 -0
- package/dist/nodes/SubstackGateway/SubstackUtils.js.map +1 -0
- package/dist/nodes/SubstackGateway/shared/DataFormatters.d.ts +9 -0
- package/dist/nodes/SubstackGateway/shared/DataFormatters.js +73 -0
- package/dist/nodes/SubstackGateway/shared/DataFormatters.js.map +1 -0
- package/dist/nodes/SubstackGateway/shared/OperationHandler.d.ts +11 -0
- package/dist/nodes/SubstackGateway/shared/OperationHandler.js +44 -0
- package/dist/nodes/SubstackGateway/shared/OperationHandler.js.map +1 -0
- package/dist/nodes/SubstackGateway/shared/OperationUtils.d.ts +5 -0
- package/dist/nodes/SubstackGateway/shared/OperationUtils.js +35 -0
- package/dist/nodes/SubstackGateway/shared/OperationUtils.js.map +1 -0
- package/dist/nodes/SubstackGateway/shared/SubstackGatewayClient.d.ts +69 -0
- package/dist/nodes/SubstackGateway/shared/SubstackGatewayClient.js +222 -0
- package/dist/nodes/SubstackGateway/shared/SubstackGatewayClient.js.map +1 -0
- package/dist/nodes/SubstackGateway/substack.svg +7 -0
- package/dist/nodes/SubstackGateway/types.d.ts +51 -0
- package/dist/nodes/SubstackGateway/types.js +3 -0
- package/dist/nodes/SubstackGateway/types.js.map +1 -0
- package/dist/package.json +67 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataFormatters = void 0;
|
|
4
|
+
const SubstackUtils_1 = require("../SubstackUtils");
|
|
5
|
+
class DataFormatters {
|
|
6
|
+
static formatNote(note, publicationAddress) {
|
|
7
|
+
var _a, _b, _c;
|
|
8
|
+
return {
|
|
9
|
+
noteId: ((_a = note.id) === null || _a === void 0 ? void 0 : _a.toString()) || 'unknown',
|
|
10
|
+
body: note.body || '',
|
|
11
|
+
url: SubstackUtils_1.SubstackUtils.formatUrl(publicationAddress, `/p/${note.id || 'unknown'}`),
|
|
12
|
+
date: DataFormatters.formatDate(note.publishedAt || new Date()),
|
|
13
|
+
status: 'published',
|
|
14
|
+
userId: ((_c = (_b = note.author) === null || _b === void 0 ? void 0 : _b.id) === null || _c === void 0 ? void 0 : _c.toString()) || 'unknown',
|
|
15
|
+
likes: note.likesCount || 0,
|
|
16
|
+
type: 'note',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
static formatPost(post, publicationAddress) {
|
|
20
|
+
return {
|
|
21
|
+
id: post.id,
|
|
22
|
+
title: post.title || '',
|
|
23
|
+
subtitle: post.subtitle || '',
|
|
24
|
+
slug: post.slug,
|
|
25
|
+
url: post.url || SubstackUtils_1.SubstackUtils.formatUrl(publicationAddress, `/p/${post.slug || post.id}`),
|
|
26
|
+
postDate: DataFormatters.formatDate(post.publishedAt || new Date()),
|
|
27
|
+
description: post.truncatedBody || post.body || '',
|
|
28
|
+
htmlBody: post.htmlBody || '',
|
|
29
|
+
markdown: post.markdown || '',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
static formatComment(comment, parentPostId) {
|
|
33
|
+
return {
|
|
34
|
+
id: comment.id,
|
|
35
|
+
body: comment.body,
|
|
36
|
+
isAdmin: comment.isAdmin || false,
|
|
37
|
+
parentPostId: parentPostId || 0,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
static formatProfile(profile) {
|
|
41
|
+
return {
|
|
42
|
+
id: profile.id,
|
|
43
|
+
name: profile.name,
|
|
44
|
+
handle: profile.handle || profile.slug,
|
|
45
|
+
bio: profile.bio,
|
|
46
|
+
url: profile.url,
|
|
47
|
+
avatarUrl: profile.avatarUrl,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
static formatFollowing(followee, returnType) {
|
|
51
|
+
if (returnType === 'ids') {
|
|
52
|
+
return {
|
|
53
|
+
id: followee.id,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
id: followee.id,
|
|
58
|
+
name: followee.name,
|
|
59
|
+
handle: followee.handle || followee.slug,
|
|
60
|
+
bio: followee.bio,
|
|
61
|
+
url: followee.url,
|
|
62
|
+
avatarUrl: followee.avatarUrl,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
static formatDate(date) {
|
|
66
|
+
if (date && !isNaN(new Date(date).getTime())) {
|
|
67
|
+
return new Date(date).toISOString();
|
|
68
|
+
}
|
|
69
|
+
return new Date().toISOString();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.DataFormatters = DataFormatters;
|
|
73
|
+
//# sourceMappingURL=DataFormatters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataFormatters.js","sourceRoot":"","sources":["../../../../nodes/SubstackGateway/shared/DataFormatters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IExecuteFunctions } from 'n8n-workflow';
|
|
2
|
+
import { SubstackClient } from './SubstackGatewayClient';
|
|
3
|
+
import { IStandardResponse } from '../types';
|
|
4
|
+
export type OperationExecutor<T> = () => Promise<T>;
|
|
5
|
+
export declare class OperationHandler {
|
|
6
|
+
static execute<T>(executeFunctions: IExecuteFunctions, itemIndex: number, executor: OperationExecutor<T>): Promise<IStandardResponse>;
|
|
7
|
+
static success<T>(data: T): IStandardResponse;
|
|
8
|
+
static getLimit(executeFunctions: IExecuteFunctions, itemIndex: number): number;
|
|
9
|
+
static resolveProfile(client: SubstackClient, slug?: string): Promise<any>;
|
|
10
|
+
static collectFromIterable<T, R>(iterable: AsyncIterable<T>, limit: number, formatter: (item: T) => R): Promise<R[]>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OperationHandler = void 0;
|
|
4
|
+
const SubstackUtils_1 = require("../SubstackUtils");
|
|
5
|
+
const OperationUtils_1 = require("./OperationUtils");
|
|
6
|
+
class OperationHandler {
|
|
7
|
+
static async execute(executeFunctions, itemIndex, executor) {
|
|
8
|
+
try {
|
|
9
|
+
const data = await executor();
|
|
10
|
+
return this.success(data);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
return SubstackUtils_1.SubstackUtils.formatErrorResponse({
|
|
14
|
+
message: error.message,
|
|
15
|
+
node: executeFunctions.getNode(),
|
|
16
|
+
itemIndex,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
static success(data) {
|
|
21
|
+
return {
|
|
22
|
+
success: true,
|
|
23
|
+
data,
|
|
24
|
+
metadata: {
|
|
25
|
+
status: 'success',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
static getLimit(executeFunctions, itemIndex) {
|
|
30
|
+
const limitParam = executeFunctions.getNodeParameter('limit', itemIndex, '');
|
|
31
|
+
return OperationUtils_1.OperationUtils.parseLimit(limitParam);
|
|
32
|
+
}
|
|
33
|
+
static async resolveProfile(client, slug) {
|
|
34
|
+
if (slug) {
|
|
35
|
+
return client.profileForSlug(slug);
|
|
36
|
+
}
|
|
37
|
+
return client.ownProfile();
|
|
38
|
+
}
|
|
39
|
+
static async collectFromIterable(iterable, limit, formatter) {
|
|
40
|
+
return OperationUtils_1.OperationUtils.executeAsyncIterable(iterable, limit, formatter);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.OperationHandler = OperationHandler;
|
|
44
|
+
//# sourceMappingURL=OperationHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OperationHandler.js","sourceRoot":"","sources":["../../../../nodes/SubstackGateway/shared/OperationHandler.ts"],"names":[],"mappings":";;;AAEA,oDAAiD;AAEjD,qDAAkD;AAIlD,MAAa,gBAAgB;IAC5B,MAAM,CAAC,KAAK,CAAC,OAAO,CACnB,gBAAmC,EACnC,SAAiB,EACjB,QAA8B;QAE9B,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,6BAAa,CAAC,mBAAmB,CAAC;gBACxC,OAAO,EAAG,KAAe,CAAC,OAAO;gBACjC,IAAI,EAAE,gBAAgB,CAAC,OAAO,EAAE;gBAChC,SAAS;aACT,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED,MAAM,CAAC,OAAO,CAAI,IAAO;QACxB,OAAO;YACN,OAAO,EAAE,IAAI;YACb,IAAI;YACJ,QAAQ,EAAE;gBACT,MAAM,EAAE,SAAS;aACjB;SACD,CAAC;IACH,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,gBAAmC,EAAE,SAAiB;QACrE,MAAM,UAAU,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAC7E,OAAO,+BAAc,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,cAAc,CAC1B,MAAsB,EACtB,IAAa;QAEb,IAAI,IAAI,EAAE,CAAC;YACV,OAAO,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;IAC5B,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAC/B,QAA0B,EAC1B,KAAa,EACb,SAAyB;QAEzB,OAAO,+BAAc,CAAC,oBAAoB,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACxE,CAAC;CACD;AAlDD,4CAkDC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare class OperationUtils {
|
|
2
|
+
static executeAsyncIterable<T, R>(iterable: AsyncIterable<T>, limit: number, formatter: (item: T, ...args: any[]) => R, ...formatterArgs: any[]): Promise<R[]>;
|
|
3
|
+
static parseLimit(limitParam: any): number;
|
|
4
|
+
static parseNumericParam(param: any, paramName: string): number;
|
|
5
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OperationUtils = void 0;
|
|
4
|
+
class OperationUtils {
|
|
5
|
+
static async executeAsyncIterable(iterable, limit, formatter, ...formatterArgs) {
|
|
6
|
+
const results = [];
|
|
7
|
+
let count = 0;
|
|
8
|
+
for await (const item of iterable) {
|
|
9
|
+
if (count >= limit)
|
|
10
|
+
break;
|
|
11
|
+
try {
|
|
12
|
+
results.push(formatter(item, ...formatterArgs));
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
}
|
|
16
|
+
count++;
|
|
17
|
+
}
|
|
18
|
+
return results;
|
|
19
|
+
}
|
|
20
|
+
static parseLimit(limitParam) {
|
|
21
|
+
if (limitParam !== '' && limitParam !== null && limitParam !== undefined) {
|
|
22
|
+
return Number(limitParam);
|
|
23
|
+
}
|
|
24
|
+
return 100;
|
|
25
|
+
}
|
|
26
|
+
static parseNumericParam(param, paramName) {
|
|
27
|
+
const numericValue = typeof param === 'string' ? parseInt(param, 10) : param;
|
|
28
|
+
if (!numericValue || isNaN(numericValue)) {
|
|
29
|
+
throw new Error(`Invalid ${paramName}: must be a valid number`);
|
|
30
|
+
}
|
|
31
|
+
return numericValue;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.OperationUtils = OperationUtils;
|
|
35
|
+
//# sourceMappingURL=OperationUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OperationUtils.js","sourceRoot":"","sources":["../../../../nodes/SubstackGateway/shared/OperationUtils.ts"],"names":[],"mappings":";;;AAAA,MAAa,cAAc;IAI1B,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAChC,QAA0B,EAC1B,KAAa,EACb,SAAyC,EACzC,GAAG,aAAoB;QAEvB,MAAM,OAAO,GAAQ,EAAE,CAAC;QACxB,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YACnC,IAAI,KAAK,IAAI,KAAK;gBAAE,MAAM;YAE1B,IAAI,CAAC;gBACJ,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC;YACjD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;YAEjB,CAAC;YACD,KAAK,EAAE,CAAC;QACT,CAAC;QAED,OAAO,OAAO,CAAC;IAChB,CAAC;IAKD,MAAM,CAAC,UAAU,CAAC,UAAe;QAChC,IAAI,UAAU,KAAK,EAAE,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC1E,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,GAAG,CAAC;IACZ,CAAC;IAKD,MAAM,CAAC,iBAAiB,CAAC,KAAU,EAAE,SAAiB;QACrD,MAAM,YAAY,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAE7E,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,0BAA0B,CAAC,CAAC;QACjE,CAAC;QAED,OAAO,YAAY,CAAC;IACrB,CAAC;CACD;AAjDD,wCAiDC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface SubstackClientConfig {
|
|
2
|
+
publicationUrl: string;
|
|
3
|
+
token: string;
|
|
4
|
+
gatewayUrl?: string;
|
|
5
|
+
perPage?: number;
|
|
6
|
+
maxRequestsPerSecond?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface SubstackProfileSummary {
|
|
9
|
+
id: number;
|
|
10
|
+
name: string;
|
|
11
|
+
handle: string;
|
|
12
|
+
slug: string;
|
|
13
|
+
url: string;
|
|
14
|
+
bio?: string;
|
|
15
|
+
avatarUrl?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface SubstackProfile extends SubstackProfileSummary {
|
|
18
|
+
posts(): AsyncIterable<SubstackPostSummary>;
|
|
19
|
+
notes(): AsyncIterable<SubstackNote>;
|
|
20
|
+
}
|
|
21
|
+
export interface SubstackOwnProfile extends SubstackProfile {
|
|
22
|
+
following(): AsyncIterable<SubstackProfileSummary>;
|
|
23
|
+
publishNote(content: string, options?: {
|
|
24
|
+
attachment?: string;
|
|
25
|
+
}): Promise<SubstackPublishNoteResponse>;
|
|
26
|
+
}
|
|
27
|
+
export interface SubstackPostSummary {
|
|
28
|
+
id: number;
|
|
29
|
+
title: string;
|
|
30
|
+
subtitle: string;
|
|
31
|
+
slug?: string;
|
|
32
|
+
url?: string;
|
|
33
|
+
truncatedBody: string;
|
|
34
|
+
htmlBody: string;
|
|
35
|
+
markdown: string;
|
|
36
|
+
publishedAt: string;
|
|
37
|
+
}
|
|
38
|
+
export interface SubstackPost extends SubstackPostSummary {
|
|
39
|
+
comments(): AsyncIterable<SubstackComment>;
|
|
40
|
+
}
|
|
41
|
+
export interface SubstackNote {
|
|
42
|
+
id: number;
|
|
43
|
+
body: string;
|
|
44
|
+
likesCount: number;
|
|
45
|
+
publishedAt: string;
|
|
46
|
+
author: {
|
|
47
|
+
id: number;
|
|
48
|
+
name: string;
|
|
49
|
+
handle: string;
|
|
50
|
+
avatarUrl?: string;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export interface SubstackComment {
|
|
54
|
+
id: number;
|
|
55
|
+
body: string;
|
|
56
|
+
isAdmin: boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface SubstackPublishNoteResponse {
|
|
59
|
+
id: number;
|
|
60
|
+
}
|
|
61
|
+
export declare class SubstackClient {
|
|
62
|
+
private readonly httpClient;
|
|
63
|
+
private readonly perPage;
|
|
64
|
+
constructor(config: SubstackClientConfig);
|
|
65
|
+
ownProfile(): Promise<SubstackOwnProfile>;
|
|
66
|
+
profileForSlug(slug: string): Promise<SubstackProfile>;
|
|
67
|
+
postForId(id: number): Promise<SubstackPost>;
|
|
68
|
+
noteForId(id: number): Promise<SubstackNote>;
|
|
69
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
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.SubstackClient = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const axios_rate_limit_1 = __importDefault(require("axios-rate-limit"));
|
|
9
|
+
class GatewayHttpClient {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
var _a, _b;
|
|
12
|
+
const gatewayBase = ((_a = config.gatewayUrl) !== null && _a !== void 0 ? _a : 'https://substack-gateway.vercel.app').replace(/\/$/, '');
|
|
13
|
+
const baseUrl = `${gatewayBase}/api/v1`;
|
|
14
|
+
const maxRequestsPerSecond = (_b = config.maxRequestsPerSecond) !== null && _b !== void 0 ? _b : 25;
|
|
15
|
+
const axiosClient = axios_1.default.create({
|
|
16
|
+
baseURL: baseUrl,
|
|
17
|
+
headers: {
|
|
18
|
+
Authorization: `Bearer ${config.token}`,
|
|
19
|
+
'x-publication-url': config.publicationUrl,
|
|
20
|
+
Accept: 'application/json',
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
this.client = (0, axios_rate_limit_1.default)(axiosClient, {
|
|
25
|
+
maxRequests: maxRequestsPerSecond,
|
|
26
|
+
perMilliseconds: 1000,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async get(path, params) {
|
|
30
|
+
const response = await this.client.get(path, { params });
|
|
31
|
+
return response.data;
|
|
32
|
+
}
|
|
33
|
+
async post(path, payload) {
|
|
34
|
+
const response = await this.client.post(path, payload);
|
|
35
|
+
return response.data;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
class GatewayProfileContext {
|
|
39
|
+
constructor(httpClient, perPage, rawData) {
|
|
40
|
+
this.httpClient = httpClient;
|
|
41
|
+
this.perPage = perPage;
|
|
42
|
+
this.id = rawData.id;
|
|
43
|
+
this.name = rawData.name;
|
|
44
|
+
this.handle = rawData.handle;
|
|
45
|
+
this.slug = rawData.handle;
|
|
46
|
+
this.url = rawData.url;
|
|
47
|
+
this.bio = rawData.bio;
|
|
48
|
+
this.avatarUrl = rawData.avatar_url;
|
|
49
|
+
}
|
|
50
|
+
async *posts() {
|
|
51
|
+
var _a, _b, _c, _d, _e;
|
|
52
|
+
let offset = 0;
|
|
53
|
+
while (true) {
|
|
54
|
+
const response = await this.httpClient.get(`/profiles/${encodeURIComponent(this.slug)}/posts`, { limit: this.perPage, offset });
|
|
55
|
+
const items = (_a = response.items) !== null && _a !== void 0 ? _a : [];
|
|
56
|
+
if (items.length === 0)
|
|
57
|
+
break;
|
|
58
|
+
for (const item of items) {
|
|
59
|
+
yield {
|
|
60
|
+
id: item.id,
|
|
61
|
+
title: item.title,
|
|
62
|
+
subtitle: (_b = item.subtitle) !== null && _b !== void 0 ? _b : '',
|
|
63
|
+
slug: item.slug,
|
|
64
|
+
url: item.url,
|
|
65
|
+
truncatedBody: (_c = item.truncated_body) !== null && _c !== void 0 ? _c : '',
|
|
66
|
+
htmlBody: (_d = item.html_body) !== null && _d !== void 0 ? _d : '',
|
|
67
|
+
markdown: (_e = item.markdown) !== null && _e !== void 0 ? _e : '',
|
|
68
|
+
publishedAt: item.published_at,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (items.length < this.perPage)
|
|
72
|
+
break;
|
|
73
|
+
offset += this.perPage;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async *notes() {
|
|
77
|
+
var _a, _b, _c, _d, _e, _f;
|
|
78
|
+
let cursor = undefined;
|
|
79
|
+
while (true) {
|
|
80
|
+
const response = await this.httpClient.get(`/profiles/${encodeURIComponent(this.slug)}/notes`, { cursor });
|
|
81
|
+
const items = (_a = response.items) !== null && _a !== void 0 ? _a : [];
|
|
82
|
+
for (const item of items) {
|
|
83
|
+
yield {
|
|
84
|
+
id: item.id,
|
|
85
|
+
body: item.body,
|
|
86
|
+
likesCount: (_b = item.likes_count) !== null && _b !== void 0 ? _b : 0,
|
|
87
|
+
publishedAt: item.published_at,
|
|
88
|
+
author: {
|
|
89
|
+
id: (_c = item.author) === null || _c === void 0 ? void 0 : _c.id,
|
|
90
|
+
name: (_d = item.author) === null || _d === void 0 ? void 0 : _d.name,
|
|
91
|
+
handle: (_e = item.author) === null || _e === void 0 ? void 0 : _e.handle,
|
|
92
|
+
avatarUrl: (_f = item.author) === null || _f === void 0 ? void 0 : _f.avatar_url,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (!response.next_cursor)
|
|
97
|
+
break;
|
|
98
|
+
cursor = response.next_cursor;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
class GatewayOwnProfileContext extends GatewayProfileContext {
|
|
103
|
+
async *notes() {
|
|
104
|
+
var _a, _b, _c, _d, _e, _f;
|
|
105
|
+
let cursor = undefined;
|
|
106
|
+
while (true) {
|
|
107
|
+
const response = await this.httpClient.get('/me/notes', { cursor });
|
|
108
|
+
const items = (_a = response.items) !== null && _a !== void 0 ? _a : [];
|
|
109
|
+
for (const item of items) {
|
|
110
|
+
yield {
|
|
111
|
+
id: item.id,
|
|
112
|
+
body: item.body,
|
|
113
|
+
likesCount: (_b = item.likes_count) !== null && _b !== void 0 ? _b : 0,
|
|
114
|
+
publishedAt: item.published_at,
|
|
115
|
+
author: {
|
|
116
|
+
id: (_c = item.author) === null || _c === void 0 ? void 0 : _c.id,
|
|
117
|
+
name: (_d = item.author) === null || _d === void 0 ? void 0 : _d.name,
|
|
118
|
+
handle: (_e = item.author) === null || _e === void 0 ? void 0 : _e.handle,
|
|
119
|
+
avatarUrl: (_f = item.author) === null || _f === void 0 ? void 0 : _f.avatar_url,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (!response.next_cursor)
|
|
124
|
+
break;
|
|
125
|
+
cursor = response.next_cursor;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async *following() {
|
|
129
|
+
var _a;
|
|
130
|
+
const following = await this.httpClient.get('/me/following');
|
|
131
|
+
for (const user of (_a = following.items) !== null && _a !== void 0 ? _a : []) {
|
|
132
|
+
try {
|
|
133
|
+
const profile = await this.httpClient.get(`/profiles/${encodeURIComponent(user.handle)}`);
|
|
134
|
+
yield {
|
|
135
|
+
id: profile.id,
|
|
136
|
+
name: profile.name,
|
|
137
|
+
handle: profile.handle,
|
|
138
|
+
slug: profile.handle,
|
|
139
|
+
url: profile.url,
|
|
140
|
+
bio: profile.bio,
|
|
141
|
+
avatarUrl: profile.avatar_url,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async publishNote(content, options) {
|
|
149
|
+
const payload = { content };
|
|
150
|
+
if (options === null || options === void 0 ? void 0 : options.attachment) {
|
|
151
|
+
payload.attachment = options.attachment;
|
|
152
|
+
}
|
|
153
|
+
const response = await this.httpClient.post('/notes', payload);
|
|
154
|
+
return { id: response.id };
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
class GatewayPostContext {
|
|
158
|
+
constructor(httpClient, rawData) {
|
|
159
|
+
var _a, _b, _c, _d;
|
|
160
|
+
this.httpClient = httpClient;
|
|
161
|
+
this.id = rawData.id;
|
|
162
|
+
this.title = rawData.title;
|
|
163
|
+
this.subtitle = (_a = rawData.subtitle) !== null && _a !== void 0 ? _a : '';
|
|
164
|
+
this.slug = rawData.slug;
|
|
165
|
+
this.url = rawData.url;
|
|
166
|
+
this.truncatedBody = (_b = rawData.truncated_body) !== null && _b !== void 0 ? _b : '';
|
|
167
|
+
this.htmlBody = (_c = rawData.html_body) !== null && _c !== void 0 ? _c : '';
|
|
168
|
+
this.markdown = (_d = rawData.markdown) !== null && _d !== void 0 ? _d : '';
|
|
169
|
+
this.publishedAt = rawData.published_at;
|
|
170
|
+
}
|
|
171
|
+
async *comments() {
|
|
172
|
+
var _a, _b;
|
|
173
|
+
const response = await this.httpClient.get(`/posts/${this.id}/comments`);
|
|
174
|
+
for (const item of (_a = response.items) !== null && _a !== void 0 ? _a : []) {
|
|
175
|
+
yield {
|
|
176
|
+
id: item.id,
|
|
177
|
+
body: item.body,
|
|
178
|
+
isAdmin: (_b = item.is_admin) !== null && _b !== void 0 ? _b : false,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
class SubstackClient {
|
|
184
|
+
constructor(config) {
|
|
185
|
+
var _a;
|
|
186
|
+
this.httpClient = new GatewayHttpClient(config);
|
|
187
|
+
this.perPage = (_a = config.perPage) !== null && _a !== void 0 ? _a : 25;
|
|
188
|
+
}
|
|
189
|
+
async ownProfile() {
|
|
190
|
+
const profile = await this.httpClient.get('/me');
|
|
191
|
+
return new GatewayOwnProfileContext(this.httpClient, this.perPage, profile);
|
|
192
|
+
}
|
|
193
|
+
async profileForSlug(slug) {
|
|
194
|
+
if (!slug || slug.trim() === '') {
|
|
195
|
+
throw new Error('Profile slug cannot be empty');
|
|
196
|
+
}
|
|
197
|
+
const profile = await this.httpClient.get(`/profiles/${encodeURIComponent(slug)}`);
|
|
198
|
+
return new GatewayProfileContext(this.httpClient, this.perPage, profile);
|
|
199
|
+
}
|
|
200
|
+
async postForId(id) {
|
|
201
|
+
const post = await this.httpClient.get(`/posts/${id}`);
|
|
202
|
+
return new GatewayPostContext(this.httpClient, post);
|
|
203
|
+
}
|
|
204
|
+
async noteForId(id) {
|
|
205
|
+
var _a, _b, _c, _d, _e;
|
|
206
|
+
const note = await this.httpClient.get(`/notes/${id}`);
|
|
207
|
+
return {
|
|
208
|
+
id: note.id,
|
|
209
|
+
body: note.body,
|
|
210
|
+
likesCount: (_a = note.likes_count) !== null && _a !== void 0 ? _a : 0,
|
|
211
|
+
publishedAt: note.published_at,
|
|
212
|
+
author: {
|
|
213
|
+
id: (_b = note.author) === null || _b === void 0 ? void 0 : _b.id,
|
|
214
|
+
name: (_c = note.author) === null || _c === void 0 ? void 0 : _c.name,
|
|
215
|
+
handle: (_d = note.author) === null || _d === void 0 ? void 0 : _d.handle,
|
|
216
|
+
avatarUrl: (_e = note.author) === null || _e === void 0 ? void 0 : _e.avatar_url,
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
exports.SubstackClient = SubstackClient;
|
|
222
|
+
//# sourceMappingURL=SubstackGatewayClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubstackGatewayClient.js","sourceRoot":"","sources":["../../../../nodes/SubstackGateway/shared/SubstackGatewayClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
3
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100" height="100">
|
|
4
|
+
<rect width="512" height="128" fill="#FF6719"/>
|
|
5
|
+
<rect y="192" width="512" height="128" fill="#FF6719"/>
|
|
6
|
+
<polygon points="0,384 512,384 256,512" fill="#FF6719"/>
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { INode } from 'n8n-workflow';
|
|
2
|
+
export interface IStandardResponse {
|
|
3
|
+
success: boolean;
|
|
4
|
+
data: any;
|
|
5
|
+
error?: string;
|
|
6
|
+
metadata?: {
|
|
7
|
+
url?: string;
|
|
8
|
+
date?: string;
|
|
9
|
+
status?: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface ISubstackNote {
|
|
13
|
+
noteId: string;
|
|
14
|
+
body: string;
|
|
15
|
+
url: string;
|
|
16
|
+
date: string;
|
|
17
|
+
status: string;
|
|
18
|
+
userId: string;
|
|
19
|
+
likes?: number;
|
|
20
|
+
type?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ISubstackPost {
|
|
23
|
+
id: number;
|
|
24
|
+
title: string;
|
|
25
|
+
subtitle?: string;
|
|
26
|
+
slug?: string;
|
|
27
|
+
url: string;
|
|
28
|
+
postDate: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
htmlBody?: string;
|
|
31
|
+
markdown?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface ISubstackComment {
|
|
34
|
+
id: number;
|
|
35
|
+
body: string;
|
|
36
|
+
isAdmin?: boolean;
|
|
37
|
+
parentPostId: number;
|
|
38
|
+
}
|
|
39
|
+
export interface ISubstackFollowing {
|
|
40
|
+
id: number;
|
|
41
|
+
name?: string;
|
|
42
|
+
handle?: string;
|
|
43
|
+
bio?: string;
|
|
44
|
+
url?: string;
|
|
45
|
+
avatarUrl?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface IErrorResponse {
|
|
48
|
+
message: string;
|
|
49
|
+
node: INode;
|
|
50
|
+
itemIndex: number;
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../nodes/SubstackGateway/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-substack-new",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "n8n community node for Substack API integration",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package"
|
|
7
|
+
],
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"homepage": "",
|
|
10
|
+
"author": {
|
|
11
|
+
"name": "Jakub Slys",
|
|
12
|
+
"email": "jakub@slys.dev"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/jakub-k-slys/n8n-nodes-substack-new.git"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20.15"
|
|
20
|
+
},
|
|
21
|
+
"main": "dist/index.js",
|
|
22
|
+
"types": "dist/index.d.ts",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\" && tsc && gulp build:icons",
|
|
25
|
+
"dev": "tsc --watch",
|
|
26
|
+
"format": "prettier nodes credentials --write",
|
|
27
|
+
"lint": "eslint nodes credentials package.json",
|
|
28
|
+
"lintfix": "eslint nodes credentials package.json --fix",
|
|
29
|
+
"prepublishOnly": "pnpm run build && eslint -c eslint.prepublish.config.js nodes credentials package.json",
|
|
30
|
+
"test": "jest",
|
|
31
|
+
"test:watch": "jest --watch",
|
|
32
|
+
"test:unit": "jest",
|
|
33
|
+
"test:unit:watch": "jest --watch"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"n8n": {
|
|
39
|
+
"n8nNodesApiVersion": 1,
|
|
40
|
+
"credentials": [
|
|
41
|
+
"dist/credentials/SubstackGatewayApi.credentials.js"
|
|
42
|
+
],
|
|
43
|
+
"nodes": [
|
|
44
|
+
"dist/nodes/SubstackGateway/Substack.node.js"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/jest": "^30.0.0",
|
|
49
|
+
"@typescript-eslint/parser": "~8.57.2",
|
|
50
|
+
"eslint": ">=9.29.0 <10",
|
|
51
|
+
"eslint-plugin-n8n-nodes-base": "^1.16.3",
|
|
52
|
+
"gulp": "^5.0.0",
|
|
53
|
+
"jest": "^30.0.3",
|
|
54
|
+
"prettier": "^3.5.3",
|
|
55
|
+
"ts-jest": "^29.2.5",
|
|
56
|
+
"typescript": "^5.8.2"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"n8n-workflow": "2.13.1"
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"axios": "^1.13.2",
|
|
63
|
+
"axios-rate-limit": "^1.4.0",
|
|
64
|
+
"fp-ts": "^2.16.10",
|
|
65
|
+
"io-ts": "^2.2.22"
|
|
66
|
+
}
|
|
67
|
+
}
|