fragment-dev 1.0.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.
@@ -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: []