@lunch-money/v2-api-spec 2.11.1-preview.5 → 2.11.1-preview.9
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 +17 -0
- package/lunch-money-api-v2.yaml +294 -48
- package/oauth-scopes/catalog.d.ts +9 -0
- package/oauth-scopes/catalog.js +528 -0
- package/oauth-scopes/index.d.ts +2 -0
- package/oauth-scopes/index.js +12 -0
- package/oauth-scopes/types.d.ts +50 -0
- package/oauth-scopes/types.js +2 -0
- package/package.json +20 -3
- package/version-history.md +5 -0
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ After installation, the package provides:
|
|
|
14
14
|
|
|
15
15
|
- **OpenAPI Specification**: `node_modules/@lunch-money/v2-api-spec/lunch-money-api-v2.yaml`
|
|
16
16
|
- **Version History**: `node_modules/@lunch-money/v2-api-spec/version-history.md`
|
|
17
|
+
- **OAuth scope catalog**: `@lunch-money/v2-api-spec/oauth-scopes`
|
|
17
18
|
|
|
18
19
|
## Usage
|
|
19
20
|
|
|
@@ -26,6 +27,22 @@ const specPath = require.resolve('@lunch-money/v2-api-spec/lunch-money-api-v2.ya
|
|
|
26
27
|
const spec = fs.readFileSync(specPath, 'utf8');
|
|
27
28
|
```
|
|
28
29
|
|
|
30
|
+
### Using the OAuth scope catalog
|
|
31
|
+
|
|
32
|
+
The package also provides immutable OAuth scope and scope-group definitions.
|
|
33
|
+
API scopes identify the V2 operations they authorize by `operationId`.
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
const {
|
|
37
|
+
getOAuthScopeDefinition,
|
|
38
|
+
matchOAuthScopeGroup,
|
|
39
|
+
oauthScopeGroups,
|
|
40
|
+
oauthScopes,
|
|
41
|
+
} = require('@lunch-money/v2-api-spec/oauth-scopes');
|
|
42
|
+
|
|
43
|
+
const transactionRead = getOAuthScopeDefinition('transactions:read');
|
|
44
|
+
```
|
|
45
|
+
|
|
29
46
|
### Using with OpenAPI Tools
|
|
30
47
|
|
|
31
48
|
```bash
|
package/lunch-money-api-v2.yaml
CHANGED
|
@@ -53,9 +53,11 @@ servers:
|
|
|
53
53
|
tags:
|
|
54
54
|
- name: me
|
|
55
55
|
description: View details and settings for the current user and account.<p>
|
|
56
|
-
Use [/me/
|
|
57
|
-
[/me/
|
|
58
|
-
|
|
56
|
+
Use [/me/user/settings](#tag/me/GET/me/user/settings) for user-wide
|
|
57
|
+
preferences, [/me/account/settings](#tag/me/GET/me/account/settings) for
|
|
58
|
+
account-wide preferences, and
|
|
59
|
+
[/me/user/account/settings](#tag/me/GET/me/user/account/settings) for
|
|
60
|
+
preferences specific to the current user and budgeting account.
|
|
59
61
|
- name: categories
|
|
60
62
|
description: Work with categories
|
|
61
63
|
externalDocs:
|
|
@@ -3798,6 +3800,7 @@ components:
|
|
|
3798
3800
|
- budget_rollover_left_to_budget
|
|
3799
3801
|
|
|
3800
3802
|
weekStartsOnEnum:
|
|
3803
|
+
x-internal: true
|
|
3801
3804
|
type: string
|
|
3802
3805
|
title: week starts on enum
|
|
3803
3806
|
enum:
|
|
@@ -3806,6 +3809,7 @@ components:
|
|
|
3806
3809
|
description: The day on which a calendar week begins.
|
|
3807
3810
|
|
|
3808
3811
|
monthYearFormatEnum:
|
|
3812
|
+
x-internal: true
|
|
3809
3813
|
type: string
|
|
3810
3814
|
title: month and year format enum
|
|
3811
3815
|
description: Format string for displaying month and year values
|
|
@@ -3832,6 +3836,7 @@ components:
|
|
|
3832
3836
|
- "YYYY/MM"
|
|
3833
3837
|
|
|
3834
3838
|
monthDayYearFormatEnum:
|
|
3839
|
+
x-internal: true
|
|
3835
3840
|
type: string
|
|
3836
3841
|
title: month, day and year format enum
|
|
3837
3842
|
description: Format string for displaying full dates in the
|
|
@@ -3889,6 +3894,7 @@ components:
|
|
|
3889
3894
|
- "M/DD/YYYY"
|
|
3890
3895
|
|
|
3891
3896
|
monthDayFormatEnum:
|
|
3897
|
+
x-internal: true
|
|
3892
3898
|
type: string
|
|
3893
3899
|
title: month and day format enum
|
|
3894
3900
|
description: Format string for displaying month and day values
|
|
@@ -3931,6 +3937,98 @@ components:
|
|
|
3931
3937
|
- "DD.M"
|
|
3932
3938
|
- "DD/M"
|
|
3933
3939
|
|
|
3940
|
+
localeEnum:
|
|
3941
|
+
type: string
|
|
3942
|
+
title: locale enum
|
|
3943
|
+
description: Locale used for formatting numbers and currency amounts in
|
|
3944
|
+
the Lunch Money app.
|
|
3945
|
+
example: en-US
|
|
3946
|
+
enum:
|
|
3947
|
+
- sq-AL # Albanian (Albania)
|
|
3948
|
+
- be-BY # Belarusian (Belarus)
|
|
3949
|
+
- bg-BG # Bulgarian (Bulgaria)
|
|
3950
|
+
- ca-ES # Catalan (Spain)
|
|
3951
|
+
- zh-CN # Chinese (Simplified) (China)
|
|
3952
|
+
- zh-HK # Chinese (Traditional) (Hong Kong)
|
|
3953
|
+
- zh-TW # Chinese (Traditional) (Taiwan)
|
|
3954
|
+
- hr-HR # Croatian (Croatia)
|
|
3955
|
+
- cs-CZ # Czech (Czech Republic)
|
|
3956
|
+
- da-DK # Danish (Denmark)
|
|
3957
|
+
- nl-BE # Dutch (Belgium)
|
|
3958
|
+
- nl-NL # Dutch (Netherlands)
|
|
3959
|
+
- en-AU # English (Australia)
|
|
3960
|
+
- en-CA # English (Canada)
|
|
3961
|
+
- en-IN # English (India)
|
|
3962
|
+
- en-IE # English (Ireland)
|
|
3963
|
+
- en-MT # English (Malta)
|
|
3964
|
+
- en-NZ # English (New Zealand)
|
|
3965
|
+
- en-PH # English (Philippines)
|
|
3966
|
+
- en-SG # English (Singapore)
|
|
3967
|
+
- en-ZA # English (South Africa)
|
|
3968
|
+
- en-GB # English (United Kingdom)
|
|
3969
|
+
- en-US # English (United States)
|
|
3970
|
+
- et-EE # Estonian (Estonia)
|
|
3971
|
+
- fi-FI # Finnish (Finland)
|
|
3972
|
+
- fr-BE # French (Belgium)
|
|
3973
|
+
- fr-CA # French (Canada)
|
|
3974
|
+
- fr-FR # French (France)
|
|
3975
|
+
- fr-LU # French (Luxembourg)
|
|
3976
|
+
- fr-CH # French (Switzerland)
|
|
3977
|
+
- de-AT # German (Austria)
|
|
3978
|
+
- de-DE # German (Germany)
|
|
3979
|
+
- de-LU # German (Luxembourg)
|
|
3980
|
+
- de-CH # German (Switzerland)
|
|
3981
|
+
- el-CY # Greek (Cyprus)
|
|
3982
|
+
- el-GR # Greek (Greece)
|
|
3983
|
+
- iw-IL # Hebrew (Israel); modern replacement: he-IL
|
|
3984
|
+
- hi-IN # Hindi (India)
|
|
3985
|
+
- hu-HU # Hungarian (Hungary)
|
|
3986
|
+
- is-IS # Icelandic (Iceland)
|
|
3987
|
+
- in-ID # Indonesian (Indonesia); modern replacement: id-ID
|
|
3988
|
+
- ga-IE # Irish (Ireland)
|
|
3989
|
+
- it-IT # Italian (Italy)
|
|
3990
|
+
- it-CH # Italian (Switzerland)
|
|
3991
|
+
- ja-JP # Japanese (Japan)
|
|
3992
|
+
- ko-KR # Korean (South Korea)
|
|
3993
|
+
- lv-LV # Latvian (Latvia)
|
|
3994
|
+
- lt-LT # Lithuanian (Lithuania)
|
|
3995
|
+
- mk-MK # Macedonian (Macedonia)
|
|
3996
|
+
- ms-MY # Malay (Malaysia)
|
|
3997
|
+
- mt-MT # Maltese (Malta)
|
|
3998
|
+
- no-NO # Norwegian (Norway)
|
|
3999
|
+
- pl-PL # Polish (Poland)
|
|
4000
|
+
- pt-BR # Portuguese (Brazil)
|
|
4001
|
+
- pt-PT # Portuguese (Portugal)
|
|
4002
|
+
- ro-RO # Romanian (Romania)
|
|
4003
|
+
- ru-RU # Russian (Russia)
|
|
4004
|
+
- sk-SK # Slovak (Slovakia)
|
|
4005
|
+
- sl-SI # Slovenian (Slovenia)
|
|
4006
|
+
- es-AR # Spanish (Argentina)
|
|
4007
|
+
- es-BO # Spanish (Bolivia)
|
|
4008
|
+
- es-CL # Spanish (Chile)
|
|
4009
|
+
- es-CO # Spanish (Colombia)
|
|
4010
|
+
- es-CR # Spanish (Costa Rica)
|
|
4011
|
+
- es-DO # Spanish (Dominican Republic)
|
|
4012
|
+
- es-EC # Spanish (Ecuador)
|
|
4013
|
+
- es-SV # Spanish (El Salvador)
|
|
4014
|
+
- es-GT # Spanish (Guatemala)
|
|
4015
|
+
- es-HN # Spanish (Honduras)
|
|
4016
|
+
- es-MX # Spanish (Mexico)
|
|
4017
|
+
- es-NI # Spanish (Nicaragua)
|
|
4018
|
+
- es-PA # Spanish (Panama)
|
|
4019
|
+
- es-PY # Spanish (Paraguay)
|
|
4020
|
+
- es-PE # Spanish (Peru)
|
|
4021
|
+
- es-PR # Spanish (Puerto Rico)
|
|
4022
|
+
- es-ES # Spanish (Spain)
|
|
4023
|
+
- es-US # Spanish (United States)
|
|
4024
|
+
- es-UY # Spanish (Uruguay)
|
|
4025
|
+
- es-VE # Spanish (Venezuela)
|
|
4026
|
+
- sv-SE # Swedish (Sweden)
|
|
4027
|
+
- th-TH # Thai (Thailand)
|
|
4028
|
+
- tr-TR # Turkish (Turkey)
|
|
4029
|
+
- uk-UA # Ukrainian (Ukraine)
|
|
4030
|
+
- vi-VN # Vietnamese (Vietnam)
|
|
4031
|
+
|
|
3934
4032
|
accountSettingsObject:
|
|
3935
4033
|
type: object
|
|
3936
4034
|
title: account settings object
|
|
@@ -3954,13 +4052,19 @@ components:
|
|
|
3954
4052
|
description: Display name of the budgeting account in the Lunch Money
|
|
3955
4053
|
app.
|
|
3956
4054
|
locale:
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
4055
|
+
allOf:
|
|
4056
|
+
- $ref: "#/components/schemas/localeEnum"
|
|
4057
|
+
example: en-US
|
|
4058
|
+
description: Locale used for formatting numbers and currency amounts
|
|
4059
|
+
in the Lunch Money app (for example, `en-US`). See
|
|
4060
|
+
[Supported Locales](https://lunchmoney.dev/v2/locales) for accepted
|
|
4061
|
+
values. Date presentation is configured separately through
|
|
4062
|
+
[GET /me/user/settings](#tag/me/GET/me/user/settings) and
|
|
4063
|
+
[PUT /me/user/settings](#tag/me/PUT/me/user/settings). When no
|
|
4064
|
+
locale is explicitly stored for the account, the effective locale
|
|
4065
|
+
is derived from the `default_locale` associated with
|
|
4066
|
+
`primary_currency` in the currencies table (for example, `usd` →
|
|
4067
|
+
`en-US`, `cad` → `en-CA`, `gbp` → `en-GB`).
|
|
3964
4068
|
auto_create_category_rules:
|
|
3965
4069
|
type: boolean
|
|
3966
4070
|
default: true
|
|
@@ -3971,16 +4075,11 @@ components:
|
|
|
3971
4075
|
default: true
|
|
3972
4076
|
description: If `true`, suggested transaction rules are created
|
|
3973
4077
|
automatically.
|
|
3974
|
-
|
|
4078
|
+
include_pending_in_totals:
|
|
3975
4079
|
type: boolean
|
|
3976
4080
|
default: true
|
|
3977
|
-
description: If `true`, transactions are
|
|
3978
|
-
|
|
3979
|
-
auto_review_transaction_on_creation:
|
|
3980
|
-
type: boolean
|
|
3981
|
-
default: true
|
|
3982
|
-
description: If `true`, transactions are marked as reviewed when
|
|
3983
|
-
created.
|
|
4081
|
+
description: If `true`, pending transactions are included in account
|
|
4082
|
+
totals.
|
|
3984
4083
|
required:
|
|
3985
4084
|
- primary_currency
|
|
3986
4085
|
- supported_currencies
|
|
@@ -3988,13 +4087,13 @@ components:
|
|
|
3988
4087
|
- locale
|
|
3989
4088
|
- auto_create_category_rules
|
|
3990
4089
|
- auto_create_suggested_transaction_rules
|
|
3991
|
-
-
|
|
3992
|
-
- auto_review_transaction_on_creation
|
|
4090
|
+
- include_pending_in_totals
|
|
3993
4091
|
|
|
3994
4092
|
updateAccountSettingsRequestObject:
|
|
3995
4093
|
x-internal: true
|
|
3996
4094
|
type: object
|
|
3997
4095
|
additionalProperties: false
|
|
4096
|
+
minProperties: 1
|
|
3998
4097
|
description: Request body for updating account settings. Include at least
|
|
3999
4098
|
one property to update.
|
|
4000
4099
|
properties:
|
|
@@ -4016,9 +4115,15 @@ components:
|
|
|
4016
4115
|
description: If set, updates the display name of the budgeting account.
|
|
4017
4116
|
x-updatable: true
|
|
4018
4117
|
locale:
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4118
|
+
allOf:
|
|
4119
|
+
- $ref: "#/components/schemas/localeEnum"
|
|
4120
|
+
example: en-US
|
|
4121
|
+
description: If set, updates the locale used for formatting numbers
|
|
4122
|
+
and currency amounts in the Lunch Money app. See
|
|
4123
|
+
[Supported Locales](https://lunchmoney.dev/v2/locales) for accepted
|
|
4124
|
+
values. Date presentation is configured separately through
|
|
4125
|
+
[GET /me/user/settings](#tag/me/GET/me/user/settings) and
|
|
4126
|
+
[PUT /me/user/settings](#tag/me/PUT/me/user/settings).
|
|
4022
4127
|
x-updatable: true
|
|
4023
4128
|
auto_create_category_rules:
|
|
4024
4129
|
type: boolean
|
|
@@ -4030,15 +4135,70 @@ components:
|
|
|
4030
4135
|
description: If set, updates whether suggested transaction rules are
|
|
4031
4136
|
created automatically.
|
|
4032
4137
|
x-updatable: true
|
|
4138
|
+
include_pending_in_totals:
|
|
4139
|
+
type: boolean
|
|
4140
|
+
description: If set, updates whether pending transactions are included
|
|
4141
|
+
in account totals.
|
|
4142
|
+
x-updatable: true
|
|
4143
|
+
|
|
4144
|
+
userAccountSettingsObject:
|
|
4145
|
+
type: object
|
|
4146
|
+
title: user account settings object
|
|
4147
|
+
additionalProperties: false
|
|
4148
|
+
description: Settings specific to the authorized user within the current
|
|
4149
|
+
budgeting account.
|
|
4150
|
+
properties:
|
|
4151
|
+
auto_review_transaction_on_update:
|
|
4152
|
+
type: boolean
|
|
4153
|
+
default: true
|
|
4154
|
+
description: If `true`, transactions are marked as reviewed when their
|
|
4155
|
+
date, category, payee, amount, account, or notes are changed.
|
|
4156
|
+
auto_review_transaction_on_creation:
|
|
4157
|
+
type: boolean
|
|
4158
|
+
default: true
|
|
4159
|
+
description: If `true`, new manual transactions start as reviewed. If
|
|
4160
|
+
`false`, they start as unreviewed.
|
|
4161
|
+
default_manual_account_id:
|
|
4162
|
+
type: integer
|
|
4163
|
+
nullable: true
|
|
4164
|
+
description: Manual account selected by default when the user creates a
|
|
4165
|
+
manual transaction in the current budgeting account. Must identify a
|
|
4166
|
+
manual account returned by
|
|
4167
|
+
[GET /manual_accounts](#tag/manual_accounts/GET/manual_accounts) for
|
|
4168
|
+
the current budgeting account. Set to `null` to clear the selection.
|
|
4169
|
+
required:
|
|
4170
|
+
- auto_review_transaction_on_update
|
|
4171
|
+
- auto_review_transaction_on_creation
|
|
4172
|
+
- default_manual_account_id
|
|
4173
|
+
|
|
4174
|
+
updateUserAccountSettingsRequestObject:
|
|
4175
|
+
x-internal: true
|
|
4176
|
+
type: object
|
|
4177
|
+
additionalProperties: false
|
|
4178
|
+
minProperties: 1
|
|
4179
|
+
description: Request body for updating settings specific to the authorized
|
|
4180
|
+
user within the current budgeting account. Include at least one property
|
|
4181
|
+
to update.
|
|
4182
|
+
properties:
|
|
4033
4183
|
auto_review_transaction_on_update:
|
|
4034
4184
|
type: boolean
|
|
4035
4185
|
description: If set, updates whether transactions are marked as reviewed
|
|
4036
|
-
when
|
|
4186
|
+
when their date, category, payee, amount, account, or notes are
|
|
4187
|
+
changed.
|
|
4037
4188
|
x-updatable: true
|
|
4038
4189
|
auto_review_transaction_on_creation:
|
|
4039
4190
|
type: boolean
|
|
4040
|
-
description: If set, updates whether transactions
|
|
4041
|
-
|
|
4191
|
+
description: If set, updates whether new manual transactions start as
|
|
4192
|
+
reviewed or unreviewed.
|
|
4193
|
+
x-updatable: true
|
|
4194
|
+
default_manual_account_id:
|
|
4195
|
+
type: integer
|
|
4196
|
+
nullable: true
|
|
4197
|
+
description: If set, updates the manual account selected by default when
|
|
4198
|
+
the user creates a manual transaction in the current budgeting
|
|
4199
|
+
account. Must identify a manual account returned by
|
|
4200
|
+
[GET /manual_accounts](#tag/manual_accounts/GET/manual_accounts) for
|
|
4201
|
+
the current budgeting account. Set to `null` to clear the selection.
|
|
4042
4202
|
x-updatable: true
|
|
4043
4203
|
|
|
4044
4204
|
userSettingsObject:
|
|
@@ -4114,6 +4274,7 @@ components:
|
|
|
4114
4274
|
x-internal: true
|
|
4115
4275
|
type: object
|
|
4116
4276
|
additionalProperties: false
|
|
4277
|
+
minProperties: 1
|
|
4117
4278
|
description: Request body for updating user settings. Include at least one
|
|
4118
4279
|
property to update.
|
|
4119
4280
|
properties:
|
|
@@ -4950,11 +5111,14 @@ paths:
|
|
|
4950
5111
|
summary: Get current user
|
|
4951
5112
|
description: |-
|
|
4952
5113
|
Get details about the user associated with the supplied authorization
|
|
4953
|
-
token.<p>
|
|
4954
|
-
|
|
4955
|
-
[/me/
|
|
4956
|
-
|
|
4957
|
-
|
|
5114
|
+
token.<p> Use [/me/user/settings](#tag/me/GET/me/user/settings) for
|
|
5115
|
+
user-wide preferences,
|
|
5116
|
+
[/me/account/settings](#tag/me/GET/me/account/settings) for account-wide
|
|
5117
|
+
preferences, and
|
|
5118
|
+
[/me/user/account/settings](#tag/me/GET/me/user/account/settings) for
|
|
5119
|
+
preferences specific to the current user and budgeting account.
|
|
5120
|
+
Properties such as `primary_currency` and `budget_name` remain on this
|
|
5121
|
+
response for backwards compatibility.
|
|
4958
5122
|
operationId: getMe
|
|
4959
5123
|
parameters: []
|
|
4960
5124
|
responses:
|
|
@@ -4983,8 +5147,9 @@ paths:
|
|
|
4983
5147
|
tags:
|
|
4984
5148
|
- me
|
|
4985
5149
|
summary: Get account settings
|
|
4986
|
-
description:
|
|
4987
|
-
Returns
|
|
5150
|
+
description: >-
|
|
5151
|
+
Returns settings for the current budgeting account. These settings apply
|
|
5152
|
+
regardless of which user is accessing the account.
|
|
4988
5153
|
operationId: getAccountSettings
|
|
4989
5154
|
responses:
|
|
4990
5155
|
"200":
|
|
@@ -5003,8 +5168,7 @@ paths:
|
|
|
5003
5168
|
locale: en-US
|
|
5004
5169
|
auto_create_category_rules: true
|
|
5005
5170
|
auto_create_suggested_transaction_rules: true
|
|
5006
|
-
|
|
5007
|
-
auto_review_transaction_on_creation: true
|
|
5171
|
+
include_pending_in_totals: true
|
|
5008
5172
|
"401":
|
|
5009
5173
|
$ref: "#/components/responses/unauthorizedToken"
|
|
5010
5174
|
"429":
|
|
@@ -5017,11 +5181,10 @@ paths:
|
|
|
5017
5181
|
summary: Update account settings
|
|
5018
5182
|
description: |-
|
|
5019
5183
|
Updates account-level settings for the budgeting account
|
|
5020
|
-
associated with the authorized API token
|
|
5021
|
-
`GET /me/account/settings`
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
includes at least one updatable property.
|
|
5184
|
+
associated with the authorized API token. Submit the full response from
|
|
5185
|
+
`GET /me/account/settings` with one or more properties changed, or
|
|
5186
|
+
provide only the properties to update. The request body must include at
|
|
5187
|
+
least one property.
|
|
5025
5188
|
operationId: updateAccountSettings
|
|
5026
5189
|
requestBody:
|
|
5027
5190
|
required: true
|
|
@@ -5036,7 +5199,7 @@ paths:
|
|
|
5036
5199
|
Update automation preferences:
|
|
5037
5200
|
value:
|
|
5038
5201
|
auto_create_category_rules: false
|
|
5039
|
-
|
|
5202
|
+
include_pending_in_totals: false
|
|
5040
5203
|
responses:
|
|
5041
5204
|
"200":
|
|
5042
5205
|
description: Account settings updated successfully
|
|
@@ -5061,8 +5224,10 @@ paths:
|
|
|
5061
5224
|
tags:
|
|
5062
5225
|
- me
|
|
5063
5226
|
summary: Get user settings
|
|
5064
|
-
description:
|
|
5065
|
-
Returns
|
|
5227
|
+
description: >-
|
|
5228
|
+
Returns display and formatting preferences for the authorized user.
|
|
5229
|
+
These settings apply across every budgeting account the user owns or
|
|
5230
|
+
collaborates on.
|
|
5066
5231
|
operationId: getUserSettings
|
|
5067
5232
|
responses:
|
|
5068
5233
|
"200":
|
|
@@ -5093,11 +5258,10 @@ paths:
|
|
|
5093
5258
|
summary: Update user settings
|
|
5094
5259
|
description: |-
|
|
5095
5260
|
Updates user-level display and formatting preferences for the user
|
|
5096
|
-
associated with the authorized API token
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
request includes at least one updatable property.<p> Updating
|
|
5261
|
+
associated with the authorized API token. Submit the full response from
|
|
5262
|
+
`GET /me/user/settings` with one or more properties changed, or provide
|
|
5263
|
+
only the properties to update. The request body must include at least
|
|
5264
|
+
one property.<p> Updating
|
|
5101
5265
|
`show_debits_as_negative` affects display in the Lunch Money app only.
|
|
5102
5266
|
Amount fields in API responses always use positive values for debits and
|
|
5103
5267
|
negative values for credits.
|
|
@@ -5137,6 +5301,88 @@ paths:
|
|
|
5137
5301
|
$ref: "#/components/responses/rateLimited"
|
|
5138
5302
|
"500":
|
|
5139
5303
|
$ref: "#/components/responses/serverError"
|
|
5304
|
+
/me/user/account/settings:
|
|
5305
|
+
get:
|
|
5306
|
+
tags:
|
|
5307
|
+
- me
|
|
5308
|
+
summary: Get user account settings
|
|
5309
|
+
description: >-
|
|
5310
|
+
Returns settings specific to the authorized user within the current
|
|
5311
|
+
budgeting account. These settings do not affect other users or the
|
|
5312
|
+
authorized user's settings in other budgeting accounts.
|
|
5313
|
+
operationId: getUserAccountSettings
|
|
5314
|
+
responses:
|
|
5315
|
+
"200":
|
|
5316
|
+
description: Settings for the authorized user in the current budgeting
|
|
5317
|
+
account
|
|
5318
|
+
content:
|
|
5319
|
+
application/json:
|
|
5320
|
+
schema:
|
|
5321
|
+
$ref: "#/components/schemas/userAccountSettingsObject"
|
|
5322
|
+
example:
|
|
5323
|
+
auto_review_transaction_on_update: true
|
|
5324
|
+
auto_review_transaction_on_creation: true
|
|
5325
|
+
default_manual_account_id: null
|
|
5326
|
+
"401":
|
|
5327
|
+
$ref: "#/components/responses/unauthorizedToken"
|
|
5328
|
+
"429":
|
|
5329
|
+
$ref: "#/components/responses/rateLimited"
|
|
5330
|
+
"500":
|
|
5331
|
+
$ref: "#/components/responses/serverError"
|
|
5332
|
+
put:
|
|
5333
|
+
tags:
|
|
5334
|
+
- me
|
|
5335
|
+
summary: Update user account settings
|
|
5336
|
+
description: |-
|
|
5337
|
+
Updates settings specific to the authorized user within the current
|
|
5338
|
+
budgeting account. Submit the full response from
|
|
5339
|
+
`GET /me/user/account/settings` with one or more properties changed, or
|
|
5340
|
+
provide only the properties to update. The request body must include at
|
|
5341
|
+
least one property.
|
|
5342
|
+
operationId: updateUserAccountSettings
|
|
5343
|
+
requestBody:
|
|
5344
|
+
required: true
|
|
5345
|
+
content:
|
|
5346
|
+
application/json:
|
|
5347
|
+
schema:
|
|
5348
|
+
$ref: "#/components/schemas/updateUserAccountSettingsRequestObject"
|
|
5349
|
+
examples:
|
|
5350
|
+
Update review preference:
|
|
5351
|
+
value:
|
|
5352
|
+
auto_review_transaction_on_creation: false
|
|
5353
|
+
Clear default manual account:
|
|
5354
|
+
value:
|
|
5355
|
+
default_manual_account_id: null
|
|
5356
|
+
responses:
|
|
5357
|
+
"200":
|
|
5358
|
+
description: User account settings updated successfully
|
|
5359
|
+
content:
|
|
5360
|
+
application/json:
|
|
5361
|
+
schema:
|
|
5362
|
+
$ref: "#/components/schemas/userAccountSettingsObject"
|
|
5363
|
+
examples:
|
|
5364
|
+
Update review preference:
|
|
5365
|
+
value:
|
|
5366
|
+
auto_review_transaction_on_update: true
|
|
5367
|
+
auto_review_transaction_on_creation: false
|
|
5368
|
+
default_manual_account_id: null
|
|
5369
|
+
Clear default manual account:
|
|
5370
|
+
value:
|
|
5371
|
+
auto_review_transaction_on_update: true
|
|
5372
|
+
auto_review_transaction_on_creation: true
|
|
5373
|
+
default_manual_account_id: null
|
|
5374
|
+
"400":
|
|
5375
|
+
description: Invalid request body
|
|
5376
|
+
content:
|
|
5377
|
+
application/json:
|
|
5378
|
+
schema:
|
|
5379
|
+
$ref: "#/components/schemas/errorResponseObject"
|
|
5380
|
+
"401":
|
|
5381
|
+
$ref: "#/components/responses/unauthorizedToken"
|
|
5382
|
+
"429":
|
|
5383
|
+
$ref: "#/components/responses/rateLimited"
|
|
5384
|
+
"500":
|
|
5385
|
+
$ref: "#/components/responses/serverError"
|
|
5140
5386
|
/summary:
|
|
5141
5387
|
get:
|
|
5142
5388
|
tags:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { OAuthCatalogDefinition, OAuthCatalogValidationOptions, OAuthCatalogValidationResult, OAuthScopeDefinition, OAuthScopeGroupDefinition, OAuthScopeGroupMatch, OAuthScopeName } from './types';
|
|
2
|
+
export declare const oauthScopes: readonly OAuthScopeDefinition[];
|
|
3
|
+
export declare const oauthScopeGroups: readonly OAuthScopeGroupDefinition[];
|
|
4
|
+
export declare const oauthCatalog: OAuthCatalogDefinition;
|
|
5
|
+
export declare function getOAuthScopeDefinition(name: OAuthScopeName): OAuthScopeDefinition | undefined;
|
|
6
|
+
export declare function getOAuthScopeGroup(id: string): OAuthScopeGroupDefinition | undefined;
|
|
7
|
+
export declare function getOAuthScopeForOperationId(operationId: string): OAuthScopeDefinition | undefined;
|
|
8
|
+
export declare function matchOAuthScopeGroup(scopeNames: readonly OAuthScopeName[]): OAuthScopeGroupMatch;
|
|
9
|
+
export declare function validateOAuthCatalog(definition: OAuthCatalogDefinition, options?: OAuthCatalogValidationOptions): OAuthCatalogValidationResult;
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oauthCatalog = exports.oauthScopeGroups = exports.oauthScopes = void 0;
|
|
4
|
+
exports.getOAuthScopeDefinition = getOAuthScopeDefinition;
|
|
5
|
+
exports.getOAuthScopeGroup = getOAuthScopeGroup;
|
|
6
|
+
exports.getOAuthScopeForOperationId = getOAuthScopeForOperationId;
|
|
7
|
+
exports.matchOAuthScopeGroup = matchOAuthScopeGroup;
|
|
8
|
+
exports.validateOAuthCatalog = validateOAuthCatalog;
|
|
9
|
+
const freezeScope = (scope) => Object.freeze({ ...scope, operationIds: Object.freeze([...scope.operationIds]) });
|
|
10
|
+
const freezeGroup = (group) => Object.freeze({ ...group, scopes: Object.freeze([...group.scopes]) });
|
|
11
|
+
const scopeDefinitions = [
|
|
12
|
+
{
|
|
13
|
+
name: 'openid',
|
|
14
|
+
description: 'Verify your identity with Lunch Money',
|
|
15
|
+
category: 'identity',
|
|
16
|
+
operationIds: [],
|
|
17
|
+
status: 'active',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'email',
|
|
21
|
+
description: 'View your email address and whether it has been verified',
|
|
22
|
+
category: 'identity',
|
|
23
|
+
operationIds: [],
|
|
24
|
+
status: 'active',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'profile',
|
|
28
|
+
description: 'View your Lunch Money profile information',
|
|
29
|
+
category: 'identity',
|
|
30
|
+
operationIds: [],
|
|
31
|
+
status: 'active',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'offline_access',
|
|
35
|
+
description: 'Continue accessing Lunch Money when you are not actively using the app',
|
|
36
|
+
category: 'offline',
|
|
37
|
+
operationIds: [],
|
|
38
|
+
status: 'active',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'me:read',
|
|
42
|
+
description: 'View your Lunch Money identity and account, user, and budget settings',
|
|
43
|
+
category: 'api',
|
|
44
|
+
operationIds: ['getMe', 'getAccountSettings', 'getUserSettings', 'getUserAccountSettings'],
|
|
45
|
+
status: 'active',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'me:update',
|
|
49
|
+
description: 'Update your Lunch Money account, user, and budget settings',
|
|
50
|
+
category: 'api',
|
|
51
|
+
operationIds: ['updateAccountSettings', 'updateUserSettings', 'updateUserAccountSettings'],
|
|
52
|
+
status: 'active',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'summary:read',
|
|
56
|
+
description: 'View your budget summary',
|
|
57
|
+
category: 'api',
|
|
58
|
+
operationIds: ['getBudgetSummary'],
|
|
59
|
+
status: 'active',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'categories:read',
|
|
63
|
+
description: 'View categories and category groups',
|
|
64
|
+
category: 'api',
|
|
65
|
+
operationIds: ['getAllCategories', 'getCategoryById'],
|
|
66
|
+
status: 'active',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'categories:create',
|
|
70
|
+
description: 'Create categories and category groups',
|
|
71
|
+
category: 'api',
|
|
72
|
+
operationIds: ['createCategory'],
|
|
73
|
+
status: 'active',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'categories:update',
|
|
77
|
+
description: 'Update categories and category groups',
|
|
78
|
+
category: 'api',
|
|
79
|
+
operationIds: ['updateCategory'],
|
|
80
|
+
status: 'active',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'categories:delete',
|
|
84
|
+
description: 'Delete categories and category groups',
|
|
85
|
+
category: 'api',
|
|
86
|
+
operationIds: ['deleteCategory'],
|
|
87
|
+
status: 'active',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'crypto_manual:read',
|
|
91
|
+
description: 'View supported cryptocurrencies and manually managed cryptocurrency balances',
|
|
92
|
+
category: 'api',
|
|
93
|
+
operationIds: ['getAllCryptocurrencies', 'getAllCryptoManual', 'getCryptoManualById'],
|
|
94
|
+
status: 'active',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'crypto_manual:create',
|
|
98
|
+
description: 'Add supported cryptocurrencies and create manually managed cryptocurrency balances',
|
|
99
|
+
category: 'api',
|
|
100
|
+
operationIds: ['createCryptocurrency', 'createCryptoManual'],
|
|
101
|
+
status: 'active',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'crypto_manual:update',
|
|
105
|
+
description: 'Update manually managed cryptocurrency balances',
|
|
106
|
+
category: 'api',
|
|
107
|
+
operationIds: ['updateCryptoManual'],
|
|
108
|
+
status: 'active',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'crypto_manual:delete',
|
|
112
|
+
description: 'Delete manually managed cryptocurrency balances',
|
|
113
|
+
category: 'api',
|
|
114
|
+
operationIds: ['deleteCryptoManual'],
|
|
115
|
+
status: 'active',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'crypto_synced:read',
|
|
119
|
+
description: 'View synced cryptocurrency accounts and balances',
|
|
120
|
+
category: 'api',
|
|
121
|
+
operationIds: ['getAllCryptoSynced', 'getCryptoSyncedById', 'getCryptoSyncedBalanceBySymbol'],
|
|
122
|
+
status: 'active',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'crypto_synced:update',
|
|
126
|
+
description: 'Refresh balances for synced cryptocurrency accounts',
|
|
127
|
+
category: 'api',
|
|
128
|
+
operationIds: ['refreshCryptoSynced'],
|
|
129
|
+
status: 'active',
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'balance_history:read',
|
|
133
|
+
description: 'View balance history for accounts and synced cryptocurrency balances',
|
|
134
|
+
category: 'api',
|
|
135
|
+
operationIds: ['getBalanceHistory', 'getBalanceHistoryForAccount', 'getBalanceHistoryForCryptoSynced'],
|
|
136
|
+
status: 'active',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'balance_history:update',
|
|
140
|
+
description: 'Create or update balance history and details for deleted accounts',
|
|
141
|
+
category: 'api',
|
|
142
|
+
operationIds: ['upsertBalanceHistoryForAccount', 'upsertBalanceHistoryForCryptoSynced', 'updateBalanceHistoryDetails'],
|
|
143
|
+
status: 'active',
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: 'balance_history:delete',
|
|
147
|
+
description: 'Delete balance history for accounts and synced cryptocurrency balances',
|
|
148
|
+
category: 'api',
|
|
149
|
+
operationIds: ['deleteBalanceHistoryForAccount', 'deleteBalanceHistoryForCryptoSynced', 'deleteBalanceHistoryEntry'],
|
|
150
|
+
status: 'active',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'manual_accounts:read',
|
|
154
|
+
description: 'View manually managed accounts',
|
|
155
|
+
category: 'api',
|
|
156
|
+
operationIds: ['getAllManualAccounts', 'getManualAccountById'],
|
|
157
|
+
status: 'active',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'manual_accounts:create',
|
|
161
|
+
description: 'Create manually managed accounts',
|
|
162
|
+
category: 'api',
|
|
163
|
+
operationIds: ['createManualAccount'],
|
|
164
|
+
status: 'active',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'manual_accounts:update',
|
|
168
|
+
description: 'Update manually managed accounts',
|
|
169
|
+
category: 'api',
|
|
170
|
+
operationIds: ['updateManualAccount'],
|
|
171
|
+
status: 'active',
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: 'manual_accounts:delete',
|
|
175
|
+
description: 'Delete manually managed accounts',
|
|
176
|
+
category: 'api',
|
|
177
|
+
operationIds: ['deleteManualAccount'],
|
|
178
|
+
status: 'active',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: 'plaid_accounts:read',
|
|
182
|
+
description: 'View accounts connected through Plaid',
|
|
183
|
+
category: 'api',
|
|
184
|
+
operationIds: ['getAllPlaidAccounts', 'getPlaidAccountById'],
|
|
185
|
+
status: 'active',
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: 'plaid_accounts:update',
|
|
189
|
+
description: 'Request a Plaid account refresh, which may import new transactions',
|
|
190
|
+
category: 'api',
|
|
191
|
+
operationIds: ['triggerPlaidAccountFetch'],
|
|
192
|
+
status: 'active',
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'transactions:read',
|
|
196
|
+
description: 'View transactions, including split and group information and attachment metadata',
|
|
197
|
+
category: 'api',
|
|
198
|
+
operationIds: ['getAllTransactions', 'getTransactionById'],
|
|
199
|
+
status: 'active',
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: 'transactions:create',
|
|
203
|
+
description: 'Create transactions',
|
|
204
|
+
category: 'api',
|
|
205
|
+
operationIds: ['createNewTransactions'],
|
|
206
|
+
status: 'active',
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'transactions:update',
|
|
210
|
+
description: 'Update, split, unsplit, group, and ungroup transactions',
|
|
211
|
+
category: 'api',
|
|
212
|
+
operationIds: ['updateTransactions', 'updateTransaction', 'groupTransactions', 'ungroupTransactions', 'splitTransaction', 'unsplitTransaction'],
|
|
213
|
+
status: 'active',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: 'transactions:delete',
|
|
217
|
+
description: 'Delete transactions',
|
|
218
|
+
category: 'api',
|
|
219
|
+
operationIds: ['deleteTransactions', 'deleteTransactionById'],
|
|
220
|
+
status: 'active',
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: 'transaction_attachments:read',
|
|
224
|
+
description: 'Get download access to transaction attachments',
|
|
225
|
+
category: 'api',
|
|
226
|
+
operationIds: ['getTransactionAttachmentUrl'],
|
|
227
|
+
status: 'active',
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: 'transaction_attachments:create',
|
|
231
|
+
description: 'Attach files to transactions',
|
|
232
|
+
category: 'api',
|
|
233
|
+
operationIds: ['attachFileToTransaction'],
|
|
234
|
+
status: 'active',
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: 'transaction_attachments:delete',
|
|
238
|
+
description: 'Delete transaction attachments',
|
|
239
|
+
category: 'api',
|
|
240
|
+
operationIds: ['deleteTransactionAttachment'],
|
|
241
|
+
status: 'active',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: 'tags:read',
|
|
245
|
+
description: 'View tags',
|
|
246
|
+
category: 'api',
|
|
247
|
+
operationIds: ['getAllTags', 'getTagById'],
|
|
248
|
+
status: 'active',
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: 'tags:create',
|
|
252
|
+
description: 'Create tags',
|
|
253
|
+
category: 'api',
|
|
254
|
+
operationIds: ['createTag'],
|
|
255
|
+
status: 'active',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: 'tags:update',
|
|
259
|
+
description: 'Update tags',
|
|
260
|
+
category: 'api',
|
|
261
|
+
operationIds: ['updateTag'],
|
|
262
|
+
status: 'active',
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: 'tags:delete',
|
|
266
|
+
description: 'Delete tags',
|
|
267
|
+
category: 'api',
|
|
268
|
+
operationIds: ['deleteTag'],
|
|
269
|
+
status: 'active',
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: 'recurring_items:read',
|
|
273
|
+
description: 'View recurring items',
|
|
274
|
+
category: 'api',
|
|
275
|
+
operationIds: ['getAllRecurring', 'getRecurringById'],
|
|
276
|
+
status: 'active',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: 'budgets:read',
|
|
280
|
+
description: 'View budget period settings',
|
|
281
|
+
category: 'api',
|
|
282
|
+
operationIds: ['getBudgetSettings'],
|
|
283
|
+
status: 'active',
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: 'budgets:update',
|
|
287
|
+
description: 'Create or update budget amounts',
|
|
288
|
+
category: 'api',
|
|
289
|
+
operationIds: ['upsertBudget'],
|
|
290
|
+
status: 'active',
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: 'budgets:delete',
|
|
294
|
+
description: 'Delete budget amounts',
|
|
295
|
+
category: 'api',
|
|
296
|
+
operationIds: ['deleteBudget'],
|
|
297
|
+
status: 'active',
|
|
298
|
+
},
|
|
299
|
+
];
|
|
300
|
+
exports.oauthScopes = Object.freeze(scopeDefinitions.map(freezeScope));
|
|
301
|
+
const allApiReadScopes = exports.oauthScopes
|
|
302
|
+
.filter((scope) => scope.category === 'api' && scope.name.endsWith(':read'))
|
|
303
|
+
.map((scope) => scope.name);
|
|
304
|
+
const allApiScopes = exports.oauthScopes
|
|
305
|
+
.filter((scope) => scope.category === 'api')
|
|
306
|
+
.map((scope) => scope.name);
|
|
307
|
+
const groupDefinitions = [
|
|
308
|
+
{
|
|
309
|
+
id: 'read_only',
|
|
310
|
+
name: 'Read only',
|
|
311
|
+
description: 'View all supported Lunch Money data without changing it',
|
|
312
|
+
scopes: allApiReadScopes,
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
id: 'transactions',
|
|
316
|
+
name: 'Transactions',
|
|
317
|
+
description: 'Import, export, organize, and manage transactions and their attachments',
|
|
318
|
+
scopes: [
|
|
319
|
+
'transactions:read',
|
|
320
|
+
'transactions:create',
|
|
321
|
+
'transactions:update',
|
|
322
|
+
'transactions:delete',
|
|
323
|
+
'transaction_attachments:read',
|
|
324
|
+
'transaction_attachments:create',
|
|
325
|
+
'transaction_attachments:delete',
|
|
326
|
+
'categories:read',
|
|
327
|
+
'tags:read',
|
|
328
|
+
'manual_accounts:read',
|
|
329
|
+
'plaid_accounts:read',
|
|
330
|
+
'recurring_items:read',
|
|
331
|
+
],
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
id: 'budgeting',
|
|
335
|
+
name: 'Budgeting',
|
|
336
|
+
description: 'Analyze and manage budgets, categories, and tags',
|
|
337
|
+
scopes: [
|
|
338
|
+
'summary:read',
|
|
339
|
+
'budgets:read',
|
|
340
|
+
'budgets:update',
|
|
341
|
+
'budgets:delete',
|
|
342
|
+
'categories:read',
|
|
343
|
+
'categories:create',
|
|
344
|
+
'categories:update',
|
|
345
|
+
'categories:delete',
|
|
346
|
+
'tags:read',
|
|
347
|
+
'tags:create',
|
|
348
|
+
'tags:update',
|
|
349
|
+
'tags:delete',
|
|
350
|
+
'recurring_items:read',
|
|
351
|
+
],
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
id: 'accounts',
|
|
355
|
+
name: 'Accounts',
|
|
356
|
+
description: 'Manage accounts, balances, and balance history',
|
|
357
|
+
scopes: [
|
|
358
|
+
'manual_accounts:read',
|
|
359
|
+
'manual_accounts:create',
|
|
360
|
+
'manual_accounts:update',
|
|
361
|
+
'manual_accounts:delete',
|
|
362
|
+
'plaid_accounts:read',
|
|
363
|
+
'plaid_accounts:update',
|
|
364
|
+
'crypto_manual:read',
|
|
365
|
+
'crypto_manual:create',
|
|
366
|
+
'crypto_manual:update',
|
|
367
|
+
'crypto_manual:delete',
|
|
368
|
+
'crypto_synced:read',
|
|
369
|
+
'crypto_synced:update',
|
|
370
|
+
'balance_history:read',
|
|
371
|
+
'balance_history:update',
|
|
372
|
+
'balance_history:delete',
|
|
373
|
+
],
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
id: 'organize',
|
|
377
|
+
name: 'Organize',
|
|
378
|
+
description: 'Manage categories and tags used to organize transactions',
|
|
379
|
+
scopes: [
|
|
380
|
+
'categories:read',
|
|
381
|
+
'categories:create',
|
|
382
|
+
'categories:update',
|
|
383
|
+
'categories:delete',
|
|
384
|
+
'tags:read',
|
|
385
|
+
'tags:create',
|
|
386
|
+
'tags:update',
|
|
387
|
+
'tags:delete',
|
|
388
|
+
'recurring_items:read',
|
|
389
|
+
],
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
id: 'full_access',
|
|
393
|
+
name: 'Full access',
|
|
394
|
+
description: 'View and manage all supported Lunch Money data',
|
|
395
|
+
scopes: allApiScopes,
|
|
396
|
+
},
|
|
397
|
+
];
|
|
398
|
+
exports.oauthScopeGroups = Object.freeze(groupDefinitions.map(freezeGroup));
|
|
399
|
+
const scopeByName = new Map(exports.oauthScopes.map((scope) => [scope.name, scope]));
|
|
400
|
+
const groupById = new Map(exports.oauthScopeGroups.map((group) => [group.id, group]));
|
|
401
|
+
const scopeByOperationId = new Map(exports.oauthScopes.flatMap((scope) => scope.operationIds.map((operationId) => [operationId, scope])));
|
|
402
|
+
exports.oauthCatalog = Object.freeze({
|
|
403
|
+
scopes: exports.oauthScopes,
|
|
404
|
+
groups: exports.oauthScopeGroups,
|
|
405
|
+
});
|
|
406
|
+
function getOAuthScopeDefinition(name) {
|
|
407
|
+
return scopeByName.get(name);
|
|
408
|
+
}
|
|
409
|
+
function getOAuthScopeGroup(id) {
|
|
410
|
+
return groupById.get(id);
|
|
411
|
+
}
|
|
412
|
+
function getOAuthScopeForOperationId(operationId) {
|
|
413
|
+
return scopeByOperationId.get(operationId);
|
|
414
|
+
}
|
|
415
|
+
const canonicalSet = (values) => [...values].sort().join('\u0000');
|
|
416
|
+
const SCOPE_NAME_PATTERN = /^(?:openid|email|profile|offline_access|[a-z][a-z0-9_]*:(?:read|create|update|delete))$/;
|
|
417
|
+
const GROUP_ID_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
418
|
+
function matchOAuthScopeGroup(scopeNames) {
|
|
419
|
+
const names = new Set(scopeNames);
|
|
420
|
+
if (names.size !== scopeNames.length)
|
|
421
|
+
return { status: 'no_match', reason: 'duplicate_scope' };
|
|
422
|
+
if (scopeNames.some((name) => !getOAuthScopeDefinition(name))) {
|
|
423
|
+
return { status: 'no_match', reason: 'unknown_scope' };
|
|
424
|
+
}
|
|
425
|
+
const candidate = canonicalSet(scopeNames);
|
|
426
|
+
const group = exports.oauthScopeGroups.find((definition) => canonicalSet(definition.scopes) === candidate);
|
|
427
|
+
return group ? { status: 'matched', group } : { status: 'no_match', reason: 'no_exact_match' };
|
|
428
|
+
}
|
|
429
|
+
function validateOAuthCatalog(definition, options = {}) {
|
|
430
|
+
const issues = [];
|
|
431
|
+
const scopeNames = new Set();
|
|
432
|
+
const groupIds = new Set();
|
|
433
|
+
const groupSets = new Map();
|
|
434
|
+
const operationOwners = new Map();
|
|
435
|
+
definition.scopes.forEach((scope, index) => {
|
|
436
|
+
const path = `scopes[${index}]`;
|
|
437
|
+
if (!SCOPE_NAME_PATTERN.test(scope.name)) {
|
|
438
|
+
issues.push({ code: 'invalid_scope_name', path: `${path}.name`, message: `Invalid scope name: ${scope.name}` });
|
|
439
|
+
}
|
|
440
|
+
if (!scope.description.trim()) {
|
|
441
|
+
issues.push({ code: 'missing_description', path: `${path}.description`, message: `Scope ${scope.name} requires a description` });
|
|
442
|
+
}
|
|
443
|
+
if (scopeNames.has(scope.name)) {
|
|
444
|
+
issues.push({ code: 'duplicate_scope_name', path: `${path}.name`, message: `Duplicate scope name: ${scope.name}` });
|
|
445
|
+
}
|
|
446
|
+
scopeNames.add(scope.name);
|
|
447
|
+
if (!['identity', 'offline', 'api'].includes(scope.category)) {
|
|
448
|
+
issues.push({ code: 'invalid_category', path: `${path}.category`, message: `Invalid category: ${scope.category}` });
|
|
449
|
+
}
|
|
450
|
+
if (!['active', 'deprecated', 'retired'].includes(scope.status)) {
|
|
451
|
+
issues.push({ code: 'invalid_lifecycle', path: `${path}.status`, message: `Invalid lifecycle: ${scope.status}` });
|
|
452
|
+
}
|
|
453
|
+
if (scope.category === 'api' && scope.status !== 'retired' && scope.operationIds.length === 0) {
|
|
454
|
+
issues.push({ code: 'missing_operation_ids', path: `${path}.operationIds`, message: `API scope ${scope.name} has no operationIds` });
|
|
455
|
+
}
|
|
456
|
+
if (scope.category !== 'api' && scope.operationIds.length > 0) {
|
|
457
|
+
issues.push({ code: 'unexpected_operation_ids', path: `${path}.operationIds`, message: `Protocol scope ${scope.name} cannot own V2 operationIds` });
|
|
458
|
+
}
|
|
459
|
+
const localIds = new Set();
|
|
460
|
+
scope.operationIds.forEach((operationId, operationIndex) => {
|
|
461
|
+
const operationPath = `${path}.operationIds[${operationIndex}]`;
|
|
462
|
+
if (localIds.has(operationId)) {
|
|
463
|
+
issues.push({ code: 'duplicate_operation_id', path: operationPath, message: `Duplicate operationId: ${operationId}` });
|
|
464
|
+
}
|
|
465
|
+
localIds.add(operationId);
|
|
466
|
+
const owner = operationOwners.get(operationId);
|
|
467
|
+
if (owner && owner !== scope.name) {
|
|
468
|
+
issues.push({ code: 'conflicting_operation_id', path: operationPath, message: `${operationId} is assigned to both ${owner} and ${scope.name}` });
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
operationOwners.set(operationId, scope.name);
|
|
472
|
+
}
|
|
473
|
+
if (options.knownOperationIds && !options.knownOperationIds.has(operationId)) {
|
|
474
|
+
issues.push({ code: 'unknown_operation_id', path: operationPath, message: `Unknown V2 operationId: ${operationId}` });
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
definition.groups.forEach((group, index) => {
|
|
479
|
+
const path = `groups[${index}]`;
|
|
480
|
+
if (!GROUP_ID_PATTERN.test(group.id)) {
|
|
481
|
+
issues.push({ code: 'invalid_group_id', path: `${path}.id`, message: `Invalid group ID: ${group.id}` });
|
|
482
|
+
}
|
|
483
|
+
if (!group.description.trim()) {
|
|
484
|
+
issues.push({ code: 'missing_description', path: `${path}.description`, message: `Group ${group.id} requires a description` });
|
|
485
|
+
}
|
|
486
|
+
if (groupIds.has(group.id)) {
|
|
487
|
+
issues.push({ code: 'duplicate_group_id', path: `${path}.id`, message: `Duplicate group ID: ${group.id}` });
|
|
488
|
+
}
|
|
489
|
+
groupIds.add(group.id);
|
|
490
|
+
if (group.scopes.length === 0) {
|
|
491
|
+
issues.push({ code: 'empty_group', path: `${path}.scopes`, message: `Group ${group.id} cannot be empty` });
|
|
492
|
+
}
|
|
493
|
+
const members = new Set();
|
|
494
|
+
group.scopes.forEach((scopeName, scopeIndex) => {
|
|
495
|
+
const memberPath = `${path}.scopes[${scopeIndex}]`;
|
|
496
|
+
if (members.has(scopeName)) {
|
|
497
|
+
issues.push({ code: 'duplicate_group_scope', path: memberPath, message: `Duplicate group scope: ${scopeName}` });
|
|
498
|
+
}
|
|
499
|
+
members.add(scopeName);
|
|
500
|
+
const scope = definition.scopes.find((candidate) => candidate.name === scopeName);
|
|
501
|
+
if (!scope) {
|
|
502
|
+
issues.push({ code: 'unknown_group_scope', path: memberPath, message: `Unknown group scope: ${scopeName}` });
|
|
503
|
+
}
|
|
504
|
+
else if (scope.status === 'retired') {
|
|
505
|
+
issues.push({ code: 'retired_group_scope', path: memberPath, message: `Retired scope cannot be grouped: ${scopeName}` });
|
|
506
|
+
}
|
|
507
|
+
else if (scope.category === 'offline') {
|
|
508
|
+
issues.push({ code: 'offline_scope_in_group', path: memberPath, message: `Offline scope cannot be grouped: ${scopeName}` });
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
const setKey = canonicalSet(group.scopes);
|
|
512
|
+
const existingGroup = groupSets.get(setKey);
|
|
513
|
+
if (existingGroup) {
|
|
514
|
+
issues.push({ code: 'duplicate_group_members', path: `${path}.scopes`, message: `${group.id} has the same members as ${existingGroup}` });
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
groupSets.set(setKey, group.id);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
if (options.operationIdCoverage === 'require-all-mapped' && options.knownOperationIds) {
|
|
521
|
+
for (const operationId of options.knownOperationIds) {
|
|
522
|
+
if (!operationOwners.has(operationId)) {
|
|
523
|
+
issues.push({ code: 'unmapped_operation_id', path: 'scopes', message: `Unmapped V2 operationId: ${operationId}` });
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return Object.freeze({ valid: issues.length === 0, issues: Object.freeze(issues) });
|
|
528
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { getOAuthScopeDefinition, getOAuthScopeForOperationId, getOAuthScopeGroup, matchOAuthScopeGroup, oauthCatalog, oauthScopeGroups, oauthScopes, validateOAuthCatalog, } from './catalog';
|
|
2
|
+
export type { KnownOAuthScopeName, OAuthApiScopeAction, OAuthCatalogDefinition, OAuthCatalogIssue, OAuthCatalogIssueCode, OAuthCatalogValidationOptions, OAuthCatalogValidationResult, OAuthScopeCategory, OAuthScopeDefinition, OAuthScopeGroupDefinition, OAuthScopeGroupMatch, OAuthScopeLifecycle, OAuthScopeName, OAuthScopeResource, } from './types';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateOAuthCatalog = exports.oauthScopes = exports.oauthScopeGroups = exports.oauthCatalog = exports.matchOAuthScopeGroup = exports.getOAuthScopeGroup = exports.getOAuthScopeForOperationId = exports.getOAuthScopeDefinition = void 0;
|
|
4
|
+
var catalog_1 = require("./catalog");
|
|
5
|
+
Object.defineProperty(exports, "getOAuthScopeDefinition", { enumerable: true, get: function () { return catalog_1.getOAuthScopeDefinition; } });
|
|
6
|
+
Object.defineProperty(exports, "getOAuthScopeForOperationId", { enumerable: true, get: function () { return catalog_1.getOAuthScopeForOperationId; } });
|
|
7
|
+
Object.defineProperty(exports, "getOAuthScopeGroup", { enumerable: true, get: function () { return catalog_1.getOAuthScopeGroup; } });
|
|
8
|
+
Object.defineProperty(exports, "matchOAuthScopeGroup", { enumerable: true, get: function () { return catalog_1.matchOAuthScopeGroup; } });
|
|
9
|
+
Object.defineProperty(exports, "oauthCatalog", { enumerable: true, get: function () { return catalog_1.oauthCatalog; } });
|
|
10
|
+
Object.defineProperty(exports, "oauthScopeGroups", { enumerable: true, get: function () { return catalog_1.oauthScopeGroups; } });
|
|
11
|
+
Object.defineProperty(exports, "oauthScopes", { enumerable: true, get: function () { return catalog_1.oauthScopes; } });
|
|
12
|
+
Object.defineProperty(exports, "validateOAuthCatalog", { enumerable: true, get: function () { return catalog_1.validateOAuthCatalog; } });
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type OAuthScopeCategory = 'identity' | 'offline' | 'api';
|
|
2
|
+
export type OAuthScopeLifecycle = 'active' | 'deprecated' | 'retired';
|
|
3
|
+
export type OAuthApiScopeAction = 'read' | 'create' | 'update' | 'delete';
|
|
4
|
+
export type OAuthScopeResource = 'me' | 'summary' | 'categories' | 'crypto_manual' | 'crypto_synced' | 'balance_history' | 'manual_accounts' | 'plaid_accounts' | 'transactions' | 'transaction_attachments' | 'tags' | 'recurring_items' | 'budgets';
|
|
5
|
+
/**
|
|
6
|
+
* Durable scope names currently recognized by this catalog version.
|
|
7
|
+
* Persisted and API-facing scope values remain strings so newer names can be
|
|
8
|
+
* preserved and reported as unknown by consumers with an older catalog.
|
|
9
|
+
*/
|
|
10
|
+
export type KnownOAuthScopeName = 'openid' | 'email' | 'profile' | 'offline_access' | 'me:read' | 'me:update' | 'summary:read' | 'categories:read' | 'categories:create' | 'categories:update' | 'categories:delete' | 'crypto_manual:read' | 'crypto_manual:create' | 'crypto_manual:update' | 'crypto_manual:delete' | 'crypto_synced:read' | 'crypto_synced:update' | 'balance_history:read' | 'balance_history:update' | 'balance_history:delete' | 'manual_accounts:read' | 'manual_accounts:create' | 'manual_accounts:update' | 'manual_accounts:delete' | 'plaid_accounts:read' | 'plaid_accounts:update' | 'transactions:read' | 'transactions:create' | 'transactions:update' | 'transactions:delete' | 'transaction_attachments:read' | 'transaction_attachments:create' | 'transaction_attachments:delete' | 'tags:read' | 'tags:create' | 'tags:update' | 'tags:delete' | 'recurring_items:read' | 'budgets:read' | 'budgets:update' | 'budgets:delete';
|
|
11
|
+
export type OAuthScopeName = string;
|
|
12
|
+
export interface OAuthScopeDefinition {
|
|
13
|
+
readonly name: KnownOAuthScopeName;
|
|
14
|
+
readonly description: string;
|
|
15
|
+
readonly category: OAuthScopeCategory;
|
|
16
|
+
readonly operationIds: readonly string[];
|
|
17
|
+
readonly status: OAuthScopeLifecycle;
|
|
18
|
+
readonly lifecycleNotice?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface OAuthScopeGroupDefinition {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly description: string;
|
|
24
|
+
readonly scopes: readonly KnownOAuthScopeName[];
|
|
25
|
+
}
|
|
26
|
+
export interface OAuthCatalogDefinition {
|
|
27
|
+
readonly scopes: readonly OAuthScopeDefinition[];
|
|
28
|
+
readonly groups: readonly OAuthScopeGroupDefinition[];
|
|
29
|
+
}
|
|
30
|
+
export type OAuthCatalogIssueCode = 'invalid_scope_name' | 'invalid_group_id' | 'missing_description' | 'duplicate_scope_name' | 'duplicate_group_id' | 'duplicate_group_members' | 'duplicate_group_scope' | 'empty_group' | 'invalid_category' | 'invalid_lifecycle' | 'missing_operation_ids' | 'unexpected_operation_ids' | 'duplicate_operation_id' | 'conflicting_operation_id' | 'unknown_group_scope' | 'retired_group_scope' | 'offline_scope_in_group' | 'unknown_operation_id' | 'unmapped_operation_id';
|
|
31
|
+
export interface OAuthCatalogIssue {
|
|
32
|
+
readonly code: OAuthCatalogIssueCode;
|
|
33
|
+
readonly path: string;
|
|
34
|
+
readonly message: string;
|
|
35
|
+
}
|
|
36
|
+
export interface OAuthCatalogValidationOptions {
|
|
37
|
+
readonly knownOperationIds?: ReadonlySet<string>;
|
|
38
|
+
readonly operationIdCoverage?: 'allow-unmapped' | 'require-all-mapped';
|
|
39
|
+
}
|
|
40
|
+
export interface OAuthCatalogValidationResult {
|
|
41
|
+
readonly valid: boolean;
|
|
42
|
+
readonly issues: readonly OAuthCatalogIssue[];
|
|
43
|
+
}
|
|
44
|
+
export type OAuthScopeGroupMatch = {
|
|
45
|
+
readonly status: 'matched';
|
|
46
|
+
readonly group: OAuthScopeGroupDefinition;
|
|
47
|
+
} | {
|
|
48
|
+
readonly status: 'no_match';
|
|
49
|
+
readonly reason: 'duplicate_scope' | 'unknown_scope' | 'no_exact_match';
|
|
50
|
+
};
|
package/package.json
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunch-money/v2-api-spec",
|
|
3
|
-
"version": "2.11.1-preview.
|
|
3
|
+
"version": "2.11.1-preview.9",
|
|
4
4
|
"description": "OpenAPI specification and version history for the Lunch Money v2 API",
|
|
5
5
|
"main": "lunch-money-api-v2.yaml",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./lunch-money-api-v2.yaml",
|
|
8
|
+
"./lunch-money-api-v2.yaml": "./lunch-money-api-v2.yaml",
|
|
9
|
+
"./version-history.md": "./version-history.md",
|
|
10
|
+
"./oauth-scopes": {
|
|
11
|
+
"types": "./oauth-scopes/index.d.ts",
|
|
12
|
+
"require": "./oauth-scopes/index.js",
|
|
13
|
+
"default": "./oauth-scopes/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json",
|
|
16
|
+
"./*": "./*"
|
|
17
|
+
},
|
|
6
18
|
"files": [
|
|
7
19
|
"lunch-money-api-v2.yaml",
|
|
8
20
|
"version-history.md",
|
|
21
|
+
"oauth-scopes",
|
|
9
22
|
"README.md"
|
|
10
23
|
],
|
|
11
24
|
"scripts": {
|
|
12
25
|
"prepare": "husky install",
|
|
13
|
-
"
|
|
26
|
+
"build:oauth-scopes": "tsc -p tsconfig.oauth-scopes.json",
|
|
27
|
+
"test:oauth-scopes": "npm run build:oauth-scopes && node --test test/oauth-scopes/*.test.js",
|
|
28
|
+
"prepublishOnly": "npm run build:oauth-scopes && node scripts/prep-for-publish.js",
|
|
14
29
|
"postpublish": "node scripts/restore-readme.js",
|
|
15
30
|
"publish:docs": "node scripts/publish-docs.js --tag preview",
|
|
16
31
|
"publish:spec": "node scripts/publish-spec.js --tag preview",
|
|
@@ -30,6 +45,8 @@
|
|
|
30
45
|
"author": "",
|
|
31
46
|
"license": "ISC",
|
|
32
47
|
"devDependencies": {
|
|
33
|
-
"husky": "^8.0.3"
|
|
48
|
+
"husky": "^8.0.3",
|
|
49
|
+
"typescript": "^5.9.0",
|
|
50
|
+
"yaml": "^2.8.0"
|
|
34
51
|
}
|
|
35
52
|
}
|
package/version-history.md
CHANGED
|
@@ -6,8 +6,13 @@ The Lunch Money API spec uses a modified version of SEMVER for its versioning me
|
|
|
6
6
|
- The revision number represents the number of updates since the last endpoint was added. For example, each time changes are made to one of the existing three APIs as described above, the revision number will be bumped.
|
|
7
7
|
|
|
8
8
|
## v2.11.1 - TBD
|
|
9
|
+
- Add the OAuth scope and scope-group catalog mapped to V2 `operationId` values
|
|
9
10
|
- Add `GET /me/account/settings` and `PUT /me/account/settings` for account-level settings
|
|
10
11
|
- Add `GET /me/user/settings` and `PUT /me/user/settings` for user-level display and formatting preferences
|
|
12
|
+
- Add `GET /me/user/account/settings` and `PUT /me/user/account/settings` for settings specific to a user and budgeting account
|
|
13
|
+
from `GET /me/account/settings` and `PUT /me/account/settings` to `GET /me/user/account/settings` and `PUT /me/user/account/settings`
|
|
14
|
+
- Add `include_pending_in_totals` to `GET /me/account/settings` and `PUT /me/account/settings`
|
|
15
|
+
- Add `default_manual_account_id` to `GET /me/user/account/settings` and `PUT /me/user/account/settings`
|
|
11
16
|
- Document `GET /budgets/settings` response schema publicly; change `budget_period_quantity` to integer
|
|
12
17
|
|
|
13
18
|
## v2.11.0 - Jul 31, 2026
|