n8n-nodes-lemonsqueezy 0.7.2 → 0.8.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 CHANGED
@@ -55,8 +55,9 @@ The main node for interacting with the Lemon Squeezy API.
55
55
  |----------|------------|
56
56
  | **Checkout** | Create, Get, Get Many |
57
57
  | **Customer** | Create, Update, Delete, Get, Get Many |
58
- | **Discount** | Create, Delete, Get, Get Many |
58
+ | **Discount** | Create, Update, Delete, Get, Get Many |
59
59
  | **Discount Redemption** | Get, Get Many |
60
+ | **File** | Get, Get Many |
60
61
  | **License Key** | Get, Get Many, Update, Validate, Activate, Deactivate |
61
62
  | **License Key Instance** | Get, Get Many |
62
63
  | **Order** | Get, Get Many, Refund |
@@ -303,6 +304,19 @@ Contributions are welcome! Please feel free to submit a Pull Request.
303
304
 
304
305
  ## Changelog
305
306
 
307
+ ### v0.8.0
308
+
309
+ **New Features:**
310
+ - Added **File resource** for accessing product files (digital downloads)
311
+ - Added **Discount Update operation** for modifying existing discount codes
312
+ - Added discount amount validation (0-100 for percent, positive integer for fixed)
313
+ - Webhook URLs now require HTTPS (Lemon Squeezy requirement)
314
+
315
+ **Improvements:**
316
+ - Enhanced field descriptions with examples and placeholders
317
+ - Added API limit hints (max 100 per page) to limit fields
318
+ - 178 tests with comprehensive coverage
319
+
306
320
  ### v0.7.2
307
321
 
308
322
  **n8n Community Package Compliance:**
@@ -22,6 +22,8 @@ async function handleCreate(ctx, resource, itemIndex) {
22
22
  const amount = ctx.getNodeParameter('discountAmount', itemIndex);
23
23
  const amountType = ctx.getNodeParameter('discountAmountType', itemIndex);
24
24
  const additionalOptions = ctx.getNodeParameter('additionalOptions', itemIndex, {});
25
+ // Validate discount amount based on type
26
+ (0, helpers_1.validateDiscountAmount)(amount, amountType);
25
27
  const attributes = {
26
28
  name,
27
29
  code,
@@ -169,8 +171,8 @@ async function handleCreate(ctx, resource, itemIndex) {
169
171
  const events = ctx.getNodeParameter('webhookEvents', itemIndex);
170
172
  const secret = ctx.getNodeParameter('webhookSecret', itemIndex);
171
173
  const additionalOptions = ctx.getNodeParameter('additionalOptions', itemIndex, {});
172
- // Validate URL before API call
173
- (0, helpers_1.validateField)('url', url, 'url');
174
+ // Validate URL before API call - Lemon Squeezy requires HTTPS for webhooks
175
+ (0, helpers_1.validateField)('url', url, 'httpsUrl');
174
176
  // Validate webhook secret minimum length for security (32+ chars recommended)
175
177
  if (secret.length < 32) {
176
178
  throw new Error('Webhook secret must be at least 32 characters for security. Generate one using: openssl rand -hex 32');
@@ -263,8 +265,8 @@ async function handleUpdate(ctx, resource, itemIndex) {
263
265
  const updateFields = ctx.getNodeParameter('updateFields', itemIndex);
264
266
  const attributes = {};
265
267
  if (updateFields.url) {
266
- // Validate URL before API call
267
- (0, helpers_1.validateField)('url', updateFields.url, 'url');
268
+ // Validate URL before API call - Lemon Squeezy requires HTTPS for webhooks
269
+ (0, helpers_1.validateField)('url', updateFields.url, 'httpsUrl');
268
270
  attributes.url = updateFields.url;
269
271
  }
270
272
  if (updateFields.events) {
@@ -280,6 +282,44 @@ async function handleUpdate(ctx, resource, itemIndex) {
280
282
  const body = (0, helpers_1.buildJsonApiBody)('webhooks', attributes, undefined, webhookId);
281
283
  return await helpers_1.lemonSqueezyApiRequest.call(ctx, 'PATCH', `/webhooks/${webhookId}`, body);
282
284
  }
285
+ if (resource === 'discount') {
286
+ const discountId = ctx.getNodeParameter('discountId', itemIndex);
287
+ const updateFields = ctx.getNodeParameter('updateFields', itemIndex);
288
+ const attributes = {};
289
+ if (updateFields.name) {
290
+ attributes.name = updateFields.name;
291
+ }
292
+ if (updateFields.code) {
293
+ attributes.code = updateFields.code;
294
+ }
295
+ if (updateFields.amount !== undefined) {
296
+ // Validate discount amount if both amount and type are being updated
297
+ const amountType = updateFields.amountType || 'percent';
298
+ (0, helpers_1.validateDiscountAmount)(updateFields.amount, amountType);
299
+ attributes.amount = updateFields.amount;
300
+ }
301
+ if (updateFields.amountType) {
302
+ attributes.amount_type = updateFields.amountType;
303
+ }
304
+ if (updateFields.duration) {
305
+ attributes.duration = updateFields.duration;
306
+ }
307
+ if (updateFields.durationInMonths !== undefined) {
308
+ attributes.duration_in_months = updateFields.durationInMonths;
309
+ }
310
+ if (updateFields.maxRedemptions !== undefined) {
311
+ attributes.max_redemptions = updateFields.maxRedemptions;
312
+ attributes.is_limited_redemptions = updateFields.maxRedemptions > 0;
313
+ }
314
+ if (updateFields.startsAt) {
315
+ attributes.starts_at = updateFields.startsAt;
316
+ }
317
+ if (updateFields.expiresAt) {
318
+ attributes.expires_at = updateFields.expiresAt;
319
+ }
320
+ const body = (0, helpers_1.buildJsonApiBody)('discounts', attributes, undefined, discountId);
321
+ return await helpers_1.lemonSqueezyApiRequest.call(ctx, 'PATCH', `/discounts/${discountId}`, body);
322
+ }
283
323
  throw new Error(`Update operation not supported for resource: ${resource}`);
284
324
  }
285
325
  class LemonSqueezy {
@@ -31,6 +31,7 @@ exports.RESOURCE_ENDPOINTS = {
31
31
  webhook: 'webhooks',
32
32
  usageRecord: 'usage-records',
33
33
  user: 'users',
34
+ file: 'files',
34
35
  };
35
36
  /**
36
37
  * Resource to ID parameter mapping
@@ -51,6 +52,7 @@ exports.RESOURCE_ID_PARAMS = {
51
52
  checkout: 'checkoutId',
52
53
  webhook: 'webhookId',
53
54
  usageRecord: 'usageRecordId',
55
+ file: 'fileId',
54
56
  };
55
57
  /**
56
58
  * Webhook event types with descriptions
@@ -41,6 +41,7 @@ export declare function isValidEmail(email: string): boolean;
41
41
  * This prevents Server-Side Request Forgery (SSRF) attacks.
42
42
  *
43
43
  * @param url - The URL to validate
44
+ * @param requireHttps - If true, only HTTPS URLs are allowed (default: false)
44
45
  * @returns True if the URL is valid and safe, false otherwise
45
46
  *
46
47
  * @example
@@ -48,8 +49,9 @@ export declare function isValidEmail(email: string): boolean;
48
49
  * isValidUrl('http://localhost:3000') // false (internal)
49
50
  * isValidUrl('ftp://files.example.com') // false (non-http protocol)
50
51
  * isValidUrl('http://169.254.169.254') // false (AWS metadata)
52
+ * isValidUrl('http://example.com', true) // false (HTTPS required)
51
53
  */
52
- export declare function isValidUrl(url: string): boolean;
54
+ export declare function isValidUrl(url: string, requireHttps?: boolean): boolean;
53
55
  /**
54
56
  * Validates ISO 8601 date format.
55
57
  *
@@ -88,6 +90,7 @@ export declare function isPositiveInteger(value: unknown): boolean;
88
90
  * - 'required': Ensures value is not empty/null/undefined
89
91
  * - 'email': RFC 5322 compliant email validation
90
92
  * - 'url': Safe URL validation with SSRF protection
93
+ * - 'httpsUrl': Safe URL validation requiring HTTPS (for webhooks)
91
94
  * - 'date': ISO 8601 date format validation
92
95
  * - 'positiveInteger': Positive integer validation
93
96
  *
@@ -99,8 +102,9 @@ export declare function isPositiveInteger(value: unknown): boolean;
99
102
  * @example
100
103
  * validateField('email', 'user@example.com', 'email') // passes
101
104
  * validateField('email', 'invalid', 'email') // throws "email must be a valid email address"
105
+ * validateField('webhookUrl', 'http://example.com', 'httpsUrl') // throws "webhookUrl must be a valid HTTPS URL"
102
106
  */
103
- export declare function validateField(fieldName: string, value: unknown, validationType: 'email' | 'url' | 'date' | 'positiveInteger' | 'required'): void;
107
+ export declare function validateField(fieldName: string, value: unknown, validationType: 'email' | 'url' | 'httpsUrl' | 'date' | 'positiveInteger' | 'required'): void;
104
108
  /**
105
109
  * Safely parses a JSON string with descriptive error handling.
106
110
  *
@@ -118,6 +122,23 @@ export declare function validateField(fieldName: string, value: unknown, validat
118
122
  * // Throws: "config contains invalid JSON"
119
123
  */
120
124
  export declare function safeJsonParse<T = unknown>(jsonString: string, fieldName: string): T;
125
+ /**
126
+ * Validates discount amount based on the amount type.
127
+ *
128
+ * - For 'percent' type: amount must be between 0 and 100 (inclusive)
129
+ * - For 'fixed' type: amount must be a positive integer (in cents)
130
+ *
131
+ * @param amount - The discount amount to validate
132
+ * @param amountType - The type of discount ('percent' or 'fixed')
133
+ * @throws Error if the amount is invalid for the given type
134
+ *
135
+ * @example
136
+ * validateDiscountAmount(50, 'percent') // passes (50%)
137
+ * validateDiscountAmount(150, 'percent') // throws "Percent discount must be between 0 and 100"
138
+ * validateDiscountAmount(1000, 'fixed') // passes ($10.00 in cents)
139
+ * validateDiscountAmount(-100, 'fixed') // throws "Fixed discount amount must be a positive integer"
140
+ */
141
+ export declare function validateDiscountAmount(amount: number, amountType: string): void;
121
142
  /**
122
143
  * Checks if an error is a rate limit error (HTTP 429).
123
144
  *
@@ -51,6 +51,7 @@ exports.isValidIsoDate = isValidIsoDate;
51
51
  exports.isPositiveInteger = isPositiveInteger;
52
52
  exports.validateField = validateField;
53
53
  exports.safeJsonParse = safeJsonParse;
54
+ exports.validateDiscountAmount = validateDiscountAmount;
54
55
  exports.isRateLimitError = isRateLimitError;
55
56
  exports.isRetryableError = isRetryableError;
56
57
  exports.lemonSqueezyApiRequest = lemonSqueezyApiRequest;
@@ -101,6 +102,7 @@ function isValidEmail(email) {
101
102
  * This prevents Server-Side Request Forgery (SSRF) attacks.
102
103
  *
103
104
  * @param url - The URL to validate
105
+ * @param requireHttps - If true, only HTTPS URLs are allowed (default: false)
104
106
  * @returns True if the URL is valid and safe, false otherwise
105
107
  *
106
108
  * @example
@@ -108,10 +110,15 @@ function isValidEmail(email) {
108
110
  * isValidUrl('http://localhost:3000') // false (internal)
109
111
  * isValidUrl('ftp://files.example.com') // false (non-http protocol)
110
112
  * isValidUrl('http://169.254.169.254') // false (AWS metadata)
113
+ * isValidUrl('http://example.com', true) // false (HTTPS required)
111
114
  */
112
- function isValidUrl(url) {
115
+ function isValidUrl(url, requireHttps = false) {
113
116
  try {
114
117
  const parsedUrl = new URL(url);
118
+ // If HTTPS is required, reject HTTP URLs
119
+ if (requireHttps && parsedUrl.protocol !== 'https:') {
120
+ return false;
121
+ }
115
122
  // Only allow http and https protocols (security: prevent file://, javascript:, etc.)
116
123
  if (!['http:', 'https:'].includes(parsedUrl.protocol)) {
117
124
  return false;
@@ -199,6 +206,7 @@ function isPositiveInteger(value) {
199
206
  * - 'required': Ensures value is not empty/null/undefined
200
207
  * - 'email': RFC 5322 compliant email validation
201
208
  * - 'url': Safe URL validation with SSRF protection
209
+ * - 'httpsUrl': Safe URL validation requiring HTTPS (for webhooks)
202
210
  * - 'date': ISO 8601 date format validation
203
211
  * - 'positiveInteger': Positive integer validation
204
212
  *
@@ -210,6 +218,7 @@ function isPositiveInteger(value) {
210
218
  * @example
211
219
  * validateField('email', 'user@example.com', 'email') // passes
212
220
  * validateField('email', 'invalid', 'email') // throws "email must be a valid email address"
221
+ * validateField('webhookUrl', 'http://example.com', 'httpsUrl') // throws "webhookUrl must be a valid HTTPS URL"
213
222
  */
214
223
  function validateField(fieldName, value, validationType) {
215
224
  if (validationType === 'required') {
@@ -233,6 +242,11 @@ function validateField(fieldName, value, validationType) {
233
242
  throw new Error(`${fieldName} must be a valid URL`);
234
243
  }
235
244
  break;
245
+ case 'httpsUrl':
246
+ if (typeof value !== 'string' || !isValidUrl(value, true)) {
247
+ throw new Error(`${fieldName} must be a valid HTTPS URL (Lemon Squeezy requires HTTPS for webhooks)`);
248
+ }
249
+ break;
236
250
  case 'date':
237
251
  if (typeof value !== 'string' || !isValidIsoDate(value)) {
238
252
  throw new Error(`${fieldName} must be a valid ISO 8601 date`);
@@ -269,6 +283,34 @@ function safeJsonParse(jsonString, fieldName) {
269
283
  throw new Error(`${fieldName} contains invalid JSON`);
270
284
  }
271
285
  }
286
+ /**
287
+ * Validates discount amount based on the amount type.
288
+ *
289
+ * - For 'percent' type: amount must be between 0 and 100 (inclusive)
290
+ * - For 'fixed' type: amount must be a positive integer (in cents)
291
+ *
292
+ * @param amount - The discount amount to validate
293
+ * @param amountType - The type of discount ('percent' or 'fixed')
294
+ * @throws Error if the amount is invalid for the given type
295
+ *
296
+ * @example
297
+ * validateDiscountAmount(50, 'percent') // passes (50%)
298
+ * validateDiscountAmount(150, 'percent') // throws "Percent discount must be between 0 and 100"
299
+ * validateDiscountAmount(1000, 'fixed') // passes ($10.00 in cents)
300
+ * validateDiscountAmount(-100, 'fixed') // throws "Fixed discount amount must be a positive integer"
301
+ */
302
+ function validateDiscountAmount(amount, amountType) {
303
+ if (amountType === 'percent') {
304
+ if (amount < 0 || amount > 100) {
305
+ throw new Error('Percent discount must be between 0 and 100');
306
+ }
307
+ }
308
+ else if (amountType === 'fixed') {
309
+ if (!Number.isInteger(amount) || amount < 0) {
310
+ throw new Error('Fixed discount amount must be a positive integer (in cents)');
311
+ }
312
+ }
313
+ }
272
314
  /**
273
315
  * Checks if an error is a rate limit error (HTTP 429).
274
316
  *
@@ -52,7 +52,8 @@ exports.customerFields = [
52
52
  type: 'string',
53
53
  required: true,
54
54
  default: '',
55
- description: 'The ID of the customer',
55
+ placeholder: 'e.g., 12345',
56
+ description: 'The ID of the customer (numeric string)',
56
57
  displayOptions: {
57
58
  show: { resource: ['customer'], operation: ['get', 'update', 'delete'] },
58
59
  },
@@ -64,7 +65,8 @@ exports.customerFields = [
64
65
  type: 'string',
65
66
  required: true,
66
67
  default: '',
67
- description: 'The ID of the store this customer belongs to',
68
+ placeholder: 'e.g., 12345',
69
+ description: 'The ID of the store this customer belongs to. Find this in your <a href="https://app.lemonsqueezy.com/settings/stores" target="_blank">Lemon Squeezy Dashboard</a>.',
68
70
  displayOptions: {
69
71
  show: { resource: ['customer'], operation: ['create'] },
70
72
  },
@@ -198,8 +200,8 @@ exports.customerFields = [
198
200
  name: 'limit',
199
201
  type: 'number',
200
202
  default: 50,
201
- description: 'Max number of results to return',
202
- typeOptions: { minValue: 1 },
203
+ description: 'Max number of results to return (API maximum is 100 per page)',
204
+ typeOptions: { minValue: 1, maxValue: 100 },
203
205
  displayOptions: {
204
206
  show: { resource: ['customer'], operation: ['getAll'], returnAll: [false] },
205
207
  },
@@ -35,20 +35,27 @@ exports.discountOperations = {
35
35
  action: 'Get many discounts',
36
36
  description: 'Retrieve multiple discounts',
37
37
  },
38
+ {
39
+ name: 'Update',
40
+ value: 'update',
41
+ action: 'Update a discount',
42
+ description: 'Update an existing discount code',
43
+ },
38
44
  ],
39
45
  default: 'getAll',
40
46
  };
41
47
  exports.discountFields = [
42
- // Discount ID for Get/Delete operations
48
+ // Discount ID for Get/Update/Delete operations
43
49
  {
44
50
  displayName: 'Discount ID',
45
51
  name: 'discountId',
46
52
  type: 'string',
47
53
  required: true,
48
54
  default: '',
49
- description: 'The ID of the discount',
55
+ placeholder: 'e.g., 12345',
56
+ description: 'The ID of the discount (numeric string)',
50
57
  displayOptions: {
51
- show: { resource: ['discount'], operation: ['get', 'delete'] },
58
+ show: { resource: ['discount'], operation: ['get', 'update', 'delete'] },
52
59
  },
53
60
  },
54
61
  // Create Fields
@@ -164,6 +171,86 @@ exports.discountFields = [
164
171
  },
165
172
  ],
166
173
  },
174
+ // Update Fields
175
+ {
176
+ displayName: 'Update Fields',
177
+ name: 'updateFields',
178
+ type: 'collection',
179
+ placeholder: 'Add Field',
180
+ default: {},
181
+ displayOptions: {
182
+ show: { resource: ['discount'], operation: ['update'] },
183
+ },
184
+ options: [
185
+ {
186
+ displayName: 'Name',
187
+ name: 'name',
188
+ type: 'string',
189
+ default: '',
190
+ description: 'Internal name for the discount (not visible to customers)',
191
+ },
192
+ {
193
+ displayName: 'Code',
194
+ name: 'code',
195
+ type: 'string',
196
+ default: '',
197
+ description: 'The discount code customers will use at checkout',
198
+ },
199
+ {
200
+ displayName: 'Amount',
201
+ name: 'amount',
202
+ type: 'number',
203
+ default: 0,
204
+ description: 'Discount amount (percentage 0-100 for percent type, or fixed amount in cents for fixed type)',
205
+ },
206
+ {
207
+ displayName: 'Amount Type',
208
+ name: 'amountType',
209
+ type: 'options',
210
+ options: constants_1.DISCOUNT_AMOUNT_TYPES,
211
+ default: 'percent',
212
+ description: 'Whether the discount is a percentage or fixed amount',
213
+ },
214
+ {
215
+ displayName: 'Duration',
216
+ name: 'duration',
217
+ type: 'options',
218
+ options: constants_1.DISCOUNT_DURATION_TYPES,
219
+ default: 'once',
220
+ description: 'How long the discount should apply for subscriptions',
221
+ },
222
+ {
223
+ displayName: 'Duration In Months',
224
+ name: 'durationInMonths',
225
+ type: 'number',
226
+ default: 1,
227
+ description: 'Number of months the discount applies (only for "repeating" duration)',
228
+ typeOptions: { minValue: 1 },
229
+ },
230
+ {
231
+ displayName: 'Max Redemptions',
232
+ name: 'maxRedemptions',
233
+ type: 'number',
234
+ default: 0,
235
+ description: 'Maximum number of times this discount can be used (0 for unlimited)',
236
+ typeOptions: { minValue: 0 },
237
+ },
238
+ {
239
+ displayName: 'Starts At',
240
+ name: 'startsAt',
241
+ type: 'dateTime',
242
+ default: '',
243
+ description: 'When the discount becomes active (ISO 8601 format, e.g., 2024-01-15T10:30:00Z)',
244
+ },
245
+ {
246
+ displayName: 'Expires At',
247
+ name: 'expiresAt',
248
+ type: 'dateTime',
249
+ default: '',
250
+ description: 'When the discount expires (ISO 8601 format, e.g., 2024-12-31T23:59:59Z)',
251
+ },
252
+ ],
253
+ },
167
254
  // Return All
168
255
  {
169
256
  displayName: 'Return All',
@@ -181,8 +268,8 @@ exports.discountFields = [
181
268
  name: 'limit',
182
269
  type: 'number',
183
270
  default: 50,
184
- description: 'Max number of results to return',
185
- typeOptions: { minValue: 1 },
271
+ description: 'Max number of results to return (API maximum is 100 per page)',
272
+ typeOptions: { minValue: 1, maxValue: 100 },
186
273
  displayOptions: {
187
274
  show: { resource: ['discount'], operation: ['getAll'], returnAll: [false] },
188
275
  },
@@ -0,0 +1,3 @@
1
+ import type { INodeProperties } from 'n8n-workflow';
2
+ export declare const fileOperations: INodeProperties;
3
+ export declare const fileFields: INodeProperties[];
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fileFields = exports.fileOperations = void 0;
4
+ exports.fileOperations = {
5
+ displayName: 'Operation',
6
+ name: 'operation',
7
+ type: 'options',
8
+ noDataExpression: true,
9
+ displayOptions: {
10
+ show: { resource: ['file'] },
11
+ },
12
+ options: [
13
+ {
14
+ name: 'Get',
15
+ value: 'get',
16
+ action: 'Get a file',
17
+ description: 'Retrieve a single file by ID',
18
+ },
19
+ {
20
+ name: 'Get Many',
21
+ value: 'getAll',
22
+ action: 'Get many files',
23
+ description: 'Retrieve multiple files',
24
+ },
25
+ ],
26
+ default: 'getAll',
27
+ };
28
+ exports.fileFields = [
29
+ // File ID for Get operation
30
+ {
31
+ displayName: 'File ID',
32
+ name: 'fileId',
33
+ type: 'string',
34
+ required: true,
35
+ default: '',
36
+ placeholder: 'e.g., 12345',
37
+ description: 'The ID of the file (numeric string)',
38
+ displayOptions: {
39
+ show: { resource: ['file'], operation: ['get'] },
40
+ },
41
+ },
42
+ // Return All
43
+ {
44
+ displayName: 'Return All',
45
+ name: 'returnAll',
46
+ type: 'boolean',
47
+ default: false,
48
+ description: 'Whether to return all results or only up to a given limit',
49
+ displayOptions: {
50
+ show: { resource: ['file'], operation: ['getAll'] },
51
+ },
52
+ },
53
+ // Limit
54
+ {
55
+ displayName: 'Limit',
56
+ name: 'limit',
57
+ type: 'number',
58
+ default: 50,
59
+ description: 'Max number of results to return (API maximum is 100 per page)',
60
+ typeOptions: { minValue: 1, maxValue: 100 },
61
+ displayOptions: {
62
+ show: { resource: ['file'], operation: ['getAll'], returnAll: [false] },
63
+ },
64
+ },
65
+ // Filters
66
+ {
67
+ displayName: 'Filters',
68
+ name: 'filters',
69
+ type: 'collection',
70
+ placeholder: 'Add Filter',
71
+ default: {},
72
+ displayOptions: {
73
+ show: { resource: ['file'], operation: ['getAll'] },
74
+ },
75
+ options: [
76
+ {
77
+ displayName: 'Variant ID',
78
+ name: 'variantId',
79
+ type: 'string',
80
+ default: '',
81
+ placeholder: 'e.g., 12345',
82
+ description: 'Filter files by variant ID',
83
+ },
84
+ ],
85
+ },
86
+ ];
@@ -15,7 +15,8 @@ import { checkoutOperations, checkoutFields } from './checkout';
15
15
  import { webhookOperations, webhookFields } from './webhook';
16
16
  import { usageRecordOperations, usageRecordFields } from './usageRecord';
17
17
  import { userOperations, userFields } from './user';
18
+ import { fileOperations, fileFields } from './file';
18
19
  export declare const resourceProperty: INodeProperties;
19
20
  export declare const allOperations: INodeProperties[];
20
21
  export declare const allFields: INodeProperties[];
21
- export { productOperations, productFields, orderOperations, orderFields, orderItemOperations, orderItemFields, subscriptionOperations, subscriptionFields, subscriptionInvoiceOperations, subscriptionInvoiceFields, customerOperations, customerFields, licenseKeyOperations, licenseKeyFields, licenseKeyInstanceOperations, licenseKeyInstanceFields, discountOperations, discountFields, discountRedemptionOperations, discountRedemptionFields, storeOperations, storeFields, variantOperations, variantFields, checkoutOperations, checkoutFields, webhookOperations, webhookFields, usageRecordOperations, usageRecordFields, userOperations, userFields, };
22
+ export { productOperations, productFields, orderOperations, orderFields, orderItemOperations, orderItemFields, subscriptionOperations, subscriptionFields, subscriptionInvoiceOperations, subscriptionInvoiceFields, customerOperations, customerFields, licenseKeyOperations, licenseKeyFields, licenseKeyInstanceOperations, licenseKeyInstanceFields, discountOperations, discountFields, discountRedemptionOperations, discountRedemptionFields, storeOperations, storeFields, variantOperations, variantFields, checkoutOperations, checkoutFields, webhookOperations, webhookFields, usageRecordOperations, usageRecordFields, userOperations, userFields, fileOperations, fileFields, };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.userFields = exports.userOperations = exports.usageRecordFields = exports.usageRecordOperations = exports.webhookFields = exports.webhookOperations = exports.checkoutFields = exports.checkoutOperations = exports.variantFields = exports.variantOperations = exports.storeFields = exports.storeOperations = exports.discountRedemptionFields = exports.discountRedemptionOperations = exports.discountFields = exports.discountOperations = exports.licenseKeyInstanceFields = exports.licenseKeyInstanceOperations = exports.licenseKeyFields = exports.licenseKeyOperations = exports.customerFields = exports.customerOperations = exports.subscriptionInvoiceFields = exports.subscriptionInvoiceOperations = exports.subscriptionFields = exports.subscriptionOperations = exports.orderItemFields = exports.orderItemOperations = exports.orderFields = exports.orderOperations = exports.productFields = exports.productOperations = exports.allFields = exports.allOperations = exports.resourceProperty = void 0;
3
+ exports.fileFields = exports.fileOperations = exports.userFields = exports.userOperations = exports.usageRecordFields = exports.usageRecordOperations = exports.webhookFields = exports.webhookOperations = exports.checkoutFields = exports.checkoutOperations = exports.variantFields = exports.variantOperations = exports.storeFields = exports.storeOperations = exports.discountRedemptionFields = exports.discountRedemptionOperations = exports.discountFields = exports.discountOperations = exports.licenseKeyInstanceFields = exports.licenseKeyInstanceOperations = exports.licenseKeyFields = exports.licenseKeyOperations = exports.customerFields = exports.customerOperations = exports.subscriptionInvoiceFields = exports.subscriptionInvoiceOperations = exports.subscriptionFields = exports.subscriptionOperations = exports.orderItemFields = exports.orderItemOperations = exports.orderFields = exports.orderOperations = exports.productFields = exports.productOperations = exports.allFields = exports.allOperations = exports.resourceProperty = void 0;
4
4
  const product_1 = require("./product");
5
5
  Object.defineProperty(exports, "productOperations", { enumerable: true, get: function () { return product_1.productOperations; } });
6
6
  Object.defineProperty(exports, "productFields", { enumerable: true, get: function () { return product_1.productFields; } });
@@ -49,6 +49,9 @@ Object.defineProperty(exports, "usageRecordFields", { enumerable: true, get: fun
49
49
  const user_1 = require("./user");
50
50
  Object.defineProperty(exports, "userOperations", { enumerable: true, get: function () { return user_1.userOperations; } });
51
51
  Object.defineProperty(exports, "userFields", { enumerable: true, get: function () { return user_1.userFields; } });
52
+ const file_1 = require("./file");
53
+ Object.defineProperty(exports, "fileOperations", { enumerable: true, get: function () { return file_1.fileOperations; } });
54
+ Object.defineProperty(exports, "fileFields", { enumerable: true, get: function () { return file_1.fileFields; } });
52
55
  const shared_1 = require("./shared");
53
56
  exports.resourceProperty = {
54
57
  displayName: 'Resource',
@@ -60,6 +63,7 @@ exports.resourceProperty = {
60
63
  { name: 'Customer', value: 'customer' },
61
64
  { name: 'Discount', value: 'discount' },
62
65
  { name: 'Discount Redemption', value: 'discountRedemption' },
66
+ { name: 'File', value: 'file' },
63
67
  { name: 'License Key', value: 'licenseKey' },
64
68
  { name: 'License Key Instance', value: 'licenseKeyInstance' },
65
69
  { name: 'Order', value: 'order' },
@@ -92,6 +96,7 @@ exports.allOperations = [
92
96
  webhook_1.webhookOperations,
93
97
  ...usageRecord_1.usageRecordOperations,
94
98
  ...user_1.userOperations,
99
+ file_1.fileOperations,
95
100
  ];
96
101
  exports.allFields = [
97
102
  ...product_1.productFields,
@@ -118,4 +123,5 @@ exports.allFields = [
118
123
  ...webhook_1.webhookFields,
119
124
  ...usageRecord_1.usageRecordFields,
120
125
  ...user_1.userFields,
126
+ ...file_1.fileFields,
121
127
  ];
@@ -325,6 +325,22 @@ export interface LicenseKeyInstanceAttributes extends BaseAttributes {
325
325
  identifier: string;
326
326
  name: string;
327
327
  }
328
+ /**
329
+ * File attributes
330
+ */
331
+ export interface FileAttributes extends BaseAttributes {
332
+ variant_id: number;
333
+ identifier: string;
334
+ name: string;
335
+ extension: string;
336
+ download_url: string;
337
+ size: number;
338
+ size_formatted: string;
339
+ version: string;
340
+ sort: number;
341
+ status: 'draft' | 'published';
342
+ test_mode: boolean;
343
+ }
328
344
  /**
329
345
  * Resource types
330
346
  */
@@ -339,6 +355,7 @@ export type Discount = JsonApiResource<'discounts', DiscountAttributes>;
339
355
  export type Checkout = JsonApiResource<'checkouts', CheckoutAttributes>;
340
356
  export type Webhook = JsonApiResource<'webhooks', WebhookAttributes>;
341
357
  export type LicenseKeyInstance = JsonApiResource<'license-key-instances', LicenseKeyInstanceAttributes>;
358
+ export type File = JsonApiResource<'files', FileAttributes>;
342
359
  /**
343
360
  * Webhook event types
344
361
  */
@@ -413,7 +430,7 @@ export interface PaginationOptions {
413
430
  /**
414
431
  * Resource name to endpoint mapping
415
432
  */
416
- export type ResourceName = 'product' | 'order' | 'subscription' | 'customer' | 'licenseKey' | 'discount' | 'store' | 'variant' | 'checkout' | 'webhook' | 'licenseKeyInstance';
433
+ export type ResourceName = 'product' | 'order' | 'subscription' | 'customer' | 'licenseKey' | 'discount' | 'store' | 'variant' | 'checkout' | 'webhook' | 'licenseKeyInstance' | 'file';
417
434
  /**
418
435
  * Operation types
419
436
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-lemonsqueezy",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "n8n community node for Lemon Squeezy - digital products and subscriptions platform",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",