From 4f7821b979292539527621e315583e52a919fbb6 Mon Sep 17 00:00:00 2001 From: Paul Le Cam Date: Mon, 15 Apr 2024 17:32:45 +0100 Subject: [PATCH] Remove support for single point model --- composites/points/composite.json | 2 +- composites/points/schemas/1-init.graphql | 40 ++--- composites/points/src/definition.ts | 119 ++++++------- composites/points/src/index.ts | 6 +- .../src/controllers/singleController.ts | 70 -------- demo/server/src/index.ts | 2 - demo/server/src/routes/single.ts | 38 ----- demo/simple/index.mjs | 40 +++-- libraries/points/src/index.ts | 6 - libraries/points/src/points-reader.ts | 9 +- libraries/points/src/single-reader.ts | 65 ------- libraries/points/src/single-writer.ts | 54 ------ libraries/points/test/lib.test.ts | 158 ++---------------- 13 files changed, 105 insertions(+), 504 deletions(-) delete mode 100644 demo/server/src/controllers/singleController.ts delete mode 100644 demo/server/src/routes/single.ts delete mode 100644 libraries/points/src/single-reader.ts delete mode 100644 libraries/points/src/single-writer.ts diff --git a/composites/points/composite.json b/composites/points/composite.json index 71a2cfb..89673ff 100644 --- a/composites/points/composite.json +++ b/composites/points/composite.json @@ -1 +1 @@ -{"version":"1.1","models":{"kjzl6hvfrbw6c6m3n64vb2h4n8nxq9jjfb7sf7a9y893spm1pjd0enrsdlyphg4":[{"jws":{"payload":"AXESIIW9VBgw9lWE6fuy69Neg6qdaqVYY5khOCk1UA6Pb68O","signatures":[{"signature":"fi_HzHWxUNEN7RF656YtUUrh5AOB7IMqrzx-GQLhc7f0SwE7UpHziEiUWCI37jKL0RdxXzxCvslblLKURGaDAA","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreiefxvkbqmhwkwcot65s5pjv5a5ktvvkkwddteqtqkjvkahi635pby"},"linkedBlock":"omRkYXRhqmRuYW1ldkdlbmVyaWNQb2ludEFsbG9jYXRpb25ldmlld3OhZmlzc3VlcqFkdHlwZW9kb2N1bWVudEFjY291bnRmc2NoZW1hpmR0eXBlZm9iamVjdGUkZGVmc6FqR3JhcGhRTERJRKRkdHlwZWZzdHJpbmdldGl0bGVqR3JhcGhRTERJRGdwYXR0ZXJueI9eZGlkOlthLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKzpbYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSo6P1thLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKjo/W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qJGltYXhMZW5ndGgYZGckc2NoZW1heCxodHRwczovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC8yMDIwLTEyL3NjaGVtYWhyZXF1aXJlZIFpcmVjaXBpZW50anByb3BlcnRpZXOhaXJlY2lwaWVudKFkJHJlZnIjLyRkZWZzL0dyYXBoUUxESUR0YWRkaXRpb25hbFByb3BlcnRpZXP0Z3ZlcnNpb25jMi4waWludGVyZmFjZfVpcmVsYXRpb25zoWlyZWNpcGllbnShZHR5cGVnYWNjb3VudGppbXBsZW1lbnRzgGtkZXNjcmlwdGlvbng2SW50ZXJmYWNlIGZvciBhIGdlbmVyaWMgcG9pbnQgYWxsb2NhdGlvbiB0byBhbiBhY2NvdW50b2FjY291bnRSZWxhdGlvbqFkdHlwZWRub25lb2ltbXV0YWJsZUZpZWxkc4BmaGVhZGVyo2NzZXBlbW9kZWxlbW9kZWxSzgEEAXFxCwAJaG1vZGVsLXYxa2NvbnRyb2xsZXJzgXg4ZGlkOmtleTp6Nk1raVRCejF5bXVlcEFRNEhFSFlTRjFIOHF1RzVHTFZWUVIzZGpkWDNtRG9vV3A="}],"kjzl6hvfrbw6cb6393dpd8blke5w8r7pvbl4449mxetuibcav3oab8fnxmys6d6":[{"jws":{"payload":"AXESILEbRur9tHZU_VdgLnduXmWauZnOsE-E6akVH5y3dPIi","signatures":[{"signature":"4PM1useQFqBDUpdW7N4_6kpgcanZ3oGO14stUfQR2D76B935RT7HWivmyKtjNXFBRjDLUcIkCLDxYZ-KxjEyCA","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreifrdndov7nuozkp2v3afz3w4xtftk4zttvqj6cotkivd6olo5hsei"},"linkedBlock":"omRkYXRhqmRuYW1lcVBvaW50c0FnZ3JlZ2F0aW9uZXZpZXdzoWZpc3N1ZXKhZHR5cGVvZG9jdW1lbnRBY2NvdW50ZnNjaGVtYaZkdHlwZWZvYmplY3RlJGRlZnOiakdyYXBoUUxESUSkZHR5cGVmc3RyaW5nZXRpdGxlakdyYXBoUUxESURncGF0dGVybniPXmRpZDpbYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSs6W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qOj9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSo6P1thLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKiRpbWF4TGVuZ3RoGGRvR3JhcGhRTERhdGVUaW1lpGR0eXBlZnN0cmluZ2V0aXRsZW9HcmFwaFFMRGF0ZVRpbWVmZm9ybWF0aWRhdGUtdGltZWltYXhMZW5ndGgYZGckc2NoZW1heCxodHRwczovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC8yMDIwLTEyL3NjaGVtYWhyZXF1aXJlZINpcmVjaXBpZW50ZnBvaW50c2RkYXRlanByb3BlcnRpZXOjZGRhdGWhZCRyZWZ3Iy8kZGVmcy9HcmFwaFFMRGF0ZVRpbWVmcG9pbnRzoWR0eXBlZ2ludGVnZXJpcmVjaXBpZW50oWQkcmVmciMvJGRlZnMvR3JhcGhRTERJRHRhZGRpdGlvbmFsUHJvcGVydGllc/RndmVyc2lvbmMyLjBpaW50ZXJmYWNl9WlyZWxhdGlvbnOhaXJlY2lwaWVudKFkdHlwZWdhY2NvdW50amltcGxlbWVudHOAa2Rlc2NyaXB0aW9ueCBJbnRlcmZhY2UgZm9yIHBvaW50cyBhZ2dyZWdhdGlvbm9hY2NvdW50UmVsYXRpb26hZHR5cGVkbm9uZW9pbW11dGFibGVGaWVsZHOAZmhlYWRlcqNjc2VwZW1vZGVsZW1vZGVsUs4BBAFxcQsACWhtb2RlbC12MWtjb250cm9sbGVyc4F4OGRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dw"}],"kjzl6hvfrbw6c5be4exsm7nkkksnqatki8bceyvbgtmcu2bu5vign23b7x4emlb":[{"jws":{"payload":"AXESIGrHZPJHN7tQ7rbITv11_EFgn87p0aPDcKciW-Rnpi9T","signatures":[{"signature":"ycj0FttO0SHeK0ju6-mYfCztVGtzIzzomkGysDEBU_SSLPx3S8_yZrAykb5O2OzNj_X1u1JYSAYhsjVFkReEAg","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreidky5sperzxxnio5nwij36xl7cbmcp452orupbxbjzclpsgpjrpkm"},"linkedBlock":"omRkYXRhqmRuYW1la1RvdGFsUG9pbnRzZXZpZXdzoWZpc3N1ZXKhZHR5cGVvZG9jdW1lbnRBY2NvdW50ZnNjaGVtYaZkdHlwZWZvYmplY3RlJGRlZnOiakdyYXBoUUxESUSkZHR5cGVmc3RyaW5nZXRpdGxlakdyYXBoUUxESURncGF0dGVybniPXmRpZDpbYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSs6W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qOj9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSo6P1thLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKiRpbWF4TGVuZ3RoGGRvR3JhcGhRTERhdGVUaW1lpGR0eXBlZnN0cmluZ2V0aXRsZW9HcmFwaFFMRGF0ZVRpbWVmZm9ybWF0aWRhdGUtdGltZWltYXhMZW5ndGgYZGckc2NoZW1heCxodHRwczovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC8yMDIwLTEyL3NjaGVtYWhyZXF1aXJlZINpcmVjaXBpZW50ZnBvaW50c2RkYXRlanByb3BlcnRpZXOjZGRhdGWhZCRyZWZ3Iy8kZGVmcy9HcmFwaFFMRGF0ZVRpbWVmcG9pbnRzoWR0eXBlZ2ludGVnZXJpcmVjaXBpZW50oWQkcmVmciMvJGRlZnMvR3JhcGhRTERJRHRhZGRpdGlvbmFsUHJvcGVydGllc/RndmVyc2lvbmMyLjBpaW50ZXJmYWNl9GlyZWxhdGlvbnOhaXJlY2lwaWVudKFkdHlwZWdhY2NvdW50amltcGxlbWVudHOBeD9ranpsNmh2ZnJidzZjYjYzOTNkcGQ4YmxrZTV3OHI3cHZibDQ0NDlteGV0dWliY2F2M29hYjhmbnhteXM2ZDZrZGVzY3JpcHRpb254JVBvaW50cyBhZ2dyZWdhdGlvbiBhdCBhIHNwZWNpZmljIGRhdGVvYWNjb3VudFJlbGF0aW9uomR0eXBlY3NldGZmaWVsZHOBaXJlY2lwaWVudG9pbW11dGFibGVGaWVsZHOAZmhlYWRlcqNjc2VwZW1vZGVsZW1vZGVsUs4BBAFxcQsACWhtb2RlbC12MWtjb250cm9sbGVyc4F4OGRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dw"}],"kjzl6hvfrbw6c7ilzfpjw96drd04jadb0aybiklk70ys2imxp5mjbjmgkecgddf":[{"jws":{"payload":"AXESIJ9VPe6nxQFfkg1SFa1lVeNROBRce0_XgLDGAqDtXF2Z","signatures":[{"signature":"Rcj4PptdwafVjPdyNszkpsIty9QaoN1Ov4BrQ8P0nRgjSxnVmnKTMIVT7h9e4lGfAConRU0T3I2e8sAV7xwiAw","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreie7ku665j6fafpzedkscwwwkvpdke4bixd3j7lybmggakqo2xc5te"},"linkedBlock":"omRkYXRhqmRuYW1ldVNpbmdsZVBvaW50QWxsb2NhdGlvbmV2aWV3c6FmaXNzdWVyoWR0eXBlb2RvY3VtZW50QWNjb3VudGZzY2hlbWGmZHR5cGVmb2JqZWN0ZSRkZWZzoWpHcmFwaFFMRElEpGR0eXBlZnN0cmluZ2V0aXRsZWpHcmFwaFFMRElEZ3BhdHRlcm54j15kaWQ6W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0rOlthLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKjo/W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qOj9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSokaW1heExlbmd0aBhkZyRzY2hlbWF4LGh0dHBzOi8vanNvbi1zY2hlbWEub3JnL2RyYWZ0LzIwMjAtMTIvc2NoZW1haHJlcXVpcmVkgWlyZWNpcGllbnRqcHJvcGVydGllc6FpcmVjaXBpZW50oWQkcmVmciMvJGRlZnMvR3JhcGhRTERJRHRhZGRpdGlvbmFsUHJvcGVydGllc/RndmVyc2lvbmMyLjBpaW50ZXJmYWNl9WlyZWxhdGlvbnOhaXJlY2lwaWVudKFkdHlwZWdhY2NvdW50amltcGxlbWVudHOBeD9ranpsNmh2ZnJidzZjNm0zbjY0dmIyaDRuOG54cTlqamZiN3NmN2E5eTg5M3NwbTFwamQwZW5yc2RseXBoZzRrZGVzY3JpcHRpb254PEludGVyZmFjZSBmb3IgdGhlIGFsbG9jYXRpb24gb2YgYSBzaW5nbGUgcG9pbnQgdG8gYW4gYWNjb3VudG9hY2NvdW50UmVsYXRpb26hZHR5cGVkbm9uZW9pbW11dGFibGVGaWVsZHOAZmhlYWRlcqNjc2VwZW1vZGVsZW1vZGVsUs4BBAFxcQsACWhtb2RlbC12MWtjb250cm9sbGVyc4F4OGRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dw"}],"kjzl6hvfrbw6ca7buvthejhv7vqr85vmpsepzj0mc6665y2zarvjbuvtm3v4kah":[{"jws":{"payload":"AXESIGilp-bINx1y6OLYTTxpjS8gH7bkwXgdfi_5N7p_ter4","signatures":[{"signature":"nX7DW0-1Cor64-m8qHrtf2AL8rxdMzuK5LYkR57qbijYEP_3j9xpUTLjFSCT5RueZiZTWxFNzypTQLDID8rKCQ","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreidiuwt6nsbxdvzorywyju6gtdjpeap3nzgbpaox4l7zg65h7npk7a"},"linkedBlock":"omRkYXRhqmRuYW1leBhNdWx0aXBsZVBvaW50c0FsbG9jYXRpb25ldmlld3OhZmlzc3VlcqFkdHlwZW9kb2N1bWVudEFjY291bnRmc2NoZW1hpmR0eXBlZm9iamVjdGUkZGVmc6FqR3JhcGhRTERJRKRkdHlwZWZzdHJpbmdldGl0bGVqR3JhcGhRTERJRGdwYXR0ZXJueI9eZGlkOlthLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKzpbYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSo6P1thLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKjo/W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qJGltYXhMZW5ndGgYZGckc2NoZW1heCxodHRwczovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC8yMDIwLTEyL3NjaGVtYWhyZXF1aXJlZIJpcmVjaXBpZW50ZnBvaW50c2pwcm9wZXJ0aWVzomZwb2ludHOhZHR5cGVnaW50ZWdlcmlyZWNpcGllbnShZCRyZWZyIy8kZGVmcy9HcmFwaFFMRElEdGFkZGl0aW9uYWxQcm9wZXJ0aWVz9Gd2ZXJzaW9uYzIuMGlpbnRlcmZhY2X1aXJlbGF0aW9uc6FpcmVjaXBpZW50oWR0eXBlZ2FjY291bnRqaW1wbGVtZW50c4F4P2tqemw2aHZmcmJ3NmM2bTNuNjR2YjJoNG44bnhxOWpqZmI3c2Y3YTl5ODkzc3BtMXBqZDBlbnJzZGx5cGhnNGtkZXNjcmlwdGlvbng9SW50ZXJmYWNlIGZvciB0aGUgYWxsb2NhdGlvbiBvZiBtdWx0aXBsZSBwb2ludHMgdG8gYW4gYWNjb3VudG9hY2NvdW50UmVsYXRpb26hZHR5cGVkbm9uZW9pbW11dGFibGVGaWVsZHOAZmhlYWRlcqNjc2VwZW1vZGVsZW1vZGVsUs4BBAFxcQsACWhtb2RlbC12MWtjb250cm9sbGVyc4F4OGRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dw"}],"kjzl6hvfrbw6c9332q9di7qfshxczet94w2tzeubvkbkk9vtuwmya6s9f1bvx9p":[{"jws":{"payload":"AXESIH1o0-6-06mPazvJ0DDFeLIFBUFOcXikr-Q-ieeZxzRJ","signatures":[{"signature":"SWCjiSqgfZ2Cj37_RaMkjb9KDXGla2yA001UdbnwpN6MzJ2Wf9YSh_g-Y0nGDV_zSXpMhiaQv5jIxs4kzJsSAg","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreid5ndj65pwtvghwwo6j2aymk6fsaucucttrpcsk7zb6rhtztrzuje"},"linkedBlock":"omRkYXRhqmRuYW1la1NpbmdsZVBvaW50ZXZpZXdzoWZpc3N1ZXKhZHR5cGVvZG9jdW1lbnRBY2NvdW50ZnNjaGVtYaZkdHlwZWZvYmplY3RlJGRlZnOhakdyYXBoUUxESUSkZHR5cGVmc3RyaW5nZXRpdGxlakdyYXBoUUxESURncGF0dGVybniPXmRpZDpbYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSs6W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qOj9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSo6P1thLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKiRpbWF4TGVuZ3RoGGRnJHNjaGVtYXgsaHR0cHM6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQvMjAyMC0xMi9zY2hlbWFocmVxdWlyZWSBaXJlY2lwaWVudGpwcm9wZXJ0aWVzoWlyZWNpcGllbnShZCRyZWZyIy8kZGVmcy9HcmFwaFFMRElEdGFkZGl0aW9uYWxQcm9wZXJ0aWVz9Gd2ZXJzaW9uYzIuMGlpbnRlcmZhY2X0aXJlbGF0aW9uc6FpcmVjaXBpZW50oWR0eXBlZ2FjY291bnRqaW1wbGVtZW50c4J4P2tqemw2aHZmcmJ3NmM3aWx6ZnBqdzk2ZHJkMDRqYWRiMGF5YmlrbGs3MHlzMmlteHA1bWpiam1na2VjZ2RkZng/a2p6bDZodmZyYnc2YzZtM242NHZiMmg0bjhueHE5ampmYjdzZjdhOXk4OTNzcG0xcGpkMGVucnNkbHlwaGc0a2Rlc2NyaXB0aW9ueCpBbGxvY2F0aW9uIG9mIGEgc2luZ2xlIHBvaW50IHRvIGFuIGFjY291bnRvYWNjb3VudFJlbGF0aW9uoWR0eXBlZGxpc3RvaW1tdXRhYmxlRmllbGRzgGZoZWFkZXKjY3NlcGVtb2RlbGVtb2RlbFLOAQQBcXELAAlobW9kZWwtdjFrY29udHJvbGxlcnOBeDhkaWQ6a2V5Ono2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcA=="}],"kjzl6hvfrbw6c9fmjjdsbuxnewf0yhvco3dn5mihiogeso6i1csdbw2fq8oeijy":[{"jws":{"payload":"AXESIBRHnaqD2WivGPjSpz5FzuDrRhhZZoMQTmB_F7DTUIUL","signatures":[{"signature":"PDeOzy_1uacPIAedyvZeSty046tmnUKMkhsFhOV8GpEfZJLYZOpwUmry0jrzk3qHsgmeEmjmjnmeFmy77NazDw","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreiaui6o2va6zncxrr6gsu47eltxa5ndbqwlgqmie4yd7c6ynguefbm"},"linkedBlock":"omRkYXRhqmRuYW1lbk11bHRpcGxlUG9pbnRzZXZpZXdzoWZpc3N1ZXKhZHR5cGVvZG9jdW1lbnRBY2NvdW50ZnNjaGVtYaZkdHlwZWZvYmplY3RlJGRlZnOhakdyYXBoUUxESUSkZHR5cGVmc3RyaW5nZXRpdGxlakdyYXBoUUxESURncGF0dGVybniPXmRpZDpbYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSs6W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qOj9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSo6P1thLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKiRpbWF4TGVuZ3RoGGRnJHNjaGVtYXgsaHR0cHM6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQvMjAyMC0xMi9zY2hlbWFocmVxdWlyZWSCaXJlY2lwaWVudGZwb2ludHNqcHJvcGVydGllc6JmcG9pbnRzoWR0eXBlZ2ludGVnZXJpcmVjaXBpZW50oWQkcmVmciMvJGRlZnMvR3JhcGhRTERJRHRhZGRpdGlvbmFsUHJvcGVydGllc/RndmVyc2lvbmMyLjBpaW50ZXJmYWNl9GlyZWxhdGlvbnOhaXJlY2lwaWVudKFkdHlwZWdhY2NvdW50amltcGxlbWVudHOCeD9ranpsNmh2ZnJidzZjYTdidXZ0aGVqaHY3dnFyODV2bXBzZXB6ajBtYzY2NjV5MnphcnZqYnV2dG0zdjRrYWh4P2tqemw2aHZmcmJ3NmM2bTNuNjR2YjJoNG44bnhxOWpqZmI3c2Y3YTl5ODkzc3BtMXBqZDBlbnJzZGx5cGhnNGtkZXNjcmlwdGlvbngrQWxsb2NhdGlvbiBvZiBtdWx0aXBsZSBwb2ludHMgdG8gYW4gYWNjb3VudG9hY2NvdW50UmVsYXRpb26hZHR5cGVkbGlzdG9pbW11dGFibGVGaWVsZHOAZmhlYWRlcqNjc2VwZW1vZGVsZW1vZGVsUs4BBAFxcQsACWhtb2RlbC12MWtjb250cm9sbGVyc4F4OGRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dw"}]},"indices":{"kjzl6hvfrbw6c6m3n64vb2h4n8nxq9jjfb7sf7a9y893spm1pjd0enrsdlyphg4":[],"kjzl6hvfrbw6cb6393dpd8blke5w8r7pvbl4449mxetuibcav3oab8fnxmys6d6":[],"kjzl6hvfrbw6c5be4exsm7nkkksnqatki8bceyvbgtmcu2bu5vign23b7x4emlb":[],"kjzl6hvfrbw6c7ilzfpjw96drd04jadb0aybiklk70ys2imxp5mjbjmgkecgddf":[],"kjzl6hvfrbw6ca7buvthejhv7vqr85vmpsepzj0mc6665y2zarvjbuvtm3v4kah":[],"kjzl6hvfrbw6c9332q9di7qfshxczet94w2tzeubvkbkk9vtuwmya6s9f1bvx9p":[],"kjzl6hvfrbw6c9fmjjdsbuxnewf0yhvco3dn5mihiogeso6i1csdbw2fq8oeijy":[]},"aliases":{"kjzl6hvfrbw6cb6393dpd8blke5w8r7pvbl4449mxetuibcav3oab8fnxmys6d6":"PointsAggregation","kjzl6hvfrbw6c6m3n64vb2h4n8nxq9jjfb7sf7a9y893spm1pjd0enrsdlyphg4":"GenericPointAllocation","kjzl6hvfrbw6c5be4exsm7nkkksnqatki8bceyvbgtmcu2bu5vign23b7x4emlb":"TotalPoints","kjzl6hvfrbw6c7ilzfpjw96drd04jadb0aybiklk70ys2imxp5mjbjmgkecgddf":"SinglePointAllocation","kjzl6hvfrbw6ca7buvthejhv7vqr85vmpsepzj0mc6665y2zarvjbuvtm3v4kah":"MultiplePointsAllocation","kjzl6hvfrbw6c9332q9di7qfshxczet94w2tzeubvkbkk9vtuwmya6s9f1bvx9p":"SinglePoint","kjzl6hvfrbw6c9fmjjdsbuxnewf0yhvco3dn5mihiogeso6i1csdbw2fq8oeijy":"MultiplePoints"},"views":{"account":{},"root":{},"models":{"kjzl6hvfrbw6c6m3n64vb2h4n8nxq9jjfb7sf7a9y893spm1pjd0enrsdlyphg4":{},"kjzl6hvfrbw6cb6393dpd8blke5w8r7pvbl4449mxetuibcav3oab8fnxmys6d6":{},"kjzl6hvfrbw6c5be4exsm7nkkksnqatki8bceyvbgtmcu2bu5vign23b7x4emlb":{},"kjzl6hvfrbw6c7ilzfpjw96drd04jadb0aybiklk70ys2imxp5mjbjmgkecgddf":{},"kjzl6hvfrbw6ca7buvthejhv7vqr85vmpsepzj0mc6665y2zarvjbuvtm3v4kah":{},"kjzl6hvfrbw6c9332q9di7qfshxczet94w2tzeubvkbkk9vtuwmya6s9f1bvx9p":{},"kjzl6hvfrbw6c9fmjjdsbuxnewf0yhvco3dn5mihiogeso6i1csdbw2fq8oeijy":{}}},"commonEmbeds":[]} +{"version":"1.1","models":{"kjzl6hvfrbw6c6lxvcf8bc07wjyn29ocoxqn877uia1y86qph79axtdrcuijpeo":[{"jws":{"payload":"AXESINtobkWyMBlV381m5vCoL5e1JaePHopnxnTXRRM-K1aZ","signatures":[{"signature":"AvGRjkwaj4KTAM3I-tSvCbqlW-Uh--D2OR-GQpWauH8FY2y2yrtLt_rcX54LrvZfy91yuCCy65rsYJPuqliaAg","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreig3nbxelmrqdfk57tlg43ykql4xwus2pdy6rjt4m5gxiujt4k2wte"},"linkedBlock":"omRkYXRhqmRuYW1lb1BvaW50c0ludGVyZmFjZWV2aWV3c6FmaXNzdWVyoWR0eXBlb2RvY3VtZW50QWNjb3VudGZzY2hlbWGmZHR5cGVmb2JqZWN0ZSRkZWZzoWpHcmFwaFFMRElEpGR0eXBlZnN0cmluZ2V0aXRsZWpHcmFwaFFMRElEZ3BhdHRlcm54j15kaWQ6W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0rOlthLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKjo/W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qOj9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSokaW1heExlbmd0aBhkZyRzY2hlbWF4LGh0dHBzOi8vanNvbi1zY2hlbWEub3JnL2RyYWZ0LzIwMjAtMTIvc2NoZW1haHJlcXVpcmVkgmlyZWNpcGllbnRmcG9pbnRzanByb3BlcnRpZXOiZnBvaW50c6FkdHlwZWdpbnRlZ2VyaXJlY2lwaWVudKFkJHJlZnIjLyRkZWZzL0dyYXBoUUxESUR0YWRkaXRpb25hbFByb3BlcnRpZXP0Z3ZlcnNpb25jMi4waWludGVyZmFjZfVpcmVsYXRpb25zoWlyZWNpcGllbnShZHR5cGVnYWNjb3VudGppbXBsZW1lbnRzgGtkZXNjcmlwdGlvbng4SW50ZXJmYWNlIGZvciBhIGdlbmVyaWMgcG9pbnRzIGFzc29jaWF0aW9uIHRvIGFuIGFjY291bnRvYWNjb3VudFJlbGF0aW9uoWR0eXBlZG5vbmVvaW1tdXRhYmxlRmllbGRzgGZoZWFkZXKjY3NlcGVtb2RlbGVtb2RlbFLOAQQBcXELAAlobW9kZWwtdjFrY29udHJvbGxlcnOBeDhkaWQ6a2V5Ono2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcA=="}],"kjzl6hvfrbw6cakj74rf7d3qjnm3xoydcgx7orzw4bwdmc6kljd04uojuhpef2j":[{"jws":{"payload":"AXESIHdwJbEAd1czmvtrPSXnL8_EEGzmyIQjimDiGxJwM3gk","signatures":[{"signature":"d70VIaDtbp-pGiy5i2wYdV_JqhOYJLFYqBUesqt8X8B-fAw-mPNr1bRcp4-iCRyO4Jb7L7f7ikjhcuRY4IPxDw","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreidxoas3cadxk4zzv63lhus6ol6pyqigzzwiqqryuyhcdmjham3yeq"},"linkedBlock":"omRkYXRhqmRuYW1leBlQb2ludHNBbGxvY2F0aW9uSW50ZXJmYWNlZXZpZXdzoWZpc3N1ZXKhZHR5cGVvZG9jdW1lbnRBY2NvdW50ZnNjaGVtYaZkdHlwZWZvYmplY3RlJGRlZnOhakdyYXBoUUxESUSkZHR5cGVmc3RyaW5nZXRpdGxlakdyYXBoUUxESURncGF0dGVybniPXmRpZDpbYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSs6W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qOj9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSo6P1thLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKiRpbWF4TGVuZ3RoGGRnJHNjaGVtYXgsaHR0cHM6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQvMjAyMC0xMi9zY2hlbWFocmVxdWlyZWSCaXJlY2lwaWVudGZwb2ludHNqcHJvcGVydGllc6JmcG9pbnRzoWR0eXBlZ2ludGVnZXJpcmVjaXBpZW50oWQkcmVmciMvJGRlZnMvR3JhcGhRTERJRHRhZGRpdGlvbmFsUHJvcGVydGllc/RndmVyc2lvbmMyLjBpaW50ZXJmYWNl9WlyZWxhdGlvbnOhaXJlY2lwaWVudKFkdHlwZWdhY2NvdW50amltcGxlbWVudHOBeD9ranpsNmh2ZnJidzZjNmx4dmNmOGJjMDd3anluMjlvY294cW44Nzd1aWExeTg2cXBoNzlheHRkcmN1aWpwZW9rZGVzY3JpcHRpb254OUludGVyZmFjZSBmb3IgYSBzaW5nbGUgYWxsb2NhdGlvbiBvZiBwb2ludHMgdG8gYW4gYWNjb3VudG9hY2NvdW50UmVsYXRpb26hZHR5cGVkbm9uZW9pbW11dGFibGVGaWVsZHOAZmhlYWRlcqNjc2VwZW1vZGVsZW1vZGVsUs4BBAFxcQsACWhtb2RlbC12MWtjb250cm9sbGVyc4F4OGRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dw"}],"kjzl6hvfrbw6c5m5bxe6jl7cocyxpg9b8em5w9mo3l8ws4zl5c0tu5vgapitpvk":[{"jws":{"payload":"AXESILkq4fQGondBge7o79syZ2WG5SwFp7VQ_DBsqDlHtzpO","signatures":[{"signature":"URH315iV6peuplx1j0Uvdi-_hoe4gWZLtImo5iK8tsvlmiUs76hwzGb6EiOXHUCBO9MsnwDCfsBagKajBB1nDg","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreifzflq7ibvco5ayd3xi57ntez3fq3ssybnhwvipymdmva4upnz2jy"},"linkedBlock":"omRkYXRhqmRuYW1leBpQb2ludHNBZ2dyZWdhdGlvbkludGVyZmFjZWV2aWV3c6FmaXNzdWVyoWR0eXBlb2RvY3VtZW50QWNjb3VudGZzY2hlbWGmZHR5cGVmb2JqZWN0ZSRkZWZzompHcmFwaFFMRElEpGR0eXBlZnN0cmluZ2V0aXRsZWpHcmFwaFFMRElEZ3BhdHRlcm54j15kaWQ6W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0rOlthLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKjo/W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qOj9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSokaW1heExlbmd0aBhkb0dyYXBoUUxEYXRlVGltZaRkdHlwZWZzdHJpbmdldGl0bGVvR3JhcGhRTERhdGVUaW1lZmZvcm1hdGlkYXRlLXRpbWVpbWF4TGVuZ3RoGGRnJHNjaGVtYXgsaHR0cHM6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQvMjAyMC0xMi9zY2hlbWFocmVxdWlyZWSDaXJlY2lwaWVudGZwb2ludHNkZGF0ZWpwcm9wZXJ0aWVzo2RkYXRloWQkcmVmdyMvJGRlZnMvR3JhcGhRTERhdGVUaW1lZnBvaW50c6FkdHlwZWdpbnRlZ2VyaXJlY2lwaWVudKFkJHJlZnIjLyRkZWZzL0dyYXBoUUxESUR0YWRkaXRpb25hbFByb3BlcnRpZXP0Z3ZlcnNpb25jMi4waWludGVyZmFjZfVpcmVsYXRpb25zoWlyZWNpcGllbnShZHR5cGVnYWNjb3VudGppbXBsZW1lbnRzgXg/a2p6bDZodmZyYnc2YzZseHZjZjhiYzA3d2p5bjI5b2NveHFuODc3dWlhMXk4NnFwaDc5YXh0ZHJjdWlqcGVva2Rlc2NyaXB0aW9ueDRJbnRlcmZhY2UgZm9yIGFuIGFnZ3JlZ2F0aW9uIG9mIHBvaW50cyB0byBhbiBhY2NvdW50b2FjY291bnRSZWxhdGlvbqFkdHlwZWRub25lb2ltbXV0YWJsZUZpZWxkc4BmaGVhZGVyo2NzZXBlbW9kZWxlbW9kZWxSzgEEAXFxCwAJaG1vZGVsLXYxa2NvbnRyb2xsZXJzgXg4ZGlkOmtleTp6Nk1raVRCejF5bXVlcEFRNEhFSFlTRjFIOHF1RzVHTFZWUVIzZGpkWDNtRG9vV3A="}],"kjzl6hvfrbw6c9rahz7aal75i0ncxkf5wmircmtpz2s34xls8ux1p08ic655oek":[{"jws":{"payload":"AXESIJI8d0EzGXmMXHdOGpan7VeClShUpPcEP8_jwAQcWWWM","signatures":[{"signature":"JI7h3fa3KFsVJlRjjhFfH2fxXtblRCkTqJrUBDh1tyBl9Dl0JuO_Du-Cp2uejgqcpCuC5ZE18JtQdTDt7eXuDQ","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreieshr3ucmyzpggfy52odklkp3kxqkksqvfe64cd7t7dyacbywlfrq"},"linkedBlock":"omRkYXRhqmRuYW1ldlNpbXBsZVBvaW50c0FsbG9jYXRpb25ldmlld3OhZmlzc3VlcqFkdHlwZW9kb2N1bWVudEFjY291bnRmc2NoZW1hpmR0eXBlZm9iamVjdGUkZGVmc6FqR3JhcGhRTERJRKRkdHlwZWZzdHJpbmdldGl0bGVqR3JhcGhRTERJRGdwYXR0ZXJueI9eZGlkOlthLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKzpbYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSo6P1thLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKjo/W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qJGltYXhMZW5ndGgYZGckc2NoZW1heCxodHRwczovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC8yMDIwLTEyL3NjaGVtYWhyZXF1aXJlZIJpcmVjaXBpZW50ZnBvaW50c2pwcm9wZXJ0aWVzomZwb2ludHOhZHR5cGVnaW50ZWdlcmlyZWNpcGllbnShZCRyZWZyIy8kZGVmcy9HcmFwaFFMRElEdGFkZGl0aW9uYWxQcm9wZXJ0aWVz9Gd2ZXJzaW9uYzIuMGlpbnRlcmZhY2X0aXJlbGF0aW9uc6FpcmVjaXBpZW50oWR0eXBlZ2FjY291bnRqaW1wbGVtZW50c4J4P2tqemw2aHZmcmJ3NmNha2o3NHJmN2QzcWpubTN4b3lkY2d4N29yenc0YndkbWM2a2xqZDA0dW9qdWhwZWYyang/a2p6bDZodmZyYnc2YzZseHZjZjhiYzA3d2p5bjI5b2NveHFuODc3dWlhMXk4NnFwaDc5YXh0ZHJjdWlqcGVva2Rlc2NyaXB0aW9ueCZTaW1wbGUgcG9pbnRzIGFsbG9jYXRpb24gdG8gYW4gYWNjb3VudG9hY2NvdW50UmVsYXRpb26hZHR5cGVkbGlzdG9pbW11dGFibGVGaWVsZHOAZmhlYWRlcqNjc2VwZW1vZGVsZW1vZGVsUs4BBAFxcQsACWhtb2RlbC12MWtjb250cm9sbGVyc4F4OGRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dw"}],"kjzl6hvfrbw6capj3or1esf65c1jbluhky3t2wupxefeuocqt5lz5u4gum07o24":[{"jws":{"payload":"AXESINU0jJJiAe5hSsd0iDx2o5Mst0U8TW76aOlN-h98_Sdx","signatures":[{"signature":"IheLhTPvua3YeT8mqa4dwlX2M9BPHG73WO9JBiBWwJ7NeeRowcrn5xVGDEmH0OQOsdkPpDjTk37FTUP2WATQBg","protected":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2lUQnoxeW11ZXBBUTRIRUhZU0YxSDhxdUc1R0xWVlFSM2RqZFgzbURvb1dwI3o2TWtpVEJ6MXltdWVwQVE0SEVIWVNGMUg4cXVHNUdMVlZRUjNkamRYM21Eb29XcCJ9"}],"link":"bafyreigvgsgjeyqb5zquvr3ura6hni4tfs3ukpcnn35gr2kn7ipxz7jhoe"},"linkedBlock":"omRkYXRhqmRuYW1ld1NpbXBsZVBvaW50c0FnZ3JlZ2F0aW9uZXZpZXdzoWZpc3N1ZXKhZHR5cGVvZG9jdW1lbnRBY2NvdW50ZnNjaGVtYaZkdHlwZWZvYmplY3RlJGRlZnOiakdyYXBoUUxESUSkZHR5cGVmc3RyaW5nZXRpdGxlakdyYXBoUUxESURncGF0dGVybniPXmRpZDpbYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSs6W2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0qOj9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSo6P1thLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dKiRpbWF4TGVuZ3RoGGRvR3JhcGhRTERhdGVUaW1lpGR0eXBlZnN0cmluZ2V0aXRsZW9HcmFwaFFMRGF0ZVRpbWVmZm9ybWF0aWRhdGUtdGltZWltYXhMZW5ndGgYZGckc2NoZW1heCxodHRwczovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC8yMDIwLTEyL3NjaGVtYWhyZXF1aXJlZINpcmVjaXBpZW50ZnBvaW50c2RkYXRlanByb3BlcnRpZXOjZGRhdGWhZCRyZWZ3Iy8kZGVmcy9HcmFwaFFMRGF0ZVRpbWVmcG9pbnRzoWR0eXBlZ2ludGVnZXJpcmVjaXBpZW50oWQkcmVmciMvJGRlZnMvR3JhcGhRTERJRHRhZGRpdGlvbmFsUHJvcGVydGllc/RndmVyc2lvbmMyLjBpaW50ZXJmYWNl9GlyZWxhdGlvbnOhaXJlY2lwaWVudKFkdHlwZWdhY2NvdW50amltcGxlbWVudHOCeD9ranpsNmh2ZnJidzZjNW01YnhlNmpsN2NvY3l4cGc5YjhlbTV3OW1vM2w4d3M0emw1YzB0dTV2Z2FwaXRwdmt4P2tqemw2aHZmcmJ3NmM2bHh2Y2Y4YmMwN3dqeW4yOW9jb3hxbjg3N3VpYTF5ODZxcGg3OWF4dGRyY3VpanBlb2tkZXNjcmlwdGlvbng6U2ltcGxlIHBvaW50cyBhZ2dyZWdhdGlvbiB0byBhbiBhY2NvdW50IGF0IGEgc3BlY2lmaWMgZGF0ZW9hY2NvdW50UmVsYXRpb26iZHR5cGVjc2V0ZmZpZWxkc4FpcmVjaXBpZW50b2ltbXV0YWJsZUZpZWxkc4BmaGVhZGVyo2NzZXBlbW9kZWxlbW9kZWxSzgEEAXFxCwAJaG1vZGVsLXYxa2NvbnRyb2xsZXJzgXg4ZGlkOmtleTp6Nk1raVRCejF5bXVlcEFRNEhFSFlTRjFIOHF1RzVHTFZWUVIzZGpkWDNtRG9vV3A="}]},"indices":{"kjzl6hvfrbw6c6lxvcf8bc07wjyn29ocoxqn877uia1y86qph79axtdrcuijpeo":[],"kjzl6hvfrbw6cakj74rf7d3qjnm3xoydcgx7orzw4bwdmc6kljd04uojuhpef2j":[],"kjzl6hvfrbw6c5m5bxe6jl7cocyxpg9b8em5w9mo3l8ws4zl5c0tu5vgapitpvk":[],"kjzl6hvfrbw6c9rahz7aal75i0ncxkf5wmircmtpz2s34xls8ux1p08ic655oek":[],"kjzl6hvfrbw6capj3or1esf65c1jbluhky3t2wupxefeuocqt5lz5u4gum07o24":[]},"aliases":{"kjzl6hvfrbw6c6lxvcf8bc07wjyn29ocoxqn877uia1y86qph79axtdrcuijpeo":"PointsInterface","kjzl6hvfrbw6cakj74rf7d3qjnm3xoydcgx7orzw4bwdmc6kljd04uojuhpef2j":"PointsAllocationInterface","kjzl6hvfrbw6c5m5bxe6jl7cocyxpg9b8em5w9mo3l8ws4zl5c0tu5vgapitpvk":"PointsAggregationInterface","kjzl6hvfrbw6c9rahz7aal75i0ncxkf5wmircmtpz2s34xls8ux1p08ic655oek":"SimplePointsAllocation","kjzl6hvfrbw6capj3or1esf65c1jbluhky3t2wupxefeuocqt5lz5u4gum07o24":"SimplePointsAggregation"},"views":{"account":{},"root":{},"models":{"kjzl6hvfrbw6c6lxvcf8bc07wjyn29ocoxqn877uia1y86qph79axtdrcuijpeo":{},"kjzl6hvfrbw6cakj74rf7d3qjnm3xoydcgx7orzw4bwdmc6kljd04uojuhpef2j":{},"kjzl6hvfrbw6c5m5bxe6jl7cocyxpg9b8em5w9mo3l8ws4zl5c0tu5vgapitpvk":{},"kjzl6hvfrbw6c9rahz7aal75i0ncxkf5wmircmtpz2s34xls8ux1p08ic655oek":{},"kjzl6hvfrbw6capj3or1esf65c1jbluhky3t2wupxefeuocqt5lz5u4gum07o24":{}}},"commonEmbeds":[]} diff --git a/composites/points/schemas/1-init.graphql b/composites/points/schemas/1-init.graphql index c6ac7ae..3ad701f 100644 --- a/composites/points/schemas/1-init.graphql +++ b/composites/points/schemas/1-init.graphql @@ -1,35 +1,27 @@ # -# Generic interface used by all point allocations +# Generic interface used by all point allocations and aggregations # -interface GenericPointAllocation - @createModel(description: "Interface for a generic point allocation to an account") { - issuer: DID! @documentAccount - recipient: DID! @accountReference -} - -# -# Interface specific to a single point allocation -# - -interface SinglePointAllocation implements GenericPointAllocation - @createModel(description: "Interface for the allocation of a single point to an account") { +interface PointsInterface + @createModel(description: "Interface for a generic points association to an account") { issuer: DID! @documentAccount recipient: DID! @accountReference + points: Int! } # -# Interfaces for multiple points allocation and aggregations +# Interfaces for points allocations and aggregations # -interface MultiplePointsAllocation implements GenericPointAllocation - @createModel(description: "Interface for the allocation of multiple points to an account") { +interface PointsAllocationInterface implements PointsInterface + @createModel(description: "Interface for a single allocation of points to an account") { issuer: DID! @documentAccount recipient: DID! @accountReference points: Int! } -interface PointsAggregation @createModel(description: "Interface for points aggregation") { +interface PointsAggregationInterface implements PointsInterface + @createModel(description: "Interface for an aggregation of points to an account") { issuer: DID! @documentAccount recipient: DID! @accountReference points: Int! @@ -40,22 +32,16 @@ interface PointsAggregation @createModel(description: "Interface for points aggr # Default models implementing the interfaces # -type SinglePoint implements SinglePointAllocation - @createModel(description: "Allocation of a single point to an account") { - issuer: DID! @documentAccount - recipient: DID! @accountReference -} - -type MultiplePoints implements MultiplePointsAllocation - @createModel(description: "Allocation of multiple points to an account") { +type SimplePointsAllocation implements PointsAllocationInterface + @createModel(description: "Simple points allocation to an account") { issuer: DID! @documentAccount recipient: DID! @accountReference points: Int! } -type TotalPoints implements PointsAggregation +type SimplePointsAggregation implements PointsAggregationInterface @createModel( - description: "Points aggregation at a specific date" + description: "Simple points aggregation to an account at a specific date" accountRelation: SET accountRelationFields: ["recipient"] ) { diff --git a/composites/points/src/definition.ts b/composites/points/src/definition.ts index c6026c2..fcef119 100644 --- a/composites/points/src/definition.ts +++ b/composites/points/src/definition.ts @@ -2,128 +2,109 @@ import type { RuntimeCompositeDefinition } from '@composedb/types' export const definition: RuntimeCompositeDefinition = { models: { - GenericPointAllocation: { + PointsAggregationInterface: { interface: true, - implements: [], - id: 'kjzl6hvfrbw6c6m3n64vb2h4n8nxq9jjfb7sf7a9y893spm1pjd0enrsdlyphg4', + implements: ['kjzl6hvfrbw6c6lxvcf8bc07wjyn29ocoxqn877uia1y86qph79axtdrcuijpeo'], + id: 'kjzl6hvfrbw6c5m5bxe6jl7cocyxpg9b8em5w9mo3l8ws4zl5c0tu5vgapitpvk', accountRelation: { type: 'none' }, }, - MultiplePoints: { - interface: false, - implements: [ - 'kjzl6hvfrbw6ca7buvthejhv7vqr85vmpsepzj0mc6665y2zarvjbuvtm3v4kah', - 'kjzl6hvfrbw6c6m3n64vb2h4n8nxq9jjfb7sf7a9y893spm1pjd0enrsdlyphg4', - ], - id: 'kjzl6hvfrbw6c9fmjjdsbuxnewf0yhvco3dn5mihiogeso6i1csdbw2fq8oeijy', - accountRelation: { type: 'list' }, - }, - MultiplePointsAllocation: { + PointsAllocationInterface: { interface: true, - implements: ['kjzl6hvfrbw6c6m3n64vb2h4n8nxq9jjfb7sf7a9y893spm1pjd0enrsdlyphg4'], - id: 'kjzl6hvfrbw6ca7buvthejhv7vqr85vmpsepzj0mc6665y2zarvjbuvtm3v4kah', + implements: ['kjzl6hvfrbw6c6lxvcf8bc07wjyn29ocoxqn877uia1y86qph79axtdrcuijpeo'], + id: 'kjzl6hvfrbw6cakj74rf7d3qjnm3xoydcgx7orzw4bwdmc6kljd04uojuhpef2j', accountRelation: { type: 'none' }, }, - PointsAggregation: { + PointsInterface: { interface: true, implements: [], - id: 'kjzl6hvfrbw6cb6393dpd8blke5w8r7pvbl4449mxetuibcav3oab8fnxmys6d6', + id: 'kjzl6hvfrbw6c6lxvcf8bc07wjyn29ocoxqn877uia1y86qph79axtdrcuijpeo', accountRelation: { type: 'none' }, }, - SinglePoint: { + SimplePointsAggregation: { interface: false, implements: [ - 'kjzl6hvfrbw6c7ilzfpjw96drd04jadb0aybiklk70ys2imxp5mjbjmgkecgddf', - 'kjzl6hvfrbw6c6m3n64vb2h4n8nxq9jjfb7sf7a9y893spm1pjd0enrsdlyphg4', + 'kjzl6hvfrbw6c5m5bxe6jl7cocyxpg9b8em5w9mo3l8ws4zl5c0tu5vgapitpvk', + 'kjzl6hvfrbw6c6lxvcf8bc07wjyn29ocoxqn877uia1y86qph79axtdrcuijpeo', ], - id: 'kjzl6hvfrbw6c9332q9di7qfshxczet94w2tzeubvkbkk9vtuwmya6s9f1bvx9p', - accountRelation: { type: 'list' }, - }, - SinglePointAllocation: { - interface: true, - implements: ['kjzl6hvfrbw6c6m3n64vb2h4n8nxq9jjfb7sf7a9y893spm1pjd0enrsdlyphg4'], - id: 'kjzl6hvfrbw6c7ilzfpjw96drd04jadb0aybiklk70ys2imxp5mjbjmgkecgddf', - accountRelation: { type: 'none' }, + id: 'kjzl6hvfrbw6capj3or1esf65c1jbluhky3t2wupxefeuocqt5lz5u4gum07o24', + accountRelation: { type: 'set', fields: ['recipient'] }, }, - TotalPoints: { + SimplePointsAllocation: { interface: false, - implements: ['kjzl6hvfrbw6cb6393dpd8blke5w8r7pvbl4449mxetuibcav3oab8fnxmys6d6'], - id: 'kjzl6hvfrbw6c5be4exsm7nkkksnqatki8bceyvbgtmcu2bu5vign23b7x4emlb', - accountRelation: { type: 'set', fields: ['recipient'] }, + implements: [ + 'kjzl6hvfrbw6cakj74rf7d3qjnm3xoydcgx7orzw4bwdmc6kljd04uojuhpef2j', + 'kjzl6hvfrbw6c6lxvcf8bc07wjyn29ocoxqn877uia1y86qph79axtdrcuijpeo', + ], + id: 'kjzl6hvfrbw6c9rahz7aal75i0ncxkf5wmircmtpz2s34xls8ux1p08ic655oek', + accountRelation: { type: 'list' }, }, }, objects: { - GenericPointAllocation: { + PointsAggregationInterface: { + date: { type: 'datetime', required: true, immutable: false }, + points: { type: 'integer', required: true, immutable: false }, recipient: { type: 'did', required: true, immutable: false }, issuer: { type: 'view', viewType: 'documentAccount' }, }, - MultiplePoints: { + PointsAllocationInterface: { points: { type: 'integer', required: true, immutable: false }, recipient: { type: 'did', required: true, immutable: false }, issuer: { type: 'view', viewType: 'documentAccount' }, }, - MultiplePointsAllocation: { + PointsInterface: { points: { type: 'integer', required: true, immutable: false }, recipient: { type: 'did', required: true, immutable: false }, issuer: { type: 'view', viewType: 'documentAccount' }, }, - PointsAggregation: { + SimplePointsAggregation: { date: { type: 'datetime', required: true, immutable: false }, points: { type: 'integer', required: true, immutable: false }, - recipient: { type: 'did', required: true, immutable: false }, - issuer: { type: 'view', viewType: 'documentAccount' }, - }, - SinglePoint: { - recipient: { type: 'did', required: true, immutable: false }, - issuer: { type: 'view', viewType: 'documentAccount' }, - }, - SinglePointAllocation: { - recipient: { type: 'did', required: true, immutable: false }, + recipient: { type: 'did', required: true, immutable: true }, issuer: { type: 'view', viewType: 'documentAccount' }, }, - TotalPoints: { - date: { type: 'datetime', required: true, immutable: false }, + SimplePointsAllocation: { points: { type: 'integer', required: true, immutable: false }, - recipient: { type: 'did', required: true, immutable: true }, + recipient: { type: 'did', required: true, immutable: false }, issuer: { type: 'view', viewType: 'documentAccount' }, }, }, enums: {}, accountData: { - genericPointAllocationList: { type: 'connection', name: 'GenericPointAllocation' }, - multiplePointsAllocationList: { type: 'connection', name: 'MultiplePointsAllocation' }, - multiplePointsList: { type: 'connection', name: 'MultiplePoints' }, - pointsAggregationList: { type: 'connection', name: 'PointsAggregation' }, - recipientOfGenericPointAllocationList: { + pointsAggregationInterfaceList: { type: 'connection', name: 'PointsAggregationInterface' }, + pointsAllocationInterfaceList: { type: 'connection', name: 'PointsAllocationInterface' }, + pointsInterfaceList: { type: 'connection', name: 'PointsInterface' }, + recipientOfPointsAggregationInterfaceList: { type: 'account', - name: 'GenericPointAllocation', + name: 'PointsAggregationInterface', property: 'recipient', }, - recipientOfMultiplePointsAllocationList: { + recipientOfPointsAllocationInterfaceList: { type: 'account', - name: 'MultiplePointsAllocation', + name: 'PointsAllocationInterface', property: 'recipient', }, - recipientOfMultiplePointsList: { + recipientOfPointsInterfaceList: { type: 'account', - name: 'MultiplePoints', + name: 'PointsInterface', + property: 'recipient', + }, + recipientOfSimplePointsAggregation: { + type: 'account-set', + name: 'SimplePointsAggregation', property: 'recipient', }, - recipientOfPointsAggregationList: { + recipientOfSimplePointsAggregationList: { type: 'account', - name: 'PointsAggregation', + name: 'SimplePointsAggregation', property: 'recipient', }, - recipientOfSinglePointAllocationList: { + recipientOfSimplePointsAllocationList: { type: 'account', - name: 'SinglePointAllocation', + name: 'SimplePointsAllocation', property: 'recipient', }, - recipientOfSinglePointList: { type: 'account', name: 'SinglePoint', property: 'recipient' }, - recipientOfTotalPoints: { type: 'account-set', name: 'TotalPoints', property: 'recipient' }, - recipientOfTotalPointsList: { type: 'account', name: 'TotalPoints', property: 'recipient' }, - singlePointAllocationList: { type: 'connection', name: 'SinglePointAllocation' }, - singlePointList: { type: 'connection', name: 'SinglePoint' }, - totalPoints: { type: 'set', name: 'TotalPoints' }, - totalPointsList: { type: 'connection', name: 'TotalPoints' }, + simplePointsAggregation: { type: 'set', name: 'SimplePointsAggregation' }, + simplePointsAggregationList: { type: 'connection', name: 'SimplePointsAggregation' }, + simplePointsAllocationList: { type: 'connection', name: 'SimplePointsAllocation' }, }, } diff --git a/composites/points/src/index.ts b/composites/points/src/index.ts index 3f128f4..ec2c1f7 100644 --- a/composites/points/src/index.ts +++ b/composites/points/src/index.ts @@ -2,4 +2,8 @@ * @module points-composite */ -export { definition } from './definition.js' +import { definition } from './definition.js' + +export { definition } +export const SimplePointsAggregationID = definition.models.SimplePointsAggregation.id +export const SimplePointsAllocationID = definition.models.SimplePointsAllocation.id diff --git a/demo/server/src/controllers/singleController.ts b/demo/server/src/controllers/singleController.ts deleted file mode 100644 index 144e795..0000000 --- a/demo/server/src/controllers/singleController.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { getContext } from '../utils/context.js' -import { Request, Response, NextFunction } from 'express' -import { SinglePointReader, SinglePointWriter } from '@ceramic-solutions/points' - -export interface CreateSinglePointRequest extends Request { - body: { - recipient: string - } -} - -const createSinglePoint = async ( - req: CreateSinglePointRequest, - res: Response, - next: NextFunction, -) => { - try { - const { ceramic } = await getContext() - const writer = new SinglePointWriter({ ceramic }) - await writer.addPointTo(req.body.recipient) - res.locals.ceramic = ceramic - return next() - } catch (error) { - console.error(error) - return error - } -} - -const removeSinglePoint = async ( - req: CreateSinglePointRequest, - _res: Response, - next: NextFunction, -) => { - try { - const { ceramic } = await getContext() - const reader = new SinglePointReader({ - ceramic, - issuer: ceramic.did!.id, - }) - const documents = await reader.queryPointDocumentsFor(req.body.recipient) - const id = documents.documents[documents.documents.length - 1].id - const writer = new SinglePointWriter({ ceramic }) - await writer.removePoint(id.toString()) - return next() - } catch (error) { - console.error(error) - return error - } -} - -const getSinglePoints = async ( - req: CreateSinglePointRequest, - res: Response, - next: NextFunction, -) => { - try { - const { ceramic } = await getContext() - const reader = new SinglePointReader({ - ceramic, - issuer: ceramic.did!.id, - }) - const totalPoints = await reader.countPointsFor(req.body.recipient) - res.locals.totalPoints = totalPoints - return next() - } catch (error) { - console.error(error) - return error - } -} - -export const singlePointController = { createSinglePoint, getSinglePoints, removeSinglePoint } diff --git a/demo/server/src/index.ts b/demo/server/src/index.ts index 6b88baa..0a15ea5 100644 --- a/demo/server/src/index.ts +++ b/demo/server/src/index.ts @@ -1,6 +1,5 @@ import express, { json, Request, Response, NextFunction } from 'express' import cors from 'cors' -import singleRouter from './routes/single.js' import multiRouter from './routes/multi.js' const app = express() @@ -24,7 +23,6 @@ const allowCrossDomain = (_req: Request, res: Response, next: NextFunction) => { app.use(allowCrossDomain) -app.use('/single', singleRouter) app.use('/multi', multiRouter) app.listen(port, () => { diff --git a/demo/server/src/routes/single.ts b/demo/server/src/routes/single.ts deleted file mode 100644 index 040d039..0000000 --- a/demo/server/src/routes/single.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { RequestHandler, Response, Router, Request } from 'express' -import { singlePointController } from '../controllers/singleController.js' - -const router: Router = Router() - -type R = Response & { - locals: { - totalPoints: number - } -} - -router.get( - '/', - singlePointController.getSinglePoints as RequestHandler, - (_req: Request, res: R): Response => { - return res.json({ totalPoints: res.locals.totalPoints }) - }, -) - -router.post( - '/create', - singlePointController.createSinglePoint as RequestHandler, - singlePointController.getSinglePoints as RequestHandler, - (_req: Request, res: R): Response => { - return res.json({ totalPoints: res.locals.totalPoints }) - }, -) - -router.delete( - '/remove', - singlePointController.removeSinglePoint as RequestHandler, - singlePointController.getSinglePoints as RequestHandler, - (_req: Request, res: R): Response => { - return res.json({ totalPoints: res.locals.totalPoints }) - }, -) - -export default router diff --git a/demo/simple/index.mjs b/demo/simple/index.mjs index eece1bc..08b0a82 100644 --- a/demo/simple/index.mjs +++ b/demo/simple/index.mjs @@ -1,38 +1,36 @@ // Import statements using ES module syntax -import { fromString } from 'uint8arrays'; -import { CeramicClient } from "@ceramicnetwork/http-client"; -import { getAuthenticatedDID } from '@composexp/did-utils' -import { SinglePointReader, SinglePointWriter } from '@composexp/points'; +import { fromString } from 'uint8arrays' +import { CeramicClient } from '@ceramicnetwork/http-client' +import { getAuthenticatedDID } from '@ceramic-solutions/did-utils' +import { SinglePointReader, SinglePointWriter } from '@ceramic-solutions/points' // Environment variable for Ceramic URL (Ensure it's set in your environment) -const CERAMIC_URL = process.env.CERAMIC_URL; -const CERAMIC_PRIVATE_KEY = process.env.CERAMIC_PRIVATE_KEY; +const CERAMIC_URL = process.env.CERAMIC_URL +const CERAMIC_PRIVATE_KEY = process.env.CERAMIC_PRIVATE_KEY -const point_subject = process.argv[2]; +const point_subject = process.argv[2] // Main function wrapped in an immediately invoked function expression (IIFE) to handle async/await -(async () => { - +;(async () => { if (!point_subject) { - console.error("Usage: node assign_point.mjs [subject_did]"); - process.exit(1); + console.error('Usage: node assign_point.mjs [subject_did]') + process.exit(1) } - if (! CERAMIC_PRIVATE_KEY || ! CERAMIC_URL) { - console.error("You must set CERAMIC_URL and CERAMIC_PRIVATE_KEY in your environment"); - process.exit(1); + if (!CERAMIC_PRIVATE_KEY || !CERAMIC_URL) { + console.error('You must set CERAMIC_URL and CERAMIC_PRIVATE_KEY in your environment') + process.exit(1) } - const key = fromString(CERAMIC_PRIVATE_KEY, "base16"); + const key = fromString(CERAMIC_PRIVATE_KEY, 'base16') - const ceramic = new CeramicClient(CERAMIC_URL); - ceramic.did = await getAuthenticatedDID(key); + const ceramic = new CeramicClient(CERAMIC_URL) + ceramic.did = await getAuthenticatedDID(key) const writer = new SinglePointWriter({ ceramic }) const pointInstance = await writer.addPointTo(point_subject) - console.log(`Wrote point: ${pointInstance.id.toString()}`); + console.log(`Wrote point: ${pointInstance.id.toString()}`) - const reader = new SinglePointReader({ceramic: ceramic, issuer: ceramic.did.id}) + const reader = new SinglePointReader({ ceramic: ceramic, issuer: ceramic.did.id }) const total_points = await reader.countPointsFor(point_subject) console.log(`Added a point for ${point_subject} now they have ${total_points}`) -})(); - +})() diff --git a/libraries/points/src/index.ts b/libraries/points/src/index.ts index aa6f969..fb22082 100644 --- a/libraries/points/src/index.ts +++ b/libraries/points/src/index.ts @@ -8,10 +8,4 @@ export { PointsWriter, type PointsWriterParams, } from './points-writer.js' -export { SinglePointReader, type SinglePointReaderParams } from './single-reader.js' -export { - type SinglePointWriterFromSeedParams, - SinglePointWriter, - type SinglePointWriterParams, -} from './single-writer.js' export type { QueryDocumentsOptions, QueryDocumentsResult } from './types.js' diff --git a/libraries/points/src/points-reader.ts b/libraries/points/src/points-reader.ts index a9da022..d21bbcb 100644 --- a/libraries/points/src/points-reader.ts +++ b/libraries/points/src/points-reader.ts @@ -1,7 +1,10 @@ import type { BaseQuery } from '@ceramicnetwork/common' import { type DeterministicLoadOptions, DocumentLoader } from '@composedb/loader' import type { CeramicAPI, ModelInstanceDocument } from '@composedb/types' -import { definition } from '@ceramic-solutions/points-composite' +import { + SimplePointsAggregationID, + SimplePointsAllocationID, +} from '@ceramic-solutions/points-composite' import { getCeramic } from './ceramic.js' import { getQueryForRecipient, queryConnection } from './query.js' @@ -44,8 +47,8 @@ export class PointsReader< constructor(params: PointsReaderParams) { const ceramic = getCeramic(params.ceramic) - const aggregationModelID = params.aggregationModelID ?? definition.models.TotalPoints.id - const allocationModelID = params.allocationModelID ?? definition.models.MultiplePoints.id + const aggregationModelID = params.aggregationModelID ?? SimplePointsAggregationID + const allocationModelID = params.allocationModelID ?? SimplePointsAllocationID this.#aggregationBaseQuery = { account: params.issuer, models: [aggregationModelID] } this.#aggregationModelID = aggregationModelID diff --git a/libraries/points/src/single-reader.ts b/libraries/points/src/single-reader.ts deleted file mode 100644 index 117c96a..0000000 --- a/libraries/points/src/single-reader.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { BaseQuery } from '@ceramicnetwork/common' -import { DocumentLoader } from '@composedb/loader' -import type { CeramicAPI } from '@composedb/types' -import { definition } from '@ceramic-solutions/points-composite' - -import { getCeramic } from './ceramic.js' -import { getQueryForRecipient, queryConnection } from './query.js' -import type { QueryDocumentsOptions, QueryDocumentsResult } from './types.js' - -export type SinglePointContent = { - recipient: string -} - -export type SinglePointReaderParams = { - issuer: string - ceramic?: CeramicAPI | string - loader?: DocumentLoader - modelID?: string -} - -export class SinglePointReader { - #baseQuery: BaseQuery - #ceramic: CeramicAPI - #loader: DocumentLoader - #modelID: string - - constructor(params: SinglePointReaderParams) { - const ceramic = getCeramic(params.ceramic) - const modelID = params.modelID ?? definition.models.SinglePoint.id - - this.#baseQuery = { account: params.issuer, models: [modelID] } - this.#ceramic = ceramic - this.#loader = params.loader ?? new DocumentLoader({ ceramic }) - this.#modelID = modelID - } - - get ceramic(): CeramicAPI { - return this.#ceramic - } - - get loader(): DocumentLoader { - return this.#loader - } - - get modelID(): string { - return this.#modelID - } - - async countTotalPoints(): Promise { - return await this.#ceramic.index.count(this.#baseQuery) - } - - async queryPointDocumentsFor( - did: string, - options?: QueryDocumentsOptions, - ): Promise> { - const query = getQueryForRecipient(this.#baseQuery, did) - return await queryConnection(this.#loader, query, options) - } - - async countPointsFor(did: string): Promise { - const query = getQueryForRecipient(this.#baseQuery, did) - return await this.#ceramic.index.count(query) - } -} diff --git a/libraries/points/src/single-writer.ts b/libraries/points/src/single-writer.ts deleted file mode 100644 index 723527b..0000000 --- a/libraries/points/src/single-writer.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { DocumentLoader } from '@composedb/loader' -import type { CeramicAPI, ModelInstanceDocument } from '@composedb/types' - -import { getCeramic } from './ceramic.js' -import { getAuthenticatedDID } from './did.js' -import { type SinglePointContent, SinglePointReader } from './single-reader.js' - -export type SinglePointWriterFromSeedParams = { - ceramic?: CeramicAPI | string - loader?: DocumentLoader - modelID?: string - seed: Uint8Array -} - -export type SinglePointWriterParams = { - ceramic: CeramicAPI - loader?: DocumentLoader - modelID?: string -} - -export class SinglePointWriter< - Content extends SinglePointContent = SinglePointContent, -> extends SinglePointReader { - static async fromSeed( - params: SinglePointWriterFromSeedParams, - ): Promise> { - const ceramic = getCeramic(params.ceramic) - const did = await getAuthenticatedDID(params.seed) - ceramic.did = did - return new SinglePointWriter({ ceramic, loader: params.loader, modelID: params.modelID }) - } - - constructor(params: SinglePointWriterParams) { - if (!params.ceramic.did?.authenticated) { - throw new Error(`An authenticated DID instance must be set on the Ceramic client`) - } - super({ ...params, issuer: params.ceramic.did.id }) - } - - async addPointTo( - did: string, - content: Partial = {}, - ): Promise> { - return await this.loader.create(this.modelID, { ...content, recipient: did } as Content) - } - - async removePoint(id: string): Promise { - const doc = await this.loader.load({ id }) - if (doc.metadata.model.toString() !== this.modelID) { - throw new Error(`Document ${id} is not using the expected model ${this.modelID}`) - } - await doc.shouldIndex(false) - } -} diff --git a/libraries/points/test/lib.test.ts b/libraries/points/test/lib.test.ts index 95bdf97..f2a560b 100644 --- a/libraries/points/test/lib.test.ts +++ b/libraries/points/test/lib.test.ts @@ -4,63 +4,25 @@ import { DocumentLoader } from '@composedb/loader' import { type CeramicContext, getEphemeralCeramic } from '@ceramic-solutions/ceramic-utils' import { generatePrivateKey, getAuthenticatedDID } from '@ceramic-solutions/did-utils' import { deployComposite } from '@ceramic-solutions/composite-utils' -import { definition } from '@ceramic-solutions/points-composite' +import { + SimplePointsAggregationID, + SimplePointsAllocationID, +} from '@ceramic-solutions/points-composite' import { jest } from '@jest/globals' -import { PointsReader, PointsWriter, SinglePointReader, SinglePointWriter } from '../src' +import { PointsReader, PointsWriter } from '../src' const require = createRequire(import.meta.url) const compositePath = require.resolve('@ceramic-solutions/points-composite/composite.json') describe('points', () => { - describe('SinglePointReader class', () => { - test('getters', () => { - const reader = new SinglePointReader({ issuer: 'did:key:123' }) - expect(reader.ceramic).toBeInstanceOf(CeramicClient) - expect(reader.loader).toBeInstanceOf(DocumentLoader) - expect(reader.modelID).toBe(definition.models.SinglePoint!.id) - }) - - test('uses provided ceramic and modelID params', () => { - const ceramic = new CeramicClient() - const reader = new SinglePointReader({ ceramic, issuer: 'did:key:123', modelID: 'test' }) - expect(reader.ceramic).toBe(ceramic) - expect(reader.modelID).toBe('test') - }) - }) - - describe('SinglePointWriter class', () => { - test('requires an authenticated Ceramic DID', async () => { - const ceramic = new CeramicClient() - expect(() => { - new SinglePointWriter({ ceramic }) - }).toThrow('An authenticated DID instance must be set on the Ceramic client') - - ceramic.did = await getAuthenticatedDID(generatePrivateKey()) - expect(() => { - new SinglePointWriter({ ceramic }) - }).not.toThrow() - }) - - test('SinglePointWriter.fromSeed() authenticates the DID from the provided seed', async () => { - expect(SinglePointWriter.fromSeed({ seed: generatePrivateKey() })).resolves.toBeInstanceOf( - SinglePointWriter, - ) - }) - - test('extends SinglePointReader', async () => { - const writer = await SinglePointWriter.fromSeed({ seed: generatePrivateKey() }) - expect(writer).toBeInstanceOf(SinglePointReader) - }) - }) - describe('PointsReader class', () => { test('getters', () => { const reader = new PointsReader({ issuer: 'did:key:123' }) expect(reader.ceramic).toBeInstanceOf(CeramicClient) expect(reader.loader).toBeInstanceOf(DocumentLoader) - expect(reader.aggregationModelID).toBe(definition.models.TotalPoints!.id) - expect(reader.allocationModelID).toBe(definition.models.MultiplePoints!.id) + expect(reader.aggregationModelID).toBe(SimplePointsAggregationID) + expect(reader.allocationModelID).toBe(SimplePointsAllocationID) }) test('uses provided ceramic and modelID params', () => { @@ -115,105 +77,7 @@ describe('points', () => { await context.dispose() }) - describe('single point per document', () => { - test('write and read with single point documents', async () => { - const reader = new SinglePointReader({ ceramic: context.ceramic, issuer: context.did.id }) - const writer = new SinglePointWriter({ ceramic: context.ceramic }) - // Sanity check no points have been allocated yet - await expect(reader.countTotalPoints()).resolves.toBe(0) - // Add points to a first recipient account - await writer.addPointTo('did:test:123') - await writer.addPointTo('did:test:123') - await writer.addPointTo('did:test:123') - await expect(reader.countTotalPoints()).resolves.toBe(3) - await expect(reader.countPointsFor('did:test:123')).resolves.toBe(3) - await expect(reader.countPointsFor('did:test:456')).resolves.toBe(0) - // Add points to another recipient account - await writer.addPointTo('did:test:456') - await writer.addPointTo('did:test:456') - await expect(reader.countTotalPoints()).resolves.toBe(5) - await expect(reader.countPointsFor('did:test:123')).resolves.toBe(3) - await expect(reader.countPointsFor('did:test:456')).resolves.toBe(2) - }) - - test('multiple single point writers', async () => { - const [did1, did2] = await Promise.all([ - getAuthenticatedDID(generatePrivateKey()), - getAuthenticatedDID(generatePrivateKey()), - ]) - expect(did1.id).not.toBe(did2.id) - // Write points with a first issuer account - context.ceramic.did = did1 - const writer1 = new SinglePointWriter({ ceramic: context.ceramic }) - await writer1.addPointTo('did:test:123') - await expect(writer1.countPointsFor('did:test:123')).resolves.toBe(1) - // Write points with another issuer account - context.ceramic.did = did2 - const writer2 = new SinglePointWriter({ ceramic: context.ceramic }) - await writer2.addPointTo('did:test:123') - await writer2.addPointTo('did:test:123') - await expect(writer2.countPointsFor('did:test:123')).resolves.toBe(2) - // Sanity check the first issuer points count hasn't changed - await expect(writer1.countPointsFor('did:test:123')).resolves.toBe(1) - }) - - test('add and remove points using single point writer', async () => { - const writer = new SinglePointWriter({ ceramic: context.ceramic }) - const firstPoint = await writer.addPointTo('did:test:123') - const secondPoint = await writer.addPointTo('did:test:123') - await expect(writer.countPointsFor('did:test:123')).resolves.toBe(2) - // Check point removal only applies to the specified model - const modelID = definition.models.SinglePoint!.id - await expect(writer.removePoint(modelID)).rejects.toThrow( - `Document ${modelID} is not using the expected model ${modelID}`, - ) - // Remove added points - await writer.removePoint(firstPoint.id.toString()) - await expect(writer.countPointsFor('did:test:123')).resolves.toBe(1) - await writer.removePoint(secondPoint.id.toString()) - await expect(writer.countPointsFor('did:test:123')).resolves.toBe(0) - }) - - test('query single point documents', async () => { - const writer = new SinglePointWriter({ ceramic: context.ceramic }) - const createdDoc = await writer.addPointTo('did:test:123') - const loadedDoc = await writer.loader.load({ id: createdDoc.id.toString() }) - expect(loadedDoc?.id.equals(createdDoc.id)).toBe(true) - const createdDoc1 = await writer.addPointTo('did:test:123') - const createdDoc2 = await writer.addPointTo('did:test:123') - const createdDoc3 = await writer.addPointTo('did:test:123') - const createdDoc4 = await writer.addPointTo('did:test:123') - // First query without cursor, returns the last documents created - const query1 = await writer.queryPointDocumentsFor('did:test:123', { count: 2 }) - expect(query1.documents).toHaveLength(2) - expect(query1.documents.map((doc) => doc.id.toString())).toEqual([ - createdDoc3.id.toString(), - createdDoc4.id.toString(), - ]) - // Second query using cursor from the first query - const query2 = await writer.queryPointDocumentsFor('did:test:123', { - before: query1.startCursor, - }) - expect(query2.documents).toHaveLength(3) - expect(query2.documents.map((doc) => doc.id.toString())).toEqual([ - createdDoc.id.toString(), - createdDoc1.id.toString(), - createdDoc2.id.toString(), - ]) - // Third query for a specific slice in chronological order - const query3 = await writer.queryPointDocumentsFor('did:test:123', { - count: 2, - after: query2.startCursor, - }) - expect(query3.documents).toHaveLength(2) - expect(query3.documents.map((doc) => doc.id.toString())).toEqual([ - createdDoc1.id.toString(), - createdDoc2.id.toString(), - ]) - }) - }) - - describe('multiple points allocation documents', () => { + describe('allocation documents', () => { test('allocate points to multiple recipients', async () => { const writer = new PointsWriter({ ceramic: context.ceramic }) // Add points to a first recipient account @@ -247,7 +111,7 @@ describe('points', () => { await writer2.allocatePointsTo('did:test:123', 10) await writer2.allocatePointsTo('did:test:123', 10) // Count how many documents are written by issuer - const modelID = definition.models.MultiplePoints!.id + const modelID = SimplePointsAllocationID await expect(context.ceramic.index.count({ models: [modelID] })).resolves.toBe(3) await expect( context.ceramic.index.count({ account: did1.id, models: [modelID] }), @@ -265,7 +129,7 @@ describe('points', () => { writer.ceramic.index.count({ models: [writer.allocationModelID] }), ).resolves.toBe(2) // Check point removal only applies to the specified model - const modelID = definition.models.MultiplePoints!.id + const modelID = SimplePointsAllocationID await expect(writer.removePointsAllocation(modelID)).rejects.toThrow( `Document ${modelID} is not using the expected model ${modelID}`, ) @@ -319,7 +183,7 @@ describe('points', () => { }) }) - describe('points aggregation documents', () => { + describe('aggregation documents', () => { test('aggregate points', async () => { const writer = new PointsWriter({ ceramic: context.ceramic }) await expect(writer.loadAggregationDocumentFor('did:key:123')).resolves.toBeNull()