@eluvio/elv-client-js 3.2.39 → 3.2.41
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/dist/ElvClient-min.js +6 -6
- package/dist/ElvClient-node-min.js +9 -9
- package/dist/ElvFrameClient-min.js +1 -1
- package/dist/ElvPermissionsClient-min.js +7 -7
- package/dist/ElvWalletClient-min.js +6 -6
- package/dist/ElvWalletClient-node-min.js +10 -10
- package/dist/src/AuthorizationClient.js +599 -507
- package/dist/src/Utils.js +2 -1
- package/dist/src/client/ABRPublishing.js +2 -2
- package/dist/src/client/ContentManagement.js +44 -5
- package/dist/src/walletClient/Notifications.js +191 -0
- package/dist/src/walletClient/Utils.js +16 -5
- package/dist/src/walletClient/index.js +1 -0
- package/package.json +1 -1
- package/src/AuthorizationClient.js +43 -0
- package/src/Utils.js +2 -2
- package/src/client/ABRPublishing.js +2 -2
- package/src/client/ContentManagement.js +28 -2
- package/src/walletClient/Notifications.js +109 -0
- package/src/walletClient/index.js +1 -0
- package/testScripts/CreateProductionMaster.js +14 -6
- package/testScripts/abr_profile_4k_clear_store_encrypted.json +111 -0
- package/testScripts/{abr_profile_4k_clear.json → abr_profile_4k_clear_store_unencrypted.json} +0 -0
- package/testScripts/abr_profile_clear_store_encrypted.json +1945 -0
- package/testScripts/{abr_profile_clear.json → abr_profile_clear_store_unencrypted.json} +0 -0
- package/utilities/ProductionMasterCreate.js +18 -6
- package/utilities/example_files/abr_profile_4k_clear_store_encrypted.json +111 -0
- package/utilities/example_files/{abr_profile_4k_clear.json → abr_profile_4k_clear_store_unencrypted.json} +0 -0
- package/utilities/example_files/abr_profile_clear_hls_only_store_encrypted.json +1892 -0
- package/utilities/example_files/{abr_profile_clear_hls_only.json → abr_profile_clear_hls_only_store_unencrypted.json} +0 -0
- package/utilities/example_files/abr_profile_clear_store_encrypted.json +1899 -0
- /package/utilities/example_files/{abr_profile_clear.json → abr_profile_clear_store_unencrypted.json} +0 -0
package/dist/src/Utils.js
CHANGED
|
@@ -466,7 +466,8 @@ var Utils = {
|
|
|
466
466
|
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
467
467
|
},
|
|
468
468
|
B64: function B64(str) {
|
|
469
|
-
|
|
469
|
+
var encoding = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "utf-8";
|
|
470
|
+
return Buffer.from(str, encoding).toString("base64");
|
|
470
471
|
},
|
|
471
472
|
FromB64: function FromB64(str) {
|
|
472
473
|
return Buffer.from(str, "base64").toString("utf-8");
|
|
@@ -42,7 +42,7 @@ var _require = require("../Validation"),
|
|
|
42
42
|
* @param {string} contentTypeName - Name of the content type to use
|
|
43
43
|
* @param {Object=} metadata - Additional metadata for the content object
|
|
44
44
|
* @param {Array<Object>=} fileInfo - Files to upload (See UploadFiles/UploadFilesFromS3 method)
|
|
45
|
-
* @param {boolean=} encrypt=
|
|
45
|
+
* @param {boolean=} encrypt=true - (Local or copied files only) - Unless `false` is passed in explicitly, any uploaded/copied files will be stored encrypted
|
|
46
46
|
* @param {boolean=} copy=false - (S3) If specified, files will be copied from S3
|
|
47
47
|
* @param {function=} callback - Progress callback for file upload (See UploadFiles/UploadFilesFromS3 method)
|
|
48
48
|
* @param {Array<Object>=} access=[] - Array of cloud credentials, along with path matching regex strings - Required if any files in the masters are cloud references (currently only AWS S3 is supported)
|
|
@@ -87,7 +87,7 @@ exports.CreateProductionMaster = /*#__PURE__*/function () {
|
|
|
87
87
|
while (1) {
|
|
88
88
|
switch (_context.prev = _context.next) {
|
|
89
89
|
case 0:
|
|
90
|
-
libraryId = _ref.libraryId, type = _ref.type, name = _ref.name, description = _ref.description, _ref$metadata = _ref.metadata, metadata = _ref$metadata === void 0 ? {} : _ref$metadata, fileInfo = _ref.fileInfo, _ref$encrypt = _ref.encrypt, encrypt = _ref$encrypt === void 0 ?
|
|
90
|
+
libraryId = _ref.libraryId, type = _ref.type, name = _ref.name, description = _ref.description, _ref$metadata = _ref.metadata, metadata = _ref$metadata === void 0 ? {} : _ref$metadata, fileInfo = _ref.fileInfo, _ref$encrypt = _ref.encrypt, encrypt = _ref$encrypt === void 0 ? true : _ref$encrypt, _ref$access = _ref.access, access = _ref$access === void 0 ? [] : _ref$access, _ref$copy = _ref.copy, copy = _ref$copy === void 0 ? false : _ref$copy, callback = _ref.callback;
|
|
91
91
|
ValidateLibrary(libraryId);
|
|
92
92
|
_context.next = 4;
|
|
93
93
|
return this.CreateContentObject({
|
|
@@ -2646,7 +2646,8 @@ exports.UpdateContentObjectGraph = /*#__PURE__*/function () {
|
|
|
2646
2646
|
target: string (path to link target),
|
|
2647
2647
|
type: string ("file", "meta" | "metadata", "rep" - default "metadata")
|
|
2648
2648
|
targetHash: string (optional, for cross-object links),
|
|
2649
|
-
autoUpdate: boolean (if specified, link will be automatically updated to latest version by UpdateContentObjectGraph method)
|
|
2649
|
+
autoUpdate: boolean (if specified, link will be automatically updated to latest version by UpdateContentObjectGraph method),
|
|
2650
|
+
authContainer: string (optional, object id of container object if creating a signed link)
|
|
2650
2651
|
}
|
|
2651
2652
|
]
|
|
2652
2653
|
|
|
@@ -2678,7 +2679,7 @@ exports.CreateLinks = /*#__PURE__*/function () {
|
|
|
2678
2679
|
_context33.next = 5;
|
|
2679
2680
|
return this.utils.LimitedMap(10, links, /*#__PURE__*/function () {
|
|
2680
2681
|
var _ref57 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee31(info) {
|
|
2681
|
-
var path, type, target, link;
|
|
2682
|
+
var path, type, target, authTarget, link, linkMetadata;
|
|
2682
2683
|
return _regeneratorRuntime.wrap(function _callee31$(_context32) {
|
|
2683
2684
|
while (1) {
|
|
2684
2685
|
switch (_context32.prev = _context32.next) {
|
|
@@ -2690,7 +2691,7 @@ exports.CreateLinks = /*#__PURE__*/function () {
|
|
|
2690
2691
|
type = "meta";
|
|
2691
2692
|
}
|
|
2692
2693
|
|
|
2693
|
-
target = info.target.replace(/^(\/|\.)+/, "");
|
|
2694
|
+
target = authTarget = info.target.replace(/^(\/|\.)+/, "");
|
|
2694
2695
|
|
|
2695
2696
|
if (info.targetHash) {
|
|
2696
2697
|
target = "/qfab/".concat(info.targetHash, "/").concat(type, "/").concat(target);
|
|
@@ -2708,9 +2709,47 @@ exports.CreateLinks = /*#__PURE__*/function () {
|
|
|
2708
2709
|
tag: "latest"
|
|
2709
2710
|
}
|
|
2710
2711
|
};
|
|
2712
|
+
} // Sign link
|
|
2713
|
+
|
|
2714
|
+
|
|
2715
|
+
if (!info.authContainer) {
|
|
2716
|
+
_context32.next = 17;
|
|
2717
|
+
break;
|
|
2711
2718
|
}
|
|
2712
2719
|
|
|
2713
|
-
_context32.next =
|
|
2720
|
+
_context32.next = 10;
|
|
2721
|
+
return _this6.ContentObjectMetadata({
|
|
2722
|
+
libraryId: libraryId,
|
|
2723
|
+
objectId: objectId,
|
|
2724
|
+
metadataSubtree: path
|
|
2725
|
+
});
|
|
2726
|
+
|
|
2727
|
+
case 10:
|
|
2728
|
+
linkMetadata = _context32.sent;
|
|
2729
|
+
|
|
2730
|
+
if (linkMetadata) {
|
|
2731
|
+
link = linkMetadata;
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
if (!link["."]) link["."] = {};
|
|
2735
|
+
|
|
2736
|
+
if (linkMetadata["."]["authorization"]) {
|
|
2737
|
+
_context32.next = 17;
|
|
2738
|
+
break;
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
_context32.next = 16;
|
|
2742
|
+
return _this6.authClient.GenerateSignedLinkToken({
|
|
2743
|
+
containerId: info.authContainer,
|
|
2744
|
+
versionHash: info.targetHash,
|
|
2745
|
+
link: "./".concat(type, "/").concat(authTarget)
|
|
2746
|
+
});
|
|
2747
|
+
|
|
2748
|
+
case 16:
|
|
2749
|
+
link["."]["authorization"] = _context32.sent;
|
|
2750
|
+
|
|
2751
|
+
case 17:
|
|
2752
|
+
_context32.next = 19;
|
|
2714
2753
|
return _this6.ReplaceMetadata({
|
|
2715
2754
|
libraryId: libraryId,
|
|
2716
2755
|
objectId: objectId,
|
|
@@ -2719,7 +2758,7 @@ exports.CreateLinks = /*#__PURE__*/function () {
|
|
|
2719
2758
|
metadata: link
|
|
2720
2759
|
});
|
|
2721
2760
|
|
|
2722
|
-
case
|
|
2761
|
+
case 19:
|
|
2723
2762
|
case "end":
|
|
2724
2763
|
return _context32.stop();
|
|
2725
2764
|
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
var _regeneratorRuntime = require("@babel/runtime/regenerator");
|
|
2
|
+
|
|
3
|
+
var _asyncToGenerator = require("@babel/runtime/helpers/asyncToGenerator");
|
|
4
|
+
|
|
5
|
+
var Utils = require("../Utils");
|
|
6
|
+
|
|
7
|
+
var UrlJoin = require("url-join");
|
|
8
|
+
|
|
9
|
+
var NotificationPath = function NotificationPath(_ref) {
|
|
10
|
+
var network = _ref.network,
|
|
11
|
+
path = _ref.path;
|
|
12
|
+
return UrlJoin("/push", network === "main" ? "/main" : "/dv3", path);
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Push a notification to the current user
|
|
16
|
+
*
|
|
17
|
+
* @methodGroup Notifications
|
|
18
|
+
* @param {string} tenantId - The tenant associated with this notification
|
|
19
|
+
* @param {string} eventType - The type of the notification
|
|
20
|
+
* @param {(Object | string)=} data - Data associated with this notification
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
exports.PushNotification = /*#__PURE__*/function () {
|
|
25
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref2) {
|
|
26
|
+
var tenantId, eventType, data;
|
|
27
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
28
|
+
while (1) {
|
|
29
|
+
switch (_context.prev = _context.next) {
|
|
30
|
+
case 0:
|
|
31
|
+
tenantId = _ref2.tenantId, eventType = _ref2.eventType, data = _ref2.data;
|
|
32
|
+
_context.next = 3;
|
|
33
|
+
return this.stateStoreClient.Request({
|
|
34
|
+
method: "POST",
|
|
35
|
+
path: NotificationPath({
|
|
36
|
+
network: this.network,
|
|
37
|
+
path: UrlJoin("notify_user", this.UserAddress(), tenantId, eventType)
|
|
38
|
+
}),
|
|
39
|
+
body: data,
|
|
40
|
+
headers: {
|
|
41
|
+
Authorization: "Bearer ".concat(this.AuthToken())
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
case 3:
|
|
46
|
+
case "end":
|
|
47
|
+
return _context.stop();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}, _callee, this);
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
return function (_x) {
|
|
54
|
+
return _ref3.apply(this, arguments);
|
|
55
|
+
};
|
|
56
|
+
}();
|
|
57
|
+
/**
|
|
58
|
+
* Add a listener to receive new notifications.
|
|
59
|
+
*
|
|
60
|
+
* @methodGroup Notifications
|
|
61
|
+
* @param {function} onMessage - Callback invoked when a new notification is received
|
|
62
|
+
*
|
|
63
|
+
* @returns {Promise<EventSource>} - An EventSource instance listening for notifications. Use source.close() to close the listener.
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
exports.AddNotificationListener = /*#__PURE__*/function () {
|
|
68
|
+
var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref4) {
|
|
69
|
+
var onMessage, url, source;
|
|
70
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
71
|
+
while (1) {
|
|
72
|
+
switch (_context2.prev = _context2.next) {
|
|
73
|
+
case 0:
|
|
74
|
+
onMessage = _ref4.onMessage;
|
|
75
|
+
|
|
76
|
+
if (onMessage) {
|
|
77
|
+
_context2.next = 3;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw Error("Eluvio Wallet Client: No onMessage callback provided to AddNotificationListener");
|
|
82
|
+
|
|
83
|
+
case 3:
|
|
84
|
+
url = new URL(this.stateStoreClient.BaseURI().toString());
|
|
85
|
+
url.pathname = NotificationPath({
|
|
86
|
+
network: this.network,
|
|
87
|
+
path: UrlJoin("register", this.UserAddress(), this.AuthToken())
|
|
88
|
+
});
|
|
89
|
+
source = new EventSource(url);
|
|
90
|
+
|
|
91
|
+
source.onmessage = function (event) {
|
|
92
|
+
var parsedMessage = JSON.parse(event.data);
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
parsedMessage.data = JSON.parse(parsedMessage.data); // eslint-disable-next-line no-empty
|
|
96
|
+
} catch (error) {}
|
|
97
|
+
|
|
98
|
+
onMessage(parsedMessage);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return _context2.abrupt("return", source);
|
|
102
|
+
|
|
103
|
+
case 8:
|
|
104
|
+
case "end":
|
|
105
|
+
return _context2.stop();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, _callee2, this);
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
return function (_x2) {
|
|
112
|
+
return _ref5.apply(this, arguments);
|
|
113
|
+
};
|
|
114
|
+
}();
|
|
115
|
+
/**
|
|
116
|
+
* Retrieve notifications for the current user.
|
|
117
|
+
*
|
|
118
|
+
* @methodGroup Notifications
|
|
119
|
+
* @param {integer=} limit=10 - The maximum number of notifications to return
|
|
120
|
+
* @param {string=} tenantId - Filter notifications to only those related to the specified tenant
|
|
121
|
+
* @param {Array<string>=} types - Filter notifications to only the specified types
|
|
122
|
+
* @param {string=} offsetId - Return notifications older than the specified ID
|
|
123
|
+
*
|
|
124
|
+
* @returns {Promise<Array<Object>>} - A list of notifications for the specified parameters
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
exports.Notifications = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
129
|
+
var _ref7,
|
|
130
|
+
tenantId,
|
|
131
|
+
types,
|
|
132
|
+
offsetId,
|
|
133
|
+
_ref7$limit,
|
|
134
|
+
limit,
|
|
135
|
+
queryParams,
|
|
136
|
+
_yield$Utils$Response,
|
|
137
|
+
records,
|
|
138
|
+
_args3 = arguments;
|
|
139
|
+
|
|
140
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
141
|
+
while (1) {
|
|
142
|
+
switch (_context3.prev = _context3.next) {
|
|
143
|
+
case 0:
|
|
144
|
+
_ref7 = _args3.length > 0 && _args3[0] !== undefined ? _args3[0] : {}, tenantId = _ref7.tenantId, types = _ref7.types, offsetId = _ref7.offsetId, _ref7$limit = _ref7.limit, limit = _ref7$limit === void 0 ? 10 : _ref7$limit;
|
|
145
|
+
queryParams = {
|
|
146
|
+
limit: limit
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
if (tenantId) {
|
|
150
|
+
queryParams.tenant_id = tenantId;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (types) {
|
|
154
|
+
queryParams.types = Array.isArray(types) ? types.join(",") : types;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (offsetId) {
|
|
158
|
+
queryParams.offset_by = offsetId;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
_context3.next = 7;
|
|
162
|
+
return Utils.ResponseToJson(this.stateStoreClient.Request({
|
|
163
|
+
method: "GET",
|
|
164
|
+
path: NotificationPath({
|
|
165
|
+
network: this.network,
|
|
166
|
+
path: UrlJoin("history", this.UserAddress())
|
|
167
|
+
}),
|
|
168
|
+
queryParams: queryParams,
|
|
169
|
+
headers: {
|
|
170
|
+
Authorization: "Bearer ".concat(this.AuthToken())
|
|
171
|
+
}
|
|
172
|
+
}));
|
|
173
|
+
|
|
174
|
+
case 7:
|
|
175
|
+
_yield$Utils$Response = _context3.sent;
|
|
176
|
+
records = _yield$Utils$Response.records;
|
|
177
|
+
return _context3.abrupt("return", records.map(function (record) {
|
|
178
|
+
try {
|
|
179
|
+
record.data = JSON.parse(record.data); // eslint-disable-next-line no-empty
|
|
180
|
+
} catch (error) {}
|
|
181
|
+
|
|
182
|
+
return record;
|
|
183
|
+
}));
|
|
184
|
+
|
|
185
|
+
case 10:
|
|
186
|
+
case "end":
|
|
187
|
+
return _context3.stop();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}, _callee3, this);
|
|
191
|
+
}));
|
|
@@ -65,13 +65,24 @@ var FormatNFTDetails = function FormatNFTDetails(entry) {
|
|
|
65
65
|
var isListing = !!entry.id;
|
|
66
66
|
var metadata = (isListing ? entry.nft : entry.meta) || {};
|
|
67
67
|
var info = isListing ? entry.info : entry;
|
|
68
|
+
var paymentAccounts = entry.accepts || [];
|
|
68
69
|
var details = {
|
|
69
|
-
USDCAccepted:
|
|
70
|
-
|
|
70
|
+
USDCAccepted: paymentAccounts.length > 0,
|
|
71
|
+
USDCOnly: !!paymentAccounts.find(function (entry) {
|
|
72
|
+
return entry.preferred;
|
|
73
|
+
}),
|
|
74
|
+
EthUSDCAccepted: !!paymentAccounts.find(function (account) {
|
|
75
|
+
return account.type === "eth";
|
|
76
|
+
}),
|
|
77
|
+
EthUSDCOnly: !!paymentAccounts.find(function (account) {
|
|
78
|
+
return account.type === "eth" && account.preferred;
|
|
79
|
+
}),
|
|
80
|
+
SolUSDCAccepted: !!paymentAccounts.find(function (account) {
|
|
81
|
+
return account.type === "eth";
|
|
82
|
+
}),
|
|
83
|
+
SolUSDCOnly: !!paymentAccounts.find(function (account) {
|
|
84
|
+
return account.type === "eth" && account.preferred;
|
|
71
85
|
}),
|
|
72
|
-
USDCOnly: ((entry.accepts || []).find(function (entry) {
|
|
73
|
-
return entry.type === "sol";
|
|
74
|
-
}) || {}).preferred,
|
|
75
86
|
TenantId: entry.tenant || entry.tenant_id,
|
|
76
87
|
ContractAddr: info.contract_addr,
|
|
77
88
|
ContractId: "ictr".concat(Utils.AddressToHash(info.contract_addr)),
|
|
@@ -1971,4 +1971,5 @@ var ElvWalletClient = /*#__PURE__*/function () {
|
|
|
1971
1971
|
|
|
1972
1972
|
Object.assign(ElvWalletClient.prototype, require("./ClientMethods"));
|
|
1973
1973
|
Object.assign(ElvWalletClient.prototype, require("./Profile"));
|
|
1974
|
+
Object.assign(ElvWalletClient.prototype, require("./Notifications"));
|
|
1974
1975
|
exports.ElvWalletClient = ElvWalletClient;
|
package/package.json
CHANGED
|
@@ -3,6 +3,8 @@ const Ethers = require("ethers");
|
|
|
3
3
|
const Utils = require("./Utils");
|
|
4
4
|
const UrlJoin = require("url-join");
|
|
5
5
|
const {LogMessage} = require("./LogMessage");
|
|
6
|
+
const {ValidateObject} = require("./Validation");
|
|
7
|
+
const Pako = require("pako");
|
|
6
8
|
|
|
7
9
|
/*
|
|
8
10
|
// -- Contract javascript files built using build/BuildContracts.js
|
|
@@ -240,6 +242,47 @@ class AuthorizationClient {
|
|
|
240
242
|
return `${token}.${Utils.B64(multiSig)}`;
|
|
241
243
|
}
|
|
242
244
|
|
|
245
|
+
async GenerateSignedLinkToken({containerId, versionHash, link}) {
|
|
246
|
+
ValidateObject(containerId);
|
|
247
|
+
const canEdit = await this.client.CallContractMethod({
|
|
248
|
+
contractAddress: Utils.HashToAddress(containerId),
|
|
249
|
+
methodName: "canEdit"
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const { objectId } = Utils.DecodeVersionHash(versionHash);
|
|
253
|
+
|
|
254
|
+
if(!canEdit) {
|
|
255
|
+
throw Error(`Current user does not have permission to edit content object ${objectId}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const signerAddress = this.client.CurrentAccountAddress();
|
|
259
|
+
|
|
260
|
+
let token = {
|
|
261
|
+
adr: Utils.B64(signerAddress.replace("0x", ""), "hex"),
|
|
262
|
+
spc: await this.client.ContentSpaceId(),
|
|
263
|
+
lib: await this.client.ContentObjectLibraryId({objectId}),
|
|
264
|
+
qid: objectId,
|
|
265
|
+
sub: Utils.FormatAddress(signerAddress),
|
|
266
|
+
gra: "read",
|
|
267
|
+
iat: Date.now(),
|
|
268
|
+
exp: Date.now() + 3600000,
|
|
269
|
+
ctx: {
|
|
270
|
+
elv: {
|
|
271
|
+
lnk: link,
|
|
272
|
+
src: containerId
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const compressedToken = Pako.deflateRaw(Buffer.from(JSON.stringify(token), "utf-8"));
|
|
278
|
+
const signature = await this.Sign(Ethers.utils.keccak256(compressedToken));
|
|
279
|
+
|
|
280
|
+
return `aslsjc${Utils.B58(Buffer.concat([
|
|
281
|
+
Buffer.from(signature.replace(/^0x/, ""), "hex"),
|
|
282
|
+
Buffer.from(compressedToken)
|
|
283
|
+
]))}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
243
286
|
async MakeAccessRequest({
|
|
244
287
|
libraryId,
|
|
245
288
|
objectId,
|
package/src/Utils.js
CHANGED
|
@@ -433,8 +433,8 @@ const Utils = {
|
|
|
433
433
|
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
434
434
|
},
|
|
435
435
|
|
|
436
|
-
B64: str => {
|
|
437
|
-
return Buffer.from(str,
|
|
436
|
+
B64: (str, encoding="utf-8") => {
|
|
437
|
+
return Buffer.from(str, encoding).toString("base64");
|
|
438
438
|
},
|
|
439
439
|
|
|
440
440
|
FromB64: str => {
|
|
@@ -31,7 +31,7 @@ const {
|
|
|
31
31
|
* @param {string} contentTypeName - Name of the content type to use
|
|
32
32
|
* @param {Object=} metadata - Additional metadata for the content object
|
|
33
33
|
* @param {Array<Object>=} fileInfo - Files to upload (See UploadFiles/UploadFilesFromS3 method)
|
|
34
|
-
* @param {boolean=} encrypt=
|
|
34
|
+
* @param {boolean=} encrypt=true - (Local or copied files only) - Unless `false` is passed in explicitly, any uploaded/copied files will be stored encrypted
|
|
35
35
|
* @param {boolean=} copy=false - (S3) If specified, files will be copied from S3
|
|
36
36
|
* @param {function=} callback - Progress callback for file upload (See UploadFiles/UploadFilesFromS3 method)
|
|
37
37
|
* @param {Array<Object>=} access=[] - Array of cloud credentials, along with path matching regex strings - Required if any files in the masters are cloud references (currently only AWS S3 is supported)
|
|
@@ -73,7 +73,7 @@ exports.CreateProductionMaster = async function({
|
|
|
73
73
|
description,
|
|
74
74
|
metadata={},
|
|
75
75
|
fileInfo,
|
|
76
|
-
encrypt=
|
|
76
|
+
encrypt=true,
|
|
77
77
|
access=[],
|
|
78
78
|
copy=false,
|
|
79
79
|
callback
|
|
@@ -1319,7 +1319,8 @@ exports.UpdateContentObjectGraph = async function({libraryId, objectId, versionH
|
|
|
1319
1319
|
target: string (path to link target),
|
|
1320
1320
|
type: string ("file", "meta" | "metadata", "rep" - default "metadata")
|
|
1321
1321
|
targetHash: string (optional, for cross-object links),
|
|
1322
|
-
autoUpdate: boolean (if specified, link will be automatically updated to latest version by UpdateContentObjectGraph method)
|
|
1322
|
+
autoUpdate: boolean (if specified, link will be automatically updated to latest version by UpdateContentObjectGraph method),
|
|
1323
|
+
authContainer: string (optional, object id of container object if creating a signed link)
|
|
1323
1324
|
}
|
|
1324
1325
|
]
|
|
1325
1326
|
|
|
@@ -1348,7 +1349,9 @@ exports.CreateLinks = async function({
|
|
|
1348
1349
|
let type = (info.type || "file") === "file" ? "files" : info.type;
|
|
1349
1350
|
if(type === "metadata") { type = "meta"; }
|
|
1350
1351
|
|
|
1351
|
-
let target
|
|
1352
|
+
let target;
|
|
1353
|
+
let authTarget;
|
|
1354
|
+
target = authTarget = info.target.replace(/^(\/|\.)+/, "");
|
|
1352
1355
|
if(info.targetHash) {
|
|
1353
1356
|
target = `/qfab/${info.targetHash}/${type}/${target}`;
|
|
1354
1357
|
} else {
|
|
@@ -1363,6 +1366,29 @@ exports.CreateLinks = async function({
|
|
|
1363
1366
|
link["."] = { auto_update: { tag: "latest"} };
|
|
1364
1367
|
}
|
|
1365
1368
|
|
|
1369
|
+
// Sign link
|
|
1370
|
+
if(info.authContainer) {
|
|
1371
|
+
const linkMetadata = await this.ContentObjectMetadata({
|
|
1372
|
+
libraryId,
|
|
1373
|
+
objectId,
|
|
1374
|
+
metadataSubtree: path
|
|
1375
|
+
});
|
|
1376
|
+
|
|
1377
|
+
if(linkMetadata) {
|
|
1378
|
+
link = linkMetadata;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
if(!link["."]) link["."] = {};
|
|
1382
|
+
|
|
1383
|
+
if(!linkMetadata["."]["authorization"]) {
|
|
1384
|
+
link["."]["authorization"] = await this.authClient.GenerateSignedLinkToken({
|
|
1385
|
+
containerId: info.authContainer,
|
|
1386
|
+
versionHash: info.targetHash,
|
|
1387
|
+
link: `./${type}/${authTarget}`
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1366
1392
|
await this.ReplaceMetadata({
|
|
1367
1393
|
libraryId,
|
|
1368
1394
|
objectId,
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Methods related to notifications for the current user.
|
|
3
|
+
*
|
|
4
|
+
* @module Notifications
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const Utils = require("../Utils");
|
|
9
|
+
const UrlJoin = require("url-join");
|
|
10
|
+
|
|
11
|
+
const NotificationPath = ({network, path}) => {
|
|
12
|
+
return UrlJoin("/push", network === "main" ? "/main" : "/dv3", path);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Push a notification to the current user
|
|
17
|
+
*
|
|
18
|
+
* @methodGroup Notifications
|
|
19
|
+
* @param {string} tenantId - The tenant associated with this notification
|
|
20
|
+
* @param {string} eventType - The type of the notification
|
|
21
|
+
* @param {(Object | string)=} data - Data associated with this notification
|
|
22
|
+
*/
|
|
23
|
+
exports.PushNotification = async function({tenantId, eventType, data}) {
|
|
24
|
+
await this.stateStoreClient.Request({
|
|
25
|
+
method: "POST",
|
|
26
|
+
path: NotificationPath({network: this.network, path: UrlJoin("notify_user", this.UserAddress(), tenantId, eventType)}),
|
|
27
|
+
body: data,
|
|
28
|
+
headers: {
|
|
29
|
+
Authorization: `Bearer ${this.AuthToken()}`
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Add a listener to receive new notifications.
|
|
36
|
+
*
|
|
37
|
+
* @methodGroup Notifications
|
|
38
|
+
* @param {function} onMessage - Callback invoked when a new notification is received
|
|
39
|
+
*
|
|
40
|
+
* @returns {Promise<EventSource>} - An EventSource instance listening for notifications. Use source.close() to close the listener.
|
|
41
|
+
*/
|
|
42
|
+
exports.AddNotificationListener = async function({onMessage}) {
|
|
43
|
+
if(!onMessage) {
|
|
44
|
+
throw Error("Eluvio Wallet Client: No onMessage callback provided to AddNotificationListener");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const url = new URL(this.stateStoreClient.BaseURI().toString());
|
|
48
|
+
url.pathname = NotificationPath({network: this.network, path: UrlJoin("register", this.UserAddress(), this.AuthToken())});
|
|
49
|
+
const source = new EventSource(url);
|
|
50
|
+
source.onmessage = event => {
|
|
51
|
+
let parsedMessage = JSON.parse(event.data);
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
parsedMessage.data = JSON.parse(parsedMessage.data);
|
|
55
|
+
// eslint-disable-next-line no-empty
|
|
56
|
+
} catch(error) {}
|
|
57
|
+
|
|
58
|
+
onMessage(parsedMessage);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return source;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Retrieve notifications for the current user.
|
|
66
|
+
*
|
|
67
|
+
* @methodGroup Notifications
|
|
68
|
+
* @param {integer=} limit=10 - The maximum number of notifications to return
|
|
69
|
+
* @param {string=} tenantId - Filter notifications to only those related to the specified tenant
|
|
70
|
+
* @param {Array<string>=} types - Filter notifications to only the specified types
|
|
71
|
+
* @param {string=} offsetId - Return notifications older than the specified ID
|
|
72
|
+
*
|
|
73
|
+
* @returns {Promise<Array<Object>>} - A list of notifications for the specified parameters
|
|
74
|
+
*/
|
|
75
|
+
exports.Notifications = async function({tenantId, types, offsetId, limit=10}={}) {
|
|
76
|
+
let queryParams = { limit };
|
|
77
|
+
|
|
78
|
+
if(tenantId) {
|
|
79
|
+
queryParams.tenant_id = tenantId;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if(types) {
|
|
83
|
+
queryParams.types = Array.isArray(types) ? types.join(",") : types;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if(offsetId) {
|
|
87
|
+
queryParams.offset_by = offsetId;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const {records} = await Utils.ResponseToJson(
|
|
91
|
+
this.stateStoreClient.Request({
|
|
92
|
+
method: "GET",
|
|
93
|
+
path: NotificationPath({network: this.network, path: UrlJoin("history", this.UserAddress())}),
|
|
94
|
+
queryParams,
|
|
95
|
+
headers: {
|
|
96
|
+
Authorization: `Bearer ${this.AuthToken()}`
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
return records.map(record => {
|
|
102
|
+
try {
|
|
103
|
+
record.data = JSON.parse(record.data);
|
|
104
|
+
// eslint-disable-next-line no-empty
|
|
105
|
+
} catch(error) {}
|
|
106
|
+
|
|
107
|
+
return record;
|
|
108
|
+
});
|
|
109
|
+
};
|
|
@@ -1146,5 +1146,6 @@ class ElvWalletClient {
|
|
|
1146
1146
|
|
|
1147
1147
|
Object.assign(ElvWalletClient.prototype, require("./ClientMethods"));
|
|
1148
1148
|
Object.assign(ElvWalletClient.prototype, require("./Profile"));
|
|
1149
|
+
Object.assign(ElvWalletClient.prototype, require("./Notifications"));
|
|
1149
1150
|
|
|
1150
1151
|
exports.ElvWalletClient = ElvWalletClient;
|
|
@@ -41,7 +41,11 @@ const argv = yargs
|
|
|
41
41
|
})
|
|
42
42
|
.option("encrypt", {
|
|
43
43
|
type: "boolean",
|
|
44
|
-
description: "
|
|
44
|
+
description: "DEPRECATED, HAS NO EFFECT: uploaded/copied files will always be stored encrypted unless --unencrypted specified."
|
|
45
|
+
})
|
|
46
|
+
.option("unencrypted", {
|
|
47
|
+
type: "boolean",
|
|
48
|
+
description: "Store uploaded/copied files unencrypted on server"
|
|
45
49
|
})
|
|
46
50
|
.option("s3-copy", {
|
|
47
51
|
type: "boolean",
|
|
@@ -85,13 +89,19 @@ const Create = async ({
|
|
|
85
89
|
slug,
|
|
86
90
|
metadata,
|
|
87
91
|
files,
|
|
88
|
-
encrypt
|
|
92
|
+
encrypt,
|
|
93
|
+
unencrypted,
|
|
89
94
|
s3Reference,
|
|
90
95
|
s3Copy,
|
|
91
96
|
credentials,
|
|
92
97
|
debug
|
|
93
98
|
}) => {
|
|
94
99
|
|
|
100
|
+
if(encrypt && unencrypted) {
|
|
101
|
+
console.error("Cannot specify both --encrypted and --unencrypted");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
95
105
|
// force ipTitleId to be a string, if present
|
|
96
106
|
if(ipTitleId) {
|
|
97
107
|
ipTitleId = ipTitleId.toString();
|
|
@@ -220,9 +230,7 @@ const Create = async ({
|
|
|
220
230
|
type = await client.ContentType({name: type});
|
|
221
231
|
}
|
|
222
232
|
|
|
223
|
-
if(!type) {
|
|
224
|
-
throw Error(`Unable to find content type "${originalType}"`);
|
|
225
|
-
}
|
|
233
|
+
if(!type) throw Error(`Unable to find content type "${originalType}"`);
|
|
226
234
|
|
|
227
235
|
type = type.hash;
|
|
228
236
|
|
|
@@ -234,7 +242,7 @@ const Create = async ({
|
|
|
234
242
|
description: "Production Master for " + title,
|
|
235
243
|
metadata,
|
|
236
244
|
fileInfo,
|
|
237
|
-
encrypt,
|
|
245
|
+
encrypt: !unencrypted,
|
|
238
246
|
access,
|
|
239
247
|
copy: s3Copy && !s3Reference,
|
|
240
248
|
callback: progress => {
|