n8n-nodes-trooptrack 0.1.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 +148 -0
- package/dist/credentials/TroopTrackApi.credentials.d.ts +9 -0
- package/dist/credentials/TroopTrackApi.credentials.d.ts.map +1 -0
- package/dist/credentials/TroopTrackApi.credentials.js +47 -0
- package/dist/credentials/TroopTrackApi.credentials.js.map +1 -0
- package/dist/credentials/trooptrack.png +0 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/nodes/TroopTrack/GenericFunctions.d.ts +4 -0
- package/dist/nodes/TroopTrack/GenericFunctions.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/GenericFunctions.js +167 -0
- package/dist/nodes/TroopTrack/GenericFunctions.js.map +1 -0
- package/dist/nodes/TroopTrack/TroopTrack.node.d.ts +11 -0
- package/dist/nodes/TroopTrack/TroopTrack.node.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/TroopTrack.node.js +448 -0
- package/dist/nodes/TroopTrack/TroopTrack.node.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Achievements.description.d.ts +4 -0
- package/dist/nodes/TroopTrack/descriptions/Achievements.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Achievements.description.js +64 -0
- package/dist/nodes/TroopTrack/descriptions/Achievements.description.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/AwardTypes.description.d.ts +4 -0
- package/dist/nodes/TroopTrack/descriptions/AwardTypes.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/AwardTypes.description.js +36 -0
- package/dist/nodes/TroopTrack/descriptions/AwardTypes.description.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Events.description.d.ts +4 -0
- package/dist/nodes/TroopTrack/descriptions/Events.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Events.description.js +59 -0
- package/dist/nodes/TroopTrack/descriptions/Events.description.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Generic.description.d.ts +4 -0
- package/dist/nodes/TroopTrack/descriptions/Generic.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Generic.description.js +56 -0
- package/dist/nodes/TroopTrack/descriptions/Generic.description.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/MailingLists.description.d.ts +4 -0
- package/dist/nodes/TroopTrack/descriptions/MailingLists.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/MailingLists.description.js +22 -0
- package/dist/nodes/TroopTrack/descriptions/MailingLists.description.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Patrols.description.d.ts +3 -0
- package/dist/nodes/TroopTrack/descriptions/Patrols.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Patrols.description.js +28 -0
- package/dist/nodes/TroopTrack/descriptions/Patrols.description.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/PhotoAlbums.description.d.ts +4 -0
- package/dist/nodes/TroopTrack/descriptions/PhotoAlbums.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/PhotoAlbums.description.js +36 -0
- package/dist/nodes/TroopTrack/descriptions/PhotoAlbums.description.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Tokens.description.d.ts +3 -0
- package/dist/nodes/TroopTrack/descriptions/Tokens.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Tokens.description.js +18 -0
- package/dist/nodes/TroopTrack/descriptions/Tokens.description.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/UserAchievements.description.d.ts +4 -0
- package/dist/nodes/TroopTrack/descriptions/UserAchievements.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/UserAchievements.description.js +42 -0
- package/dist/nodes/TroopTrack/descriptions/UserAchievements.description.js.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Users.description.d.ts +4 -0
- package/dist/nodes/TroopTrack/descriptions/Users.description.d.ts.map +1 -0
- package/dist/nodes/TroopTrack/descriptions/Users.description.js +38 -0
- package/dist/nodes/TroopTrack/descriptions/Users.description.js.map +1 -0
- package/dist/nodes/TroopTrack/trooptrack.png +0 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# n8n-nodes-trooptrack
|
|
2
|
+
|
|
3
|
+
An **unofficial n8n community node** for interacting with the TroopTrack
|
|
4
|
+
API.
|
|
5
|
+
|
|
6
|
+
This package provides read-only (GET) access to key TroopTrack resources
|
|
7
|
+
to enable reporting, automation, and data integration workflows inside
|
|
8
|
+
n8n.
|
|
9
|
+
|
|
10
|
+
Important\
|
|
11
|
+
This is **not an official TroopTrack product** and is **not affiliated
|
|
12
|
+
with TroopTrack in any way**.\
|
|
13
|
+
Use at your own risk.
|
|
14
|
+
|
|
15
|
+
------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
## Current Version
|
|
18
|
+
|
|
19
|
+
**v1.0.0**
|
|
20
|
+
|
|
21
|
+
This initial release is intentionally focused and stable.
|
|
22
|
+
|
|
23
|
+
### What v1.0 Supports
|
|
24
|
+
|
|
25
|
+
- GET / Read-only operations
|
|
26
|
+
- Structured resources for use in n8n workflows
|
|
27
|
+
- Clean output shaping for downstream nodes
|
|
28
|
+
|
|
29
|
+
### What v1.0 Does Not Support
|
|
30
|
+
|
|
31
|
+
- Create, Update, or Delete operations (POST, PUT, PATCH)
|
|
32
|
+
- Automation of UI-only TroopTrack features
|
|
33
|
+
- Headless browser automation
|
|
34
|
+
|
|
35
|
+
These capabilities are planned for future versions.
|
|
36
|
+
|
|
37
|
+
## Supported Resources
|
|
38
|
+
|
|
39
|
+
The node exposes the following resources:
|
|
40
|
+
|
|
41
|
+
- Events
|
|
42
|
+
- Event Types
|
|
43
|
+
- Patrols (derived from Event Types parameters)
|
|
44
|
+
- Users [Includes **Get Many (Simple)** for lightweight user listings]
|
|
45
|
+
- Other read-only endpoints as defined in v1
|
|
46
|
+
|
|
47
|
+
Each resource is available through standard n8n **Resource / Operation** selectors.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
Install via npm (recommended):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install n8n-nodes-trooptrack
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or inside a self-hosted n8n environment:
|
|
58
|
+
|
|
59
|
+
1. Navigate to your n8n user directory (usually \~/.n8n)
|
|
60
|
+
2. Run: npm install n8n-nodes-trooptrack
|
|
61
|
+
3. Restart n8n
|
|
62
|
+
|
|
63
|
+
## Configuration
|
|
64
|
+
|
|
65
|
+
You will need your TroopTrack API credentials.
|
|
66
|
+
|
|
67
|
+
1. In n8n, open **Credentials**
|
|
68
|
+
2. Create a new credential using the TroopTrack API type
|
|
69
|
+
3. Enter your API key and base URL
|
|
70
|
+
|
|
71
|
+
Once configured, the **TroopTrack** node will appear in the node list.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
## Example Use Cases
|
|
75
|
+
|
|
76
|
+
- Generate troop dashboards and reports
|
|
77
|
+
- Sync users, patrols, and events into other systems
|
|
78
|
+
- Power Google Sheets, Airtable, or databases with TroopTrack data
|
|
79
|
+
- Drive notifications and workflows based on TroopTrack activity
|
|
80
|
+
|
|
81
|
+
## Roadmap
|
|
82
|
+
|
|
83
|
+
This project is intentionally iterative.
|
|
84
|
+
|
|
85
|
+
### Planned Enhancements
|
|
86
|
+
|
|
87
|
+
**v1.x**
|
|
88
|
+
- Expanded GET coverage for additional endpoints
|
|
89
|
+
- Field filtering and optional parameters where supported
|
|
90
|
+
|
|
91
|
+
**v2.0**
|
|
92
|
+
- Write support
|
|
93
|
+
- POST, PUT, and PATCH operations
|
|
94
|
+
- Create and update entities directly from n8n
|
|
95
|
+
|
|
96
|
+
**Advanced Automation Layer**
|
|
97
|
+
- Puppeteer-based automation for TroopTrack features not exposed via API
|
|
98
|
+
- Headless UI actions for workflows such as:
|
|
99
|
+
- Admin-only operations
|
|
100
|
+
- Batch updates
|
|
101
|
+
- Workflow steps not supported natively by TroopTrack
|
|
102
|
+
|
|
103
|
+
------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
## Unofficial Project Disclaimer
|
|
106
|
+
|
|
107
|
+
This project is: - Not endorsed by TroopTrack - Not supported by
|
|
108
|
+
TroopTrack - Not affiliated with TroopTrack in any capacity
|
|
109
|
+
|
|
110
|
+
All trademarks and service marks belong to their respective owners.
|
|
111
|
+
|
|
112
|
+
If TroopTrack changes or deprecates API behavior, this node may require
|
|
113
|
+
updates.
|
|
114
|
+
|
|
115
|
+
------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
## Contributing
|
|
118
|
+
|
|
119
|
+
Contributions are welcome.
|
|
120
|
+
|
|
121
|
+
If you are adding:
|
|
122
|
+
- New GET endpoints
|
|
123
|
+
- Additional resource support
|
|
124
|
+
- Output improvements
|
|
125
|
+
- Bug fixes
|
|
126
|
+
|
|
127
|
+
Please open a pull request with:
|
|
128
|
+
- A clear description of the change
|
|
129
|
+
- Testing notes
|
|
130
|
+
- Any relevant API documentation
|
|
131
|
+
|
|
132
|
+
------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT License
|
|
137
|
+
|
|
138
|
+
You are free to use, modify, and distribute this package in accordance
|
|
139
|
+
with the license terms.
|
|
140
|
+
|
|
141
|
+
------------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
## Maintainer
|
|
144
|
+
|
|
145
|
+
This node is independently developed and maintained as a community
|
|
146
|
+
contribution for n8n users.
|
|
147
|
+
|
|
148
|
+
If you rely on it in production, pin your version and monitor releases.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ICredentialType, INodeProperties, Icon } from 'n8n-workflow';
|
|
2
|
+
export declare class TroopTrackApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
icon: Icon;
|
|
6
|
+
documentationUrl: string;
|
|
7
|
+
properties: INodeProperties[];
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=TroopTrackApi.credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TroopTrackApi.credentials.d.ts","sourceRoot":"","sources":["../../credentials/TroopTrackApi.credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAE3E,qBAAa,aAAc,YAAW,eAAe;IACpD,IAAI,SAAmB;IACvB,WAAW,SAAoB;IAC/B,IAAI,EAAE,IAAI,CAAiE;IAE3E,gBAAgB,SAA4B;IAE5C,UAAU,EAAE,eAAe,EAAE,CAiC3B;CACF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TroopTrackApi = void 0;
|
|
4
|
+
class TroopTrackApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'troopTrackApi';
|
|
7
|
+
this.displayName = 'TroopTrack API';
|
|
8
|
+
this.icon = { light: 'file:trooptrack.png', dark: 'file:trooptrack.png' };
|
|
9
|
+
this.documentationUrl = 'https://trooptrack.com';
|
|
10
|
+
this.properties = [
|
|
11
|
+
{
|
|
12
|
+
displayName: 'TroopTrack Subdomain',
|
|
13
|
+
name: 'subdomain',
|
|
14
|
+
type: 'string',
|
|
15
|
+
default: '',
|
|
16
|
+
required: true,
|
|
17
|
+
description: 'Only the subdomain part. Example: troop457zelie',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
displayName: 'Username',
|
|
21
|
+
name: 'username',
|
|
22
|
+
type: 'string',
|
|
23
|
+
default: '',
|
|
24
|
+
required: true,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
displayName: 'Password',
|
|
28
|
+
name: 'password',
|
|
29
|
+
type: 'string',
|
|
30
|
+
typeOptions: { password: true },
|
|
31
|
+
default: '',
|
|
32
|
+
required: true,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
displayName: 'Partner Token',
|
|
36
|
+
name: 'partnerToken',
|
|
37
|
+
type: 'string',
|
|
38
|
+
typeOptions: { password: true },
|
|
39
|
+
default: '',
|
|
40
|
+
required: true,
|
|
41
|
+
description: 'TroopTrack developer program API token',
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.TroopTrackApi = TroopTrackApi;
|
|
47
|
+
//# sourceMappingURL=TroopTrackApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TroopTrackApi.credentials.js","sourceRoot":"","sources":["../../credentials/TroopTrackApi.credentials.ts"],"names":[],"mappings":";;;AAEA,MAAa,aAAa;IAA1B;QACC,SAAI,GAAG,eAAe,CAAC;QACvB,gBAAW,GAAG,gBAAgB,CAAC;QAC/B,SAAI,GAAS,EAAE,KAAK,EAAE,qBAAqB,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC;QAE3E,qBAAgB,GAAG,wBAAwB,CAAC;QAE5C,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,sBAAsB;gBACnC,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,iDAAiD;aAC9D;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;aACd;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;aACd;YACD;gBACC,WAAW,EAAE,eAAe;gBAC5B,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,wCAAwC;aACrD;SACD,CAAC;IACH,CAAC;CAAA;AAzCD,sCAyCC"}
|
|
Binary file
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAC;AACnD,cAAc,yCAAyC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./nodes/TroopTrack/TroopTrack.node"), exports);
|
|
18
|
+
__exportStar(require("./credentials/TroopTrackApi.credentials"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qEAAmD;AACnD,0EAAwD"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IExecuteFunctions, IHookFunctions, ILoadOptionsFunctions } from 'n8n-workflow';
|
|
2
|
+
import type { IHttpRequestMethods } from 'n8n-workflow';
|
|
3
|
+
export declare function troopTrackRequest(ctx: IExecuteFunctions | IHookFunctions | ILoadOptionsFunctions, method: IHttpRequestMethods, endpoint: string, qs?: Record<string, any>, body?: any): Promise<any>;
|
|
4
|
+
//# sourceMappingURL=GenericFunctions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenericFunctions.d.ts","sourceRoot":"","sources":["../../../nodes/TroopTrack/GenericFunctions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAuB,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAwL7E,wBAAsB,iBAAiB,CACtC,GAAG,EAAE,iBAAiB,GAAG,cAAc,GAAG,qBAAqB,EAC/D,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,MAAM,EAChB,EAAE,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EAC5B,IAAI,GAAE,GAAe,GACnB,OAAO,CAAC,GAAG,CAAC,CAsCd"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.troopTrackRequest = troopTrackRequest;
|
|
4
|
+
const TOKEN_CACHE_TTL_MS = 1000 * 60 * 30; // 30 minutes
|
|
5
|
+
const tokenCache = {};
|
|
6
|
+
function assertNonEmpty(value, label) {
|
|
7
|
+
if (!value || !value.trim()) {
|
|
8
|
+
throw new Error(`${label} is required`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function normalizeSubdomain(subdomain) {
|
|
12
|
+
return subdomain.trim().toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
function getBaseUrl(subdomain) {
|
|
15
|
+
const clean = normalizeSubdomain(subdomain);
|
|
16
|
+
return `https://${clean}.trooptrack.com/api`;
|
|
17
|
+
}
|
|
18
|
+
function safeStringify(value, maxLen = 800) {
|
|
19
|
+
try {
|
|
20
|
+
const seen = new WeakSet();
|
|
21
|
+
const json = JSON.stringify(value, (_key, val) => {
|
|
22
|
+
if (typeof val === 'object' && val !== null) {
|
|
23
|
+
if (seen.has(val))
|
|
24
|
+
return '[Circular]';
|
|
25
|
+
seen.add(val);
|
|
26
|
+
}
|
|
27
|
+
if (typeof val === 'bigint')
|
|
28
|
+
return val.toString();
|
|
29
|
+
return val;
|
|
30
|
+
}, 0);
|
|
31
|
+
return json.length > maxLen ? json.slice(0, maxLen) : json;
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
// Last resort
|
|
35
|
+
const msg = e?.message ? String(e.message) : 'unknown stringify error';
|
|
36
|
+
const str = String(value);
|
|
37
|
+
return `${str.slice(0, maxLen)} (safeStringify fallback: ${msg})`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function getCreds(ctx) {
|
|
41
|
+
const creds = (await ctx.getCredentials('troopTrackApi'));
|
|
42
|
+
assertNonEmpty(creds?.subdomain, 'TroopTrack subdomain');
|
|
43
|
+
assertNonEmpty(creds?.username, 'TroopTrack username');
|
|
44
|
+
assertNonEmpty(creds?.password, 'TroopTrack password');
|
|
45
|
+
assertNonEmpty(creds?.partnerToken, 'TroopTrack partner token');
|
|
46
|
+
const sub = normalizeSubdomain(creds.subdomain);
|
|
47
|
+
// Enforce subdomain-only input
|
|
48
|
+
if (sub.includes('http://') ||
|
|
49
|
+
sub.includes('https://') ||
|
|
50
|
+
sub.includes('.') ||
|
|
51
|
+
sub.includes('/') ||
|
|
52
|
+
sub.includes(':') ||
|
|
53
|
+
sub.includes(' ')) {
|
|
54
|
+
throw new Error('TroopTrack subdomain must be only the subdomain value (example: "troop457zelie"), not a full URL or host.');
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
subdomain: sub,
|
|
58
|
+
username: creds.username,
|
|
59
|
+
password: creds.password,
|
|
60
|
+
partnerToken: creds.partnerToken,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function makeTokenCacheKey(creds) {
|
|
64
|
+
return `${normalizeSubdomain(creds.subdomain)}::${creds.username.trim().toLowerCase()}`;
|
|
65
|
+
}
|
|
66
|
+
async function fetchUserToken(ctx, creds) {
|
|
67
|
+
const options = {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
url: `${getBaseUrl(creds.subdomain)}/v1/tokens`,
|
|
70
|
+
headers: {
|
|
71
|
+
'X-Partner-Token': creds.partnerToken,
|
|
72
|
+
'X-Username': creds.username,
|
|
73
|
+
'X-User-Password': creds.password,
|
|
74
|
+
Accept: 'application/json',
|
|
75
|
+
},
|
|
76
|
+
json: true,
|
|
77
|
+
};
|
|
78
|
+
const resp = await ctx.helpers.httpRequest(options);
|
|
79
|
+
let token;
|
|
80
|
+
if (Array.isArray(resp)) {
|
|
81
|
+
token = resp?.[0]?.token;
|
|
82
|
+
}
|
|
83
|
+
else if (resp && typeof resp === 'object') {
|
|
84
|
+
if (Array.isArray(resp.users))
|
|
85
|
+
token = resp.users?.[0]?.token;
|
|
86
|
+
if (!token && Array.isArray(resp.user))
|
|
87
|
+
token = resp.user?.[0]?.token;
|
|
88
|
+
if (!token && resp.token)
|
|
89
|
+
token = resp.token;
|
|
90
|
+
}
|
|
91
|
+
if (!token) {
|
|
92
|
+
const preview = typeof resp === 'string' ? resp.slice(0, 800) : safeStringify(resp, 800);
|
|
93
|
+
throw new Error(`TroopTrack token response did not include a token. Response type: ${typeof resp}. Preview: ${preview}`);
|
|
94
|
+
}
|
|
95
|
+
return token;
|
|
96
|
+
}
|
|
97
|
+
async function getValidUserToken(ctx, creds, forceRefresh = false) {
|
|
98
|
+
const key = makeTokenCacheKey(creds);
|
|
99
|
+
const cached = tokenCache[key];
|
|
100
|
+
if (!forceRefresh && cached?.token) {
|
|
101
|
+
const age = Date.now() - cached.fetchedAtMs;
|
|
102
|
+
if (age < TOKEN_CACHE_TTL_MS)
|
|
103
|
+
return cached.token;
|
|
104
|
+
}
|
|
105
|
+
const token = await fetchUserToken(ctx, creds);
|
|
106
|
+
tokenCache[key] = { token, fetchedAtMs: Date.now() };
|
|
107
|
+
return token;
|
|
108
|
+
}
|
|
109
|
+
function isUnauthorized(err) {
|
|
110
|
+
const code = err?.statusCode ?? err?.response?.status ?? err?.cause?.statusCode;
|
|
111
|
+
return code === 401;
|
|
112
|
+
}
|
|
113
|
+
function formatHttpError(err, method, endpoint) {
|
|
114
|
+
const status = err?.statusCode ??
|
|
115
|
+
err?.response?.status ??
|
|
116
|
+
err?.cause?.statusCode ??
|
|
117
|
+
err?.response?.statusCode;
|
|
118
|
+
// Prefer API response payloads when present, but never try to stringify the whole error object.
|
|
119
|
+
const body = err?.response?.data ??
|
|
120
|
+
err?.response?.body ??
|
|
121
|
+
err?.error ??
|
|
122
|
+
err?.message;
|
|
123
|
+
let preview;
|
|
124
|
+
if (typeof body === 'string') {
|
|
125
|
+
preview = body.slice(0, 800);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
preview = safeStringify(body ?? {}, 800);
|
|
129
|
+
}
|
|
130
|
+
return new Error(`TroopTrack API error${status ? ` ${status}` : ''} for ${method} ${endpoint}. Response: ${preview}`);
|
|
131
|
+
}
|
|
132
|
+
async function troopTrackRequest(ctx, method, endpoint, qs = {}, body = undefined) {
|
|
133
|
+
const creds = await getCreds(ctx);
|
|
134
|
+
const doRequest = async (userToken) => {
|
|
135
|
+
const options = {
|
|
136
|
+
method,
|
|
137
|
+
url: `${getBaseUrl(creds.subdomain)}${endpoint}`,
|
|
138
|
+
qs,
|
|
139
|
+
headers: {
|
|
140
|
+
'X-Partner-Token': creds.partnerToken,
|
|
141
|
+
'X-User-Token': userToken,
|
|
142
|
+
Accept: 'application/json',
|
|
143
|
+
},
|
|
144
|
+
json: true,
|
|
145
|
+
};
|
|
146
|
+
if (body !== undefined)
|
|
147
|
+
options.body = body;
|
|
148
|
+
return ctx.helpers.httpRequest(options);
|
|
149
|
+
};
|
|
150
|
+
const token = await getValidUserToken(ctx, creds, false);
|
|
151
|
+
try {
|
|
152
|
+
return await doRequest(token);
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
if (!isUnauthorized(err)) {
|
|
156
|
+
throw formatHttpError(err, method, endpoint);
|
|
157
|
+
}
|
|
158
|
+
const refreshedToken = await getValidUserToken(ctx, creds, true);
|
|
159
|
+
try {
|
|
160
|
+
return await doRequest(refreshedToken);
|
|
161
|
+
}
|
|
162
|
+
catch (err2) {
|
|
163
|
+
throw formatHttpError(err2, method, endpoint);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=GenericFunctions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenericFunctions.js","sourceRoot":"","sources":["../../../nodes/TroopTrack/GenericFunctions.ts"],"names":[],"mappings":";;AA8LA,8CA4CC;AAlOD,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,aAAa;AAcxD,MAAM,UAAU,GAAoC,EAAE,CAAC;AAEvD,SAAS,cAAc,CAAC,KAAa,EAAE,KAAa;IACnD,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,cAAc,CAAC,CAAC;IACzC,CAAC;AACF,CAAC;AAED,SAAS,kBAAkB,CAAC,SAAiB;IAC5C,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACvC,CAAC;AAED,SAAS,UAAU,CAAC,SAAiB;IACpC,MAAM,KAAK,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC5C,OAAO,WAAW,KAAK,qBAAqB,CAAC;AAC9C,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,MAAM,GAAG,GAAG;IAClD,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,IAAI,OAAO,EAAU,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAC1B,KAAK,EACL,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YACb,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBAC7C,IAAI,IAAI,CAAC,GAAG,CAAC,GAAa,CAAC;oBAAE,OAAO,YAAY,CAAC;gBACjD,IAAI,CAAC,GAAG,CAAC,GAAa,CAAC,CAAC;YACzB,CAAC;YACD,IAAI,OAAO,GAAG,KAAK,QAAQ;gBAAE,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;YACnD,OAAO,GAAG,CAAC;QACZ,CAAC,EACD,CAAC,CACD,CAAC;QAEF,OAAO,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5D,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QACjB,cAAc;QACd,MAAM,GAAG,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC;QACvE,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1B,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,6BAA6B,GAAG,GAAG,CAAC;IACnE,CAAC;AACF,CAAC;AAED,KAAK,UAAU,QAAQ,CACtB,GAA+D;IAE/D,MAAM,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,cAAc,CAAC,eAAe,CAAC,CAAqC,CAAC;IAE9F,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,sBAAsB,CAAC,CAAC;IACzD,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IACvD,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IACvD,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,0BAA0B,CAAC,CAAC;IAEhE,MAAM,GAAG,GAAG,kBAAkB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAEhD,+BAA+B;IAC/B,IACC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;QACvB,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;QACxB,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QACjB,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QACjB,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QACjB,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAChB,CAAC;QACF,MAAM,IAAI,KAAK,CACd,2GAA2G,CAC3G,CAAC;IACH,CAAC;IAED,OAAO;QACN,SAAS,EAAE,GAAG;QACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,YAAY,EAAE,KAAK,CAAC,YAAY;KAChC,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,KAA4B;IACtD,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;AACzF,CAAC;AAED,KAAK,UAAU,cAAc,CAC5B,GAA+D,EAC/D,KAA4B;IAE5B,MAAM,OAAO,GAAwB;QACpC,MAAM,EAAE,MAAM;QACd,GAAG,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,YAAY;QAC/C,OAAO,EAAE;YACR,iBAAiB,EAAE,KAAK,CAAC,YAAY;YACrC,YAAY,EAAE,KAAK,CAAC,QAAQ;YAC5B,iBAAiB,EAAE,KAAK,CAAC,QAAQ;YACjC,MAAM,EAAE,kBAAkB;SAC1B;QACD,IAAI,EAAE,IAAI;KACV,CAAC;IAEF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAEpD,IAAI,KAAyB,CAAC;IAE9B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,KAAK,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;IAC1B,CAAC;SAAM,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7C,IAAI,KAAK,CAAC,OAAO,CAAE,IAAY,CAAC,KAAK,CAAC;YAAE,KAAK,GAAI,IAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;QAChF,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAE,IAAY,CAAC,IAAI,CAAC;YAAE,KAAK,GAAI,IAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;QACxF,IAAI,CAAC,KAAK,IAAK,IAAY,CAAC,KAAK;YAAE,KAAK,GAAI,IAAY,CAAC,KAAK,CAAC;IAChE,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,OAAO,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACzF,MAAM,IAAI,KAAK,CACd,qEAAqE,OAAO,IAAI,cAAc,OAAO,EAAE,CACvG,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC/B,GAA+D,EAC/D,KAA4B,EAC5B,YAAY,GAAG,KAAK;IAEpB,MAAM,GAAG,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAE/B,IAAI,CAAC,YAAY,IAAI,MAAM,EAAE,KAAK,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC;QAC5C,IAAI,GAAG,GAAG,kBAAkB;YAAE,OAAO,MAAM,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC/C,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACrD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,GAAQ;IAC/B,MAAM,IAAI,GAAG,GAAG,EAAE,UAAU,IAAI,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC;IAChF,OAAO,IAAI,KAAK,GAAG,CAAC;AACrB,CAAC;AAED,SAAS,eAAe,CAAC,GAAQ,EAAE,MAAc,EAAE,QAAgB;IAClE,MAAM,MAAM,GACX,GAAG,EAAE,UAAU;QACf,GAAG,EAAE,QAAQ,EAAE,MAAM;QACrB,GAAG,EAAE,KAAK,EAAE,UAAU;QACtB,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC;IAE3B,gGAAgG;IAChG,MAAM,IAAI,GACT,GAAG,EAAE,QAAQ,EAAE,IAAI;QACnB,GAAG,EAAE,QAAQ,EAAE,IAAI;QACnB,GAAG,EAAE,KAAK;QACV,GAAG,EAAE,OAAO,CAAC;IAEd,IAAI,OAAe,CAAC;IAEpB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9B,CAAC;SAAM,CAAC;QACP,OAAO,GAAG,aAAa,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,IAAI,KAAK,CACf,uBAAuB,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,MAAM,IAAI,QAAQ,eAAe,OAAO,EAAE,CACnG,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,iBAAiB,CACtC,GAA+D,EAC/D,MAA2B,EAC3B,QAAgB,EAChB,KAA0B,EAAE,EAC5B,OAAY,SAAS;IAErB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;IAElC,MAAM,SAAS,GAAG,KAAK,EAAE,SAAiB,EAAE,EAAE;QAC7C,MAAM,OAAO,GAAwB;YACpC,MAAM;YACN,GAAG,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,QAAQ,EAAE;YAChD,EAAE;YACF,OAAO,EAAE;gBACR,iBAAiB,EAAE,KAAK,CAAC,YAAY;gBACrC,cAAc,EAAE,SAAS;gBACzB,MAAM,EAAE,kBAAkB;aAC1B;YACD,IAAI,EAAE,IAAI;SACV,CAAC;QAEF,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;QAE5C,OAAO,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAEzD,IAAI,CAAC;QACJ,OAAO,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QACnB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAEjE,IAAI,CAAC;YACJ,OAAO,MAAM,SAAS,CAAC,cAAc,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,IAAS,EAAE,CAAC;YACpB,MAAM,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC/C,CAAC;IACF,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class TroopTrack implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
methods: {
|
|
5
|
+
loadOptions: {
|
|
6
|
+
getAwardTypes(this: import("n8n-workflow").ILoadOptionsFunctions): Promise<any>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=TroopTrack.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TroopTrack.node.d.ts","sourceRoot":"","sources":["../../../nodes/TroopTrack/TroopTrack.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,iBAAiB,EACjB,kBAAkB,EAClB,SAAS,EACT,oBAAoB,EAEpB,MAAM,cAAc,CAAC;AAgBtB,qBAAa,UAAW,YAAW,SAAS;IAC3C,WAAW,EAAE,oBAAoB,CA0D/B;IAEF,OAAO;;gCAEqB,OAAO,cAAc,EAAE,qBAAqB;;MAgBtE;IAGI,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CA0YvE"}
|