@eluvio/elv-client-js 4.2.25 → 4.2.29
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/package.json +5 -1
- package/src/EthClient.js +2 -1
- package/src/client/ABRPublishing.js +33 -19
- package/src/client/ContentAccess.js +70 -1
- package/src/client/Files.js +425 -219
- package/src/client/LiveStream.js +47 -21
- package/utilities/MediaIngest.js +424 -0
- package/utilities/MigrateEncryptionConkForNewUser.js +62 -0
- package/utilities/ObjectAddFiles.js +29 -9
- package/utilities/README_INGEST.md +332 -0
- package/utilities/lib/abr_profiles/abr_profile_4k_all.json +181 -0
- package/utilities/lib/concerns/Client.js +71 -10
- package/utilities/lib/concerns/CloudAccess.js +2 -2
- package/utilities/lib/concerns/CloudFile.js +16 -8
- package/utilities/lib/concerns/LocalFile.js +2 -1
- package/utilities/lib/data/network_specs.json +13 -0
- package/utilities/lib/models/CredentialSet.js +26 -7
- package/utilities/tests/unit/lib/concerns/Client.test.js +96 -0
|
@@ -34,7 +34,10 @@ const accessMatchIndex = R.curry(
|
|
|
34
34
|
const groupByPathMatch = (access, fileList) => R.groupBy(accessMatchIndex(access), fileList);
|
|
35
35
|
|
|
36
36
|
const validateBucketMatch = R.curry((credentialSet, sourceFilePath) => {
|
|
37
|
-
const
|
|
37
|
+
const remotePath = credentialSet.remote_access.path;
|
|
38
|
+
if(!remotePath) return;
|
|
39
|
+
|
|
40
|
+
const credentialSetBucket = removeTrailingSlash(remotePath);
|
|
38
41
|
// if full s3 path supplied, check bucket name
|
|
39
42
|
const s3prefixMatch = s3BucketRegex.exec(sourceFilePath);
|
|
40
43
|
if(s3prefixMatch) {
|
|
@@ -92,21 +95,24 @@ const New = context => {
|
|
|
92
95
|
);
|
|
93
96
|
};
|
|
94
97
|
|
|
95
|
-
const add = async ({libraryId, objectId, writeToken, files, access, encrypt, copy}) => {
|
|
98
|
+
const add = async ({libraryId, objectId, writeToken, files, access, encrypt, copy, resume}) => {
|
|
96
99
|
if(kindOf(copy) === "undefined") copy = isCopy();
|
|
97
100
|
files = files || context.args.files;
|
|
98
101
|
const groupedFiles = groupByPathMatch(access, files);
|
|
99
|
-
validatePathMatchGroups(groupedFiles);
|
|
102
|
+
validatePathMatchGroups(access, groupedFiles);
|
|
100
103
|
|
|
101
104
|
const client = await context.concerns.Client.get();
|
|
102
105
|
|
|
103
106
|
// iterate over file groups, add to fabric object using credential set for group
|
|
104
107
|
for(const [index, fileList] of R.toPairs(groupedFiles)) {
|
|
105
108
|
const credentialSet = access[index];
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
const
|
|
109
|
+
const remoteAccess = credentialSet.remote_access;
|
|
110
|
+
const cloudCredentials = remoteAccess.cloud_credentials;
|
|
111
|
+
const region = remoteAccess.storage_endpoint && remoteAccess.storage_endpoint.region;
|
|
112
|
+
const bucket = remoteAccess.path && removeTrailingSlash(remoteAccess.path);
|
|
113
|
+
const accessKey = cloudCredentials.access_key_id;
|
|
114
|
+
const secret = cloudCredentials.secret_access_key;
|
|
115
|
+
const signedUrl = cloudCredentials.signed_url;
|
|
110
116
|
|
|
111
117
|
await client.UploadFilesFromS3({
|
|
112
118
|
libraryId,
|
|
@@ -117,7 +123,9 @@ const New = context => {
|
|
|
117
123
|
bucket,
|
|
118
124
|
accessKey,
|
|
119
125
|
secret,
|
|
126
|
+
signedUrl,
|
|
120
127
|
copy,
|
|
128
|
+
resume,
|
|
121
129
|
callback,
|
|
122
130
|
encryption: encrypt ? "cgck" : "none"
|
|
123
131
|
});
|
|
@@ -134,4 +142,4 @@ const New = context => {
|
|
|
134
142
|
return {add, callback, credentialSet, fileInfo, isCopy};
|
|
135
143
|
};
|
|
136
144
|
|
|
137
|
-
module.exports = {blueprint, New};
|
|
145
|
+
module.exports = {blueprint, New};
|
|
@@ -19,7 +19,7 @@ const blueprint = {
|
|
|
19
19
|
|
|
20
20
|
const New = context => {
|
|
21
21
|
|
|
22
|
-
const add = async ({libraryId, objectId, writeToken, fileInfo, encrypt}) => {
|
|
22
|
+
const add = async ({libraryId, objectId, writeToken, fileInfo, encrypt, resume}) => {
|
|
23
23
|
const client = await context.concerns.Client.get();
|
|
24
24
|
await client.UploadFiles({
|
|
25
25
|
libraryId,
|
|
@@ -27,6 +27,7 @@ const New = context => {
|
|
|
27
27
|
writeToken,
|
|
28
28
|
fileInfo,
|
|
29
29
|
callback,
|
|
30
|
+
resume,
|
|
30
31
|
encryption: encrypt ? "cgck" : "none"
|
|
31
32
|
});
|
|
32
33
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dev": {
|
|
3
|
+
"contentSpaceId": "ispc3ANoVSzNA3P6t7abLR69ho5YPPZU",
|
|
4
|
+
"networkId": 955210,
|
|
5
|
+
"networkName": "dev",
|
|
6
|
+
"fabricVersion": 3,
|
|
7
|
+
"fabricURIs": ["http://127.0.0.1:8008"],
|
|
8
|
+
"ethereumURIs": ["https://host-76-74-28-234.contentfabric.io/eth/"],
|
|
9
|
+
"fileServiceURIs": ["http://127.0.0.1:8008"],
|
|
10
|
+
"authServiceURIs": [],
|
|
11
|
+
"searchURIs": []
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -16,17 +16,36 @@ const StorageEndpointModel = SealedModel({
|
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
const CloudCredentialsModel = SealedModel({
|
|
19
|
-
access_key_id: NonBlankString,
|
|
20
|
-
secret_access_key: NonBlankString
|
|
21
|
-
|
|
19
|
+
access_key_id: [NonBlankString],
|
|
20
|
+
secret_access_key: [NonBlankString],
|
|
21
|
+
signed_url: [NonBlankString]
|
|
22
|
+
}).assert(
|
|
23
|
+
function hasOneAuthenticationMethod(credentials) {
|
|
24
|
+
const hasAccessKey = Boolean(credentials.access_key_id);
|
|
25
|
+
const hasSecret = Boolean(credentials.secret_access_key);
|
|
26
|
+
const hasSignedUrl = Boolean(credentials.signed_url);
|
|
27
|
+
|
|
28
|
+
return hasSignedUrl
|
|
29
|
+
? !hasAccessKey && !hasSecret
|
|
30
|
+
: hasAccessKey && hasSecret;
|
|
31
|
+
},
|
|
32
|
+
"cloud_credentials must contain either signed_url or both access_key_id and secret_access_key"
|
|
33
|
+
);
|
|
22
34
|
|
|
23
35
|
const RemoteAccessModel = ObjectModel({
|
|
24
36
|
protocol: "s3",
|
|
25
37
|
platform: "aws",
|
|
26
|
-
path: NonBlankString,
|
|
27
|
-
storage_endpoint: StorageEndpointModel,
|
|
38
|
+
path: [NonBlankString],
|
|
39
|
+
storage_endpoint: [StorageEndpointModel],
|
|
28
40
|
cloud_credentials: CloudCredentialsModel
|
|
29
|
-
})
|
|
41
|
+
}).assert(
|
|
42
|
+
function hasLocationForAccessKeyCredentials(remoteAccess) {
|
|
43
|
+
if(remoteAccess.cloud_credentials.signed_url) return true;
|
|
44
|
+
|
|
45
|
+
return Boolean(remoteAccess.path && remoteAccess.storage_endpoint);
|
|
46
|
+
},
|
|
47
|
+
"path and storage_endpoint are required when using access key credentials"
|
|
48
|
+
);
|
|
30
49
|
|
|
31
50
|
const CredentialModel = ObjectModel({
|
|
32
51
|
path_matchers: TypedArrayNonEmpty(NonBlankString),
|
|
@@ -43,4 +62,4 @@ module.exports = {
|
|
|
43
62
|
CheckedCredentialSet,
|
|
44
63
|
CredentialModel,
|
|
45
64
|
CredentialSetModel,
|
|
46
|
-
};
|
|
65
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const {expect} = require("chai");
|
|
2
|
+
|
|
3
|
+
const {ElvClient} = require("../../../../../src/ElvClient");
|
|
4
|
+
const Client = require("../../../../lib/concerns/Client");
|
|
5
|
+
|
|
6
|
+
const logger = {
|
|
7
|
+
error: () => {},
|
|
8
|
+
log: () => {}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const context = ({args={}, env={}} = {}) => ({
|
|
12
|
+
args: {
|
|
13
|
+
ethContractTimeout: 10,
|
|
14
|
+
...args
|
|
15
|
+
},
|
|
16
|
+
concerns: {Logger: logger},
|
|
17
|
+
env: {
|
|
18
|
+
PRIVATE_KEY: "private-key",
|
|
19
|
+
...env
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const fakeClient = () => {
|
|
24
|
+
const nodeSelections = [];
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
GenerateWallet: () => ({AddAccount: () => ({})}),
|
|
28
|
+
SetNodes: nodes => nodeSelections.push(nodes),
|
|
29
|
+
SetSigner: async () => {},
|
|
30
|
+
ToggleLogging: () => {},
|
|
31
|
+
nodeSelections
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
describe("Client concern", () => {
|
|
36
|
+
let originalFromConfigurationUrl;
|
|
37
|
+
let originalFromNetworkName;
|
|
38
|
+
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
originalFromConfigurationUrl = ElvClient.FromConfigurationUrl;
|
|
41
|
+
originalFromNetworkName = ElvClient.FromNetworkName;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
ElvClient.FromConfigurationUrl = originalFromConfigurationUrl;
|
|
46
|
+
ElvClient.FromNetworkName = originalFromNetworkName;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("uses the main network by default", async () => {
|
|
50
|
+
let initArgs;
|
|
51
|
+
ElvClient.FromNetworkName = async args => {
|
|
52
|
+
initArgs = args;
|
|
53
|
+
return fakeClient();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
await Client.New(context()).get();
|
|
57
|
+
|
|
58
|
+
expect(initArgs.networkName).to.equal("main");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("uses a supplied config URL instead of the default network", async () => {
|
|
62
|
+
let initArgs;
|
|
63
|
+
ElvClient.FromConfigurationUrl = async args => {
|
|
64
|
+
initArgs = args;
|
|
65
|
+
return fakeClient();
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
await Client.New(context({args: {configUrl: "https://example.com/config"}})).get();
|
|
69
|
+
|
|
70
|
+
expect(initArgs.configUrl).to.equal("https://example.com/config");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("uses an explicitly selected built-in network", async () => {
|
|
74
|
+
let initArgs;
|
|
75
|
+
ElvClient.FromNetworkName = async args => {
|
|
76
|
+
initArgs = args;
|
|
77
|
+
return fakeClient();
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
await Client.New(context({args: {network: "demo"}})).get();
|
|
81
|
+
|
|
82
|
+
expect(initArgs.networkName).to.equal("demo");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("pins fabric and file-service requests to the supplied node", async () => {
|
|
86
|
+
const client = fakeClient();
|
|
87
|
+
ElvClient.FromNetworkName = async () => client;
|
|
88
|
+
|
|
89
|
+
await Client.New(context({args: {node: "fabric.example.com"}})).get();
|
|
90
|
+
|
|
91
|
+
expect(client.nodeSelections).to.deep.equal([{
|
|
92
|
+
fabricURIs: ["https://fabric.example.com"],
|
|
93
|
+
fileServiceURIs: ["https://fabric.example.com"]
|
|
94
|
+
}]);
|
|
95
|
+
});
|
|
96
|
+
});
|