fragment-dev 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FragmentSDK
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,122 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require 'json'
5
+ require 'graphql/client'
6
+ require 'graphql/client/http'
7
+ require 'sorbet-runtime'
8
+ require 'uri'
9
+ require 'net/http'
10
+ require 'fragment_client/version'
11
+
12
+ # A support module for the client
13
+ module FragmentGraphQl
14
+ VERSION = FragmentSDK::VERSION
15
+ extend T::Sig
16
+
17
+ CustomHTTP = Class.new(GraphQL::Client::HTTP) do
18
+ extend T::Sig
19
+ sig { params(context: T.untyped).returns(T::Hash[T.untyped, T.untyped]) }
20
+ def headers(context)
21
+ { 'Authorization' => format('Bearer %s', context[:access_token]),
22
+ 'X-Fragment-Client' => format('ruby-client@%s', FragmentGraphQl::VERSION) }
23
+ end
24
+ end
25
+
26
+ HTTP = T.let(CustomHTTP.new('https://api.fragment.dev/graphql'), GraphQL::Client::HTTP)
27
+
28
+ FragmentSchema = T.let(GraphQL::Client.load_schema("#{__dir__}/fragment.schema.json"), T.untyped)
29
+
30
+ Client = T.let(GraphQL::Client.new(schema: FragmentSchema, execute: HTTP), GraphQL::Client)
31
+
32
+ FragmentQueries = T.let(Client.parse(
33
+ File.read("#{__dir__}/queries.graphql")
34
+ ), T.untyped)
35
+ end
36
+
37
+ # A client for Fragment
38
+ class FragmentClient
39
+ # A token for the client with an expiry time
40
+ class Token < T::Struct
41
+ const :token, String
42
+ const :expires_at, Time
43
+ end
44
+
45
+ extend T::Sig
46
+
47
+ sig do
48
+ params(client_id: String, client_secret: String, extra_queries_filename: T.nilable(String),
49
+ api_url: T.nilable(String), oauth_url: T.nilable(String), oauth_scope: T.nilable(String)).void
50
+ end
51
+ def initialize(client_id, client_secret, extra_queries_filename: nil, api_url: nil,
52
+ oauth_url: 'https://auth.fragment.dev/oauth2/token', oauth_scope: 'https://api.fragment.dev/*')
53
+ @oauth_scope = T.let(oauth_scope, String)
54
+ @oauth_url = T.let(URI.parse(oauth_url), URI)
55
+ @client_id = T.let(client_id, String)
56
+ @client_secret = T.let(client_secret, String)
57
+
58
+ execute = api_url ? FragmentGraphQl::CustomHTTP.new(URI.parse(api_url).to_s) : FragmentGraphQl::HTTP
59
+ @execute = T.let(execute, GraphQL::Client::HTTP)
60
+
61
+ @client = T.let(GraphQL::Client.new(schema: FragmentGraphQl::FragmentSchema, execute: @execute), GraphQL::Client)
62
+ @token = T.let(create_token, Token)
63
+
64
+ define_method_from_queries(FragmentGraphQl::FragmentQueries)
65
+ return if extra_queries_filename.nil?
66
+
67
+ queries = @client.parse(
68
+ File.read(extra_queries_filename)
69
+ )
70
+ define_method_from_queries(queries)
71
+ end
72
+
73
+ sig { params(query: T.untyped, variables: T.untyped).returns(T.untyped) }
74
+ def query(query, variables)
75
+ expiry_time_skew = 120
76
+ @token = create_token if Time.now > @token.expires_at - expiry_time_skew
77
+ puts query
78
+ @client.query(query, variables: variables, context: { access_token: @token.token })
79
+ end
80
+
81
+ private
82
+
83
+ def define_method_from_queries(queries)
84
+ queries.constants.each do |qry|
85
+ name = qry.to_s.gsub(/[a-z]([A-Z])/) do |m|
86
+ format('%<lower>s_%<upper>s', lower: m[0], upper: m[1].downcase)
87
+ end.gsub(/^[A-Z]/, &:downcase)
88
+ define_singleton_method(name) do |v|
89
+ query(queries.const_get(qry), v)
90
+ end
91
+ end
92
+ end
93
+
94
+ sig { returns(Token) }
95
+ def create_token
96
+ uri = URI.parse(@oauth_url.to_s)
97
+ post = Net::HTTP::Post.new(uri.to_s)
98
+ post.basic_auth(@client_id, @client_secret)
99
+ post.body = format('grant_type=client_credentials&scope=%<scope>s&client_id=%<id>s', scope: @oauth_scope,
100
+ id: @client_id)
101
+
102
+ begin
103
+ http = Net::HTTP.new(uri.host, uri.port)
104
+ http.use_ssl = true if uri.scheme == 'https'
105
+ response = http.request(post)
106
+
107
+ case response
108
+ when Net::HTTPSuccess
109
+ # Parse the response body
110
+ body = JSON.parse(response.body)
111
+ Token.new(
112
+ token: T.let(body['access_token'], String),
113
+ expires_at: Time.now + T.let(body['expires_in'], Integer)
114
+ )
115
+ else
116
+ raise StandardError, format("oauth Authentication failed: '%s'", response.body)
117
+ end
118
+ rescue StandardError => e
119
+ raise StandardError, format("oauth Authentication failed: '%s'", e.to_s)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,6 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ # A client for Fragment
5
+ class FragmentClient
6
+ end
@@ -0,0 +1,513 @@
1
+ mutation StoreSchema($schema: SchemaInput!) {
2
+ storeSchema(schema: $schema) {
3
+ __typename
4
+ ... on StoreSchemaResult {
5
+ schema {
6
+ key
7
+ name
8
+ version {
9
+ created
10
+ version
11
+ }
12
+ }
13
+ }
14
+ ... on Error {
15
+ code
16
+ message
17
+ }
18
+ }
19
+ }
20
+
21
+ mutation CreateLedger(
22
+ $ik: SafeString!
23
+ $ledger: CreateLedgerInput!
24
+ $schemaKey: SafeString!
25
+ ) {
26
+ createLedger(ik: $ik, ledger: $ledger, schema: { key: $schemaKey }) {
27
+ __typename
28
+ ... on CreateLedgerResult {
29
+ ledger {
30
+ id
31
+ ik
32
+ name
33
+ created
34
+ schema {
35
+ key
36
+ }
37
+ }
38
+ isIkReplay
39
+ }
40
+ ... on Error {
41
+ code
42
+ message
43
+ }
44
+ }
45
+ }
46
+
47
+ mutation AddLedgerEntry(
48
+ $ik: SafeString!
49
+ $ledgerIk: SafeString!
50
+ $type: String!
51
+ $posted: DateTime
52
+ $parameters: JSON!
53
+ $tags: [LedgerEntryTagInput!]
54
+ $groups: [LedgerEntryGroupInput!]
55
+ ) {
56
+ addLedgerEntry(
57
+ ik: $ik
58
+ entry: {
59
+ ledger: { ik: $ledgerIk }
60
+ type: $type
61
+ posted: $posted
62
+ parameters: $parameters
63
+ tags: $tags
64
+ groups: $groups
65
+ }
66
+ ) {
67
+ __typename
68
+ ... on AddLedgerEntryResult {
69
+ isIkReplay
70
+ entry {
71
+ type
72
+ id
73
+ ik
74
+ posted
75
+ created
76
+ }
77
+ lines {
78
+ id
79
+ amount
80
+ account {
81
+ path
82
+ }
83
+ }
84
+ }
85
+ ... on Error {
86
+ code
87
+ message
88
+ }
89
+ }
90
+ }
91
+
92
+ mutation AddLedgerEntryRuntime(
93
+ $ik: SafeString!
94
+ $type: String!
95
+ $ledgerIk: SafeString!
96
+ $posted: DateTime
97
+ $lines: [LedgerLineInput!]!
98
+ $tags: [LedgerEntryTagInput!]
99
+ $groups: [LedgerEntryGroupInput!]
100
+ ) {
101
+ addLedgerEntry(
102
+ ik: $ik
103
+ entry: {
104
+ type: $type
105
+ ledger: { ik: $ledgerIk }
106
+ posted: $posted
107
+ lines: $lines
108
+ tags: $tags
109
+ groups: $groups
110
+ }
111
+ ) {
112
+ __typename
113
+ ... on AddLedgerEntryResult {
114
+ isIkReplay
115
+ entry {
116
+ type
117
+ id
118
+ ik
119
+ posted
120
+ created
121
+ }
122
+ lines {
123
+ id
124
+ amount
125
+ account {
126
+ path
127
+ }
128
+ }
129
+ }
130
+ ... on Error {
131
+ code
132
+ message
133
+ }
134
+ }
135
+ }
136
+
137
+ mutation ReconcileTx(
138
+ $ledgerIk: SafeString!
139
+ $type: String!
140
+ $parameters: JSON!
141
+ $tags: [LedgerEntryTagInput!]
142
+ $groups: [LedgerEntryGroupInput!]
143
+ ) {
144
+ reconcileTx(
145
+ entry: {
146
+ ledger: { ik: $ledgerIk }
147
+ type: $type
148
+ parameters: $parameters
149
+ tags: $tags
150
+ groups: $groups
151
+ }
152
+ ) {
153
+ __typename
154
+ ... on ReconcileTxResult {
155
+ entry {
156
+ id
157
+ ik
158
+ date
159
+ posted
160
+ created
161
+ description
162
+ }
163
+ lines {
164
+ id
165
+ amount
166
+ account {
167
+ path
168
+ }
169
+ externalTxId
170
+ }
171
+ }
172
+ ... on Error {
173
+ code
174
+ message
175
+ }
176
+ }
177
+ }
178
+
179
+ mutation ReconcileTxRuntime(
180
+ $ledgerIk: SafeString!
181
+ $type: String!
182
+ $lines: [LedgerLineInput!]!
183
+ $tags: [LedgerEntryTagInput!]
184
+ $groups: [LedgerEntryGroupInput!]
185
+ ) {
186
+ reconcileTx(
187
+ entry: {
188
+ ledger: { ik: $ledgerIk }
189
+ type: $type
190
+ lines: $lines
191
+ tags: $tags
192
+ groups: $groups
193
+ }
194
+ ) {
195
+ __typename
196
+ ... on ReconcileTxResult {
197
+ entry {
198
+ id
199
+ ik
200
+ date
201
+ posted
202
+ created
203
+ description
204
+ }
205
+ lines {
206
+ id
207
+ amount
208
+ account {
209
+ path
210
+ }
211
+ externalTxId
212
+ }
213
+ }
214
+ ... on Error {
215
+ code
216
+ message
217
+ }
218
+ }
219
+ }
220
+
221
+ mutation UpdateLedger($ledgerIk: SafeString!, $update: UpdateLedgerInput!) {
222
+ updateLedger(ledger: { ik: $ledgerIk }, update: $update) {
223
+ __typename
224
+ ... on UpdateLedgerResult {
225
+ ledger {
226
+ id
227
+ ik
228
+ name
229
+ }
230
+ }
231
+ ... on Error {
232
+ code
233
+ message
234
+ }
235
+ }
236
+ }
237
+ mutation CreateCustomLink($name: String!, $ik: SafeString!) {
238
+ createCustomLink(name: $name, ik: $ik) {
239
+ __typename
240
+ ... on CreateCustomLinkResult {
241
+ link {
242
+ id
243
+ name
244
+ created
245
+ }
246
+ isIkReplay
247
+ }
248
+ ... on Error {
249
+ code
250
+ message
251
+ }
252
+ }
253
+ }
254
+
255
+ mutation SyncCustomAccounts($linkId: ID!, $accounts: [CustomAccountInput!]!) {
256
+ syncCustomAccounts(link: { id: $linkId }, accounts: $accounts) {
257
+ __typename
258
+ ... on SyncCustomAccountsResult {
259
+ accounts {
260
+ id
261
+ externalId
262
+ name
263
+ currency {
264
+ code
265
+ customCurrencyId
266
+ }
267
+ }
268
+ }
269
+ ... on Error {
270
+ code
271
+ message
272
+ }
273
+ }
274
+ }
275
+
276
+ mutation SyncCustomTxs($linkId: ID!, $txs: [CustomTxInput!]!) {
277
+ syncCustomTxs(link: { id: $linkId }, txs: $txs) {
278
+ __typename
279
+ ... on SyncCustomTxsResult {
280
+ txs {
281
+ __typename
282
+ linkId
283
+ id
284
+ externalId
285
+ externalAccountId
286
+ amount
287
+ description
288
+ posted
289
+ }
290
+ }
291
+ ... on Error {
292
+ code
293
+ message
294
+ }
295
+ }
296
+ }
297
+
298
+ query GetLedger($ik: SafeString!) {
299
+ ledger(ledger: { ik: $ik }) {
300
+ id
301
+ ik
302
+ name
303
+ created
304
+ balanceUTCOffset
305
+ }
306
+ }
307
+
308
+ query GetLedgerEntry($ik: SafeString!, $ledgerIk: SafeString!) {
309
+ ledgerEntry(ledgerEntry: { ik: $ik, ledger: { ik: $ledgerIk } }) {
310
+ id
311
+ ik
312
+ posted
313
+ created
314
+ description
315
+ lines {
316
+ nodes {
317
+ id
318
+ amount
319
+ account {
320
+ path
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
326
+
327
+ query ListLedgerAccounts(
328
+ $ledgerIk: SafeString!
329
+ $after: String
330
+ $first: Int
331
+ $before: String
332
+ ) {
333
+ ledger(ledger: { ik: $ledgerIk }) {
334
+ id
335
+ ik
336
+ name
337
+ created
338
+ ledgerAccounts(after: $after, first: $first, before: $before) {
339
+ nodes {
340
+ id
341
+ path
342
+ name
343
+ type
344
+ created
345
+ }
346
+ pageInfo {
347
+ hasNextPage
348
+ endCursor
349
+ hasPreviousPage
350
+ startCursor
351
+ }
352
+ }
353
+ }
354
+ }
355
+
356
+ query ListLedgerAccountBalances(
357
+ $ledgerIk: SafeString!
358
+ $after: String
359
+ $first: Int
360
+ $before: String
361
+ $balanceCurrency: CurrencyMatchInput
362
+ $balanceAt: LastMoment
363
+ $ownBalanceConsistencyMode: ReadBalanceConsistencyMode
364
+ ) {
365
+ ledger(ledger: { ik: $ledgerIk }) {
366
+ id
367
+ ik
368
+ name
369
+ created
370
+ ledgerAccounts(after: $after, first: $first, before: $before) {
371
+ nodes {
372
+ id
373
+ path
374
+ name
375
+ type
376
+ created
377
+ ownBalance(
378
+ currency: $balanceCurrency
379
+ at: $balanceAt
380
+ consistencyMode: $ownBalanceConsistencyMode
381
+ )
382
+ childBalance(currency: $balanceCurrency, at: $balanceAt)
383
+ balance(currency: $balanceCurrency, at: $balanceAt)
384
+ }
385
+ pageInfo {
386
+ hasNextPage
387
+ endCursor
388
+ hasPreviousPage
389
+ startCursor
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
+ query ListMultiCurrencyLedgerAccountBalances(
396
+ $ledgerIk: SafeString!
397
+ $after: String
398
+ $first: Int
399
+ $before: String
400
+ $balanceAt: LastMoment
401
+ $ownBalancesConsistencyMode: ReadBalanceConsistencyMode
402
+ ) {
403
+ ledger(ledger: { ik: $ledgerIk }) {
404
+ id
405
+ ik
406
+ name
407
+ created
408
+ ledgerAccounts(after: $after, first: $first, before: $before) {
409
+ nodes {
410
+ id
411
+ path
412
+ name
413
+ type
414
+ created
415
+ ownBalances(
416
+ at: $balanceAt
417
+ consistencyMode: $ownBalancesConsistencyMode
418
+ ) {
419
+ nodes {
420
+ currency {
421
+ code
422
+ customCurrencyId
423
+ }
424
+ amount
425
+ }
426
+ }
427
+ childBalances(at: $balanceAt) {
428
+ nodes {
429
+ currency {
430
+ code
431
+ customCurrencyId
432
+ }
433
+ amount
434
+ }
435
+ }
436
+ balances(at: $balanceAt) {
437
+ nodes {
438
+ currency {
439
+ code
440
+ customCurrencyId
441
+ }
442
+ amount
443
+ }
444
+ }
445
+ }
446
+ pageInfo {
447
+ hasNextPage
448
+ endCursor
449
+ hasPreviousPage
450
+ startCursor
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ query GetLedgerAccountLines(
457
+ $path: String!
458
+ $ledgerIk: SafeString!
459
+ $after: String
460
+ $first: Int
461
+ $before: String
462
+ $filter: LedgerLinesFilterSet
463
+ ) {
464
+ ledgerAccount(ledgerAccount: { ledger: { ik: $ledgerIk }, path: $path }) {
465
+ id
466
+ path
467
+ lines(after: $after, first: $first, before: $before, filter: $filter) {
468
+ nodes {
469
+ id
470
+ posted
471
+ created
472
+ amount
473
+ description
474
+ }
475
+ pageInfo {
476
+ hasNextPage
477
+ endCursor
478
+ hasPreviousPage
479
+ startCursor
480
+ }
481
+ }
482
+ }
483
+ }
484
+
485
+ query GetLedgerAccountBalance(
486
+ $path: String!
487
+ $ledgerIk: SafeString!
488
+ $balanceCurrency: CurrencyMatchInput
489
+ $balanceAt: LastMoment
490
+ $ownBalanceConsistencyMode: ReadBalanceConsistencyMode
491
+ ) {
492
+ ledgerAccount(ledgerAccount: { ledger: { ik: $ledgerIk }, path: $path }) {
493
+ id
494
+ path
495
+ ownBalance(
496
+ currency: $balanceCurrency
497
+ at: $balanceAt
498
+ consistencyMode: $ownBalanceConsistencyMode
499
+ )
500
+ }
501
+ }
502
+
503
+ query GetSchema($key: SafeString!, $version: Int) {
504
+ schema(schema: { key: $key, version: $version }) {
505
+ key
506
+ name
507
+ version {
508
+ created
509
+ version
510
+ json
511
+ }
512
+ }
513
+ }
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fragment-dev
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - fragment
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: graphql-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.20'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.20'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sorbet-runtime
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.5'
41
+ description:
42
+ email: snoble@fragment.dev
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - lib/fragment.schema.json
48
+ - lib/fragment_client.rb
49
+ - lib/fragment_client.rbi
50
+ - lib/fragment_client/version.rb
51
+ - lib/queries.graphql
52
+ homepage: https://fragment.dev
53
+ licenses:
54
+ - Apache-2.0
55
+ metadata: {}
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '3.0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubygems_version: 3.3.27
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: the ruby fragment client sdk
75
+ test_files: []