@kumologica/sdk 3.0.0-alpha4
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/README.md +52 -0
- package/bin/kl.js +2 -0
- package/cli/KumologicaError.js +17 -0
- package/cli/cli.js +7 -0
- package/cli/commands/build-commands/aws.js +49 -0
- package/cli/commands/build-commands/azure.js +43 -0
- package/cli/commands/build-commands/kumohub.js +49 -0
- package/cli/commands/build.js +6 -0
- package/cli/commands/create-commands/create-project-iteratively.js +49 -0
- package/cli/commands/create-commands/index.js +5 -0
- package/cli/commands/create.js +66 -0
- package/cli/commands/deploy-commands/kumohub.js +114 -0
- package/cli/commands/deploy.js +6 -0
- package/cli/commands/doc-commands/html.js +60 -0
- package/cli/commands/doc.js +6 -0
- package/cli/commands/export-commands/cloudformation.js +371 -0
- package/cli/commands/export-commands/serverless.js +164 -0
- package/cli/commands/export-commands/terraform-commands/aws.js +193 -0
- package/cli/commands/export-commands/terraform-commands/azure.js +148 -0
- package/cli/commands/export-commands/terraform.js +6 -0
- package/cli/commands/export-commands/utils/validator.js +195 -0
- package/cli/commands/export.js +6 -0
- package/cli/commands/list-templates.js +24 -0
- package/cli/commands/open.js +53 -0
- package/cli/commands/start.js +165 -0
- package/cli/commands/test/TestSuiteRunner.js +76 -0
- package/cli/commands/test.js +123 -0
- package/cli/utils/download-template-from-repo.js +346 -0
- package/cli/utils/download-test.js +12 -0
- package/cli/utils/download.js +119 -0
- package/cli/utils/fs/copy-dir-contents-sync.js +15 -0
- package/cli/utils/fs/create-zip-file.js +39 -0
- package/cli/utils/fs/dir-exists-sync.js +14 -0
- package/cli/utils/fs/dir-exists.js +17 -0
- package/cli/utils/fs/file-exists-sync.js +14 -0
- package/cli/utils/fs/file-exists.js +12 -0
- package/cli/utils/fs/get-tmp-dir-path.js +22 -0
- package/cli/utils/fs/parse.js +40 -0
- package/cli/utils/fs/read-file-sync.js +11 -0
- package/cli/utils/fs/read-file.js +10 -0
- package/cli/utils/fs/safe-move-file.js +58 -0
- package/cli/utils/fs/walk-dir-sync.js +34 -0
- package/cli/utils/fs/write-file-sync.js +31 -0
- package/cli/utils/fs/write-file.js +32 -0
- package/cli/utils/logger.js +26 -0
- package/cli/utils/rename-service.js +49 -0
- package/package.json +72 -0
- package/src/api/core/comms.js +141 -0
- package/src/api/core/context.js +296 -0
- package/src/api/core/flows.js +286 -0
- package/src/api/core/index.js +29 -0
- package/src/api/core/library.js +106 -0
- package/src/api/core/nodes.js +476 -0
- package/src/api/core/projects.js +426 -0
- package/src/api/core/rest/context.js +42 -0
- package/src/api/core/rest/flow.js +53 -0
- package/src/api/core/rest/flows.js +53 -0
- package/src/api/core/rest/index.js +171 -0
- package/src/api/core/rest/nodes.js +164 -0
- package/src/api/core/rest/util.js +53 -0
- package/src/api/core/settings.js +287 -0
- package/src/api/tools/base/DesignerTool.js +108 -0
- package/src/api/tools/core/flow.js +58 -0
- package/src/api/tools/core/index.js +18 -0
- package/src/api/tools/core/node.js +77 -0
- package/src/api/tools/debugger/index.js +193 -0
- package/src/api/tools/filemanager/index.js +127 -0
- package/src/api/tools/git/index.js +103 -0
- package/src/api/tools/index.js +13 -0
- package/src/api/tools/test/index.js +56 -0
- package/src/api/tools/test/lib/TestCaseRunner.js +105 -0
- package/src/api/tools/test/lib/fixtures/example3-flow.json +148 -0
- package/src/api/tools/test/lib/fixtures/package.json +6 -0
- package/src/api/tools/test/lib/fixtures/s3-event.js +43 -0
- package/src/api/tools/test/lib/reporters/index.js +120 -0
- package/src/server/DesignerServer.js +141 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This is the comms subsystem of the runtime.
|
|
5
|
+
* @mixin @kumologica-core/runtime_comms
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A WebSocket connection between the runtime and the editor.
|
|
10
|
+
* @typedef CommsConnection
|
|
11
|
+
* @type {object}
|
|
12
|
+
* @property {string} session - a unique session identifier
|
|
13
|
+
* @property {Object} user - the user associated with the connection
|
|
14
|
+
* @property {Function} send - publish a message to the connection
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
var runtime;
|
|
19
|
+
var retained = {};
|
|
20
|
+
var connections = [];
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
function handleCommsEvent(event) {
|
|
24
|
+
publish(event.topic,event.data,event.retain);
|
|
25
|
+
}
|
|
26
|
+
function handleStatusEvent(event) {
|
|
27
|
+
var status = {
|
|
28
|
+
text: event.status.text,
|
|
29
|
+
fill: event.status.fill,
|
|
30
|
+
shape: event.status.shape
|
|
31
|
+
};
|
|
32
|
+
publish("status/"+event.id,status,true);
|
|
33
|
+
}
|
|
34
|
+
function handleRuntimeEvent(event) {
|
|
35
|
+
//runtime.log.trace("runtime event: "+JSON.stringify(event));
|
|
36
|
+
publish("notification/"+event.id,event.payload||{},event.retain);
|
|
37
|
+
}
|
|
38
|
+
function handleEventLog(event) {
|
|
39
|
+
var type = event.payload.type;
|
|
40
|
+
var id = event.id;
|
|
41
|
+
if (event.payload.data) {
|
|
42
|
+
var data = event.payload.data;
|
|
43
|
+
if (data.endsWith('\n')) {
|
|
44
|
+
data = data.substring(0,data.length-1);
|
|
45
|
+
}
|
|
46
|
+
var lines = data.split(/\n/);
|
|
47
|
+
lines.forEach(line => {
|
|
48
|
+
runtime.log.debug((type?("["+type+"] "):"")+line)
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
publish("event-log/"+event.id,event.payload||{});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function publish(topic,data,retain) {
|
|
55
|
+
if (retain) {
|
|
56
|
+
retained[topic] = data;
|
|
57
|
+
} else {
|
|
58
|
+
delete retained[topic];
|
|
59
|
+
}
|
|
60
|
+
connections.forEach(connection => connection.send(topic,data))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
var api = module.exports = {
|
|
65
|
+
init: function(_runtime) {
|
|
66
|
+
runtime = _runtime;
|
|
67
|
+
connections = [];
|
|
68
|
+
retained = {};
|
|
69
|
+
runtime.events.removeListener("node-status",handleStatusEvent);
|
|
70
|
+
runtime.events.on("node-status",handleStatusEvent);
|
|
71
|
+
runtime.events.removeListener("runtime-event",handleRuntimeEvent);
|
|
72
|
+
runtime.events.on("runtime-event",handleRuntimeEvent);
|
|
73
|
+
runtime.events.removeListener("comms",handleCommsEvent);
|
|
74
|
+
runtime.events.on("comms",handleCommsEvent);
|
|
75
|
+
runtime.events.removeListener("event-log",handleEventLog);
|
|
76
|
+
runtime.events.on("event-log",handleEventLog);
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Registers a new comms connection
|
|
81
|
+
* @param {Object} opts
|
|
82
|
+
* @param {User} opts.user - the user calling the api
|
|
83
|
+
* @param {CommsConnection} opts.client - the client connection
|
|
84
|
+
* @return {Promise<Object>} - resolves when complete
|
|
85
|
+
* @memberof @kumologica-core/runtime_comms
|
|
86
|
+
*/
|
|
87
|
+
addConnection: function(opts) {
|
|
88
|
+
connections.push(opts.client);
|
|
89
|
+
return Promise.resolve();
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Unregisters a comms connection
|
|
94
|
+
* @param {Object} opts
|
|
95
|
+
* @param {User} opts.user - the user calling the api
|
|
96
|
+
* @param {CommsConnection} opts.client - the client connection
|
|
97
|
+
* @return {Promise<Object>} - resolves when complete
|
|
98
|
+
* @memberof @kumologica-core/runtime_comms
|
|
99
|
+
*/
|
|
100
|
+
removeConnection: function(opts) {
|
|
101
|
+
for (var i=0;i<connections.length;i++) {
|
|
102
|
+
if (connections[i] === opts.client) {
|
|
103
|
+
connections.splice(i,1);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return Promise.resolve();
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Subscribes a comms connection to a given topic. Currently, all clients get
|
|
112
|
+
* automatically subscribed to everything and cannot unsubscribe. Sending a subscribe
|
|
113
|
+
* request will trigger retained messages to be sent.
|
|
114
|
+
* @param {Object} opts
|
|
115
|
+
* @param {User} opts.user - the user calling the api
|
|
116
|
+
* @param {CommsConnection} opts.client - the client connection
|
|
117
|
+
* @param {String} opts.topic - the topic to subscribe to
|
|
118
|
+
* @return {Promise<Object>} - resolves when complete
|
|
119
|
+
* @memberof @kumologica-core/runtime_comms
|
|
120
|
+
*/
|
|
121
|
+
subscribe: function(opts) {
|
|
122
|
+
var re = new RegExp("^"+opts.topic.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
|
|
123
|
+
for (var t in retained) {
|
|
124
|
+
if (re.test(t)) {
|
|
125
|
+
opts.client.send(t,retained[t]);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return Promise.resolve();
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* TODO: Unsubscribes a comms connection from a given topic
|
|
133
|
+
* @param {Object} opts
|
|
134
|
+
* @param {User} opts.user - the user calling the api
|
|
135
|
+
* @param {CommsConnection} opts.client - the client connection
|
|
136
|
+
* @param {String} opts.topic - the topic to unsubscribe from
|
|
137
|
+
* @return {Promise<Object>} - resolves when complete
|
|
138
|
+
* @memberof @kumologica-core/runtime_comms
|
|
139
|
+
*/
|
|
140
|
+
unsubscribe: function(opts) {}
|
|
141
|
+
};
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @mixin @kumologica-core/runtime_context
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
var runtime;
|
|
8
|
+
|
|
9
|
+
let util = require('@kumologica/runtime').util;
|
|
10
|
+
|
|
11
|
+
function exportContextStore(scope, ctx, store, result, callback) {
|
|
12
|
+
ctx.keys(store, function (err, keys) {
|
|
13
|
+
if (err) {
|
|
14
|
+
return callback(err);
|
|
15
|
+
}
|
|
16
|
+
result[store] = {};
|
|
17
|
+
var c = keys.length;
|
|
18
|
+
if (c === 0) {
|
|
19
|
+
callback(null);
|
|
20
|
+
} else {
|
|
21
|
+
keys.forEach(function (key) {
|
|
22
|
+
ctx.get(key, store, function (err, v) {
|
|
23
|
+
if (err) {
|
|
24
|
+
return callback(err);
|
|
25
|
+
}
|
|
26
|
+
if (
|
|
27
|
+
scope !== 'global' ||
|
|
28
|
+
store === runtime.nodes.listContextStores().default ||
|
|
29
|
+
!runtime.settings.hasOwnProperty('functionGlobalContext') ||
|
|
30
|
+
!runtime.settings.functionGlobalContext.hasOwnProperty(key) ||
|
|
31
|
+
runtime.settings.functionGlobalContext[key] !== v
|
|
32
|
+
) {
|
|
33
|
+
result[store][key] = util.encodeObject({ msg: v });
|
|
34
|
+
}
|
|
35
|
+
c--;
|
|
36
|
+
if (c === 0) {
|
|
37
|
+
callback(null);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var api = (module.exports = {
|
|
46
|
+
init: function (_runtime) {
|
|
47
|
+
runtime = _runtime;
|
|
48
|
+
},
|
|
49
|
+
/**
|
|
50
|
+
* Gets the info of an individual node set
|
|
51
|
+
* @param {Object} opts
|
|
52
|
+
* @param {User} opts.user - the user calling the api
|
|
53
|
+
* @param {String} opts.scope - the scope of the context
|
|
54
|
+
* @param {String} opts.id - the id of the context
|
|
55
|
+
* @param {String} opts.store - the context store
|
|
56
|
+
* @param {String} opts.key - the context key
|
|
57
|
+
|
|
58
|
+
* @return {Promise} - the node information
|
|
59
|
+
* @memberof @kumologica-core/runtime_context
|
|
60
|
+
*/
|
|
61
|
+
getValue: function (opts) {
|
|
62
|
+
return new Promise(function (resolve, reject) {
|
|
63
|
+
var scope = opts.scope;
|
|
64
|
+
var id = opts.id;
|
|
65
|
+
var store = opts.store;
|
|
66
|
+
var key = opts.key;
|
|
67
|
+
|
|
68
|
+
var availableStores = runtime.nodes.listContextStores();
|
|
69
|
+
//{ default: 'default', stores: [ 'default', 'file' ] }
|
|
70
|
+
if (store && availableStores.stores.indexOf(store) === -1) {
|
|
71
|
+
runtime.log.audit({
|
|
72
|
+
event: 'context.get',
|
|
73
|
+
scope: scope,
|
|
74
|
+
id: id,
|
|
75
|
+
store: store,
|
|
76
|
+
key: key,
|
|
77
|
+
error: 'not_found'
|
|
78
|
+
});
|
|
79
|
+
var err = new Error();
|
|
80
|
+
err.code = 'not_found';
|
|
81
|
+
err.status = 404;
|
|
82
|
+
return reject(err);
|
|
83
|
+
}
|
|
84
|
+
var ctx;
|
|
85
|
+
if (scope === 'global') {
|
|
86
|
+
ctx = runtime.nodes.getContext('global');
|
|
87
|
+
} else if (scope === 'flow') {
|
|
88
|
+
ctx = runtime.nodes.getContext(id);
|
|
89
|
+
} else if (scope === 'node') {
|
|
90
|
+
var node = runtime.nodes.getNode(id);
|
|
91
|
+
if (node) {
|
|
92
|
+
ctx = node.context();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (ctx) {
|
|
96
|
+
if (key) {
|
|
97
|
+
store = store || availableStores.default;
|
|
98
|
+
ctx.get(key, store, function (err, v) {
|
|
99
|
+
var encoded = util.encodeObject({ msg: v });
|
|
100
|
+
if (store !== availableStores.default) {
|
|
101
|
+
encoded.store = store;
|
|
102
|
+
}
|
|
103
|
+
runtime.log.audit({
|
|
104
|
+
event: 'context.get',
|
|
105
|
+
scope: scope,
|
|
106
|
+
id: id,
|
|
107
|
+
store: store,
|
|
108
|
+
key: key
|
|
109
|
+
});
|
|
110
|
+
resolve(encoded);
|
|
111
|
+
});
|
|
112
|
+
return;
|
|
113
|
+
} else {
|
|
114
|
+
var stores;
|
|
115
|
+
if (!store) {
|
|
116
|
+
stores = availableStores.stores;
|
|
117
|
+
} else {
|
|
118
|
+
stores = [store];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
var result = {};
|
|
122
|
+
var c = stores.length;
|
|
123
|
+
var errorReported = false;
|
|
124
|
+
stores.forEach(function (store) {
|
|
125
|
+
exportContextStore(scope, ctx, store, result, function (err) {
|
|
126
|
+
if (err) {
|
|
127
|
+
// TODO: proper error reporting
|
|
128
|
+
if (!errorReported) {
|
|
129
|
+
errorReported = true;
|
|
130
|
+
runtime.log.audit({
|
|
131
|
+
event: 'context.get',
|
|
132
|
+
scope: scope,
|
|
133
|
+
id: id,
|
|
134
|
+
store: store,
|
|
135
|
+
key: key,
|
|
136
|
+
error: 'unexpected_error'
|
|
137
|
+
});
|
|
138
|
+
var err = new Error();
|
|
139
|
+
err.code = 'unexpected_error';
|
|
140
|
+
err.status = 400;
|
|
141
|
+
return reject(err);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
c--;
|
|
147
|
+
if (c === 0) {
|
|
148
|
+
if (!errorReported) {
|
|
149
|
+
runtime.log.audit({
|
|
150
|
+
event: 'context.get',
|
|
151
|
+
scope: scope,
|
|
152
|
+
id: id,
|
|
153
|
+
store: store,
|
|
154
|
+
key: key
|
|
155
|
+
});
|
|
156
|
+
resolve(result);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
runtime.log.audit({
|
|
164
|
+
event: 'context.get',
|
|
165
|
+
scope: scope,
|
|
166
|
+
id: id,
|
|
167
|
+
store: store,
|
|
168
|
+
key: key
|
|
169
|
+
});
|
|
170
|
+
resolve({});
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Gets the info of an individual node set
|
|
177
|
+
* @param {Object} opts
|
|
178
|
+
* @param {User} opts.user - the user calling the api
|
|
179
|
+
* @param {String} opts.scope - the scope of the context
|
|
180
|
+
* @param {String} opts.id - the id of the context
|
|
181
|
+
* @param {String} opts.store - the context store
|
|
182
|
+
* @param {String} opts.key - the context key
|
|
183
|
+
|
|
184
|
+
* @return {Promise} - the node information
|
|
185
|
+
* @memberof @kumologica-core/runtime_context
|
|
186
|
+
*/
|
|
187
|
+
delete: function (opts) {
|
|
188
|
+
return new Promise(function (resolve, reject) {
|
|
189
|
+
var scope = opts.scope;
|
|
190
|
+
var id = opts.id;
|
|
191
|
+
var store = opts.store;
|
|
192
|
+
var key = opts.key;
|
|
193
|
+
|
|
194
|
+
var availableStores = runtime.nodes.listContextStores();
|
|
195
|
+
//{ default: 'default', stores: [ 'default', 'file' ] }
|
|
196
|
+
if (store && availableStores.stores.indexOf(store) === -1) {
|
|
197
|
+
runtime.log.audit({
|
|
198
|
+
event: 'context.get',
|
|
199
|
+
scope: scope,
|
|
200
|
+
id: id,
|
|
201
|
+
store: store,
|
|
202
|
+
key: key,
|
|
203
|
+
error: 'not_found'
|
|
204
|
+
});
|
|
205
|
+
var err = new Error();
|
|
206
|
+
err.code = 'not_found';
|
|
207
|
+
err.status = 404;
|
|
208
|
+
return reject(err);
|
|
209
|
+
}
|
|
210
|
+
var ctx;
|
|
211
|
+
if (scope === 'global') {
|
|
212
|
+
ctx = runtime.nodes.getContext('global');
|
|
213
|
+
} else if (scope === 'flow') {
|
|
214
|
+
ctx = runtime.nodes.getContext(id);
|
|
215
|
+
} else if (scope === 'node') {
|
|
216
|
+
var node = runtime.nodes.getNode(id);
|
|
217
|
+
if (node) {
|
|
218
|
+
ctx = node.context();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (ctx) {
|
|
222
|
+
if (key) {
|
|
223
|
+
store = store || availableStores.default;
|
|
224
|
+
ctx.set(key, undefined, store, function (err) {
|
|
225
|
+
runtime.log.audit({
|
|
226
|
+
event: 'context.delete',
|
|
227
|
+
scope: scope,
|
|
228
|
+
id: id,
|
|
229
|
+
store: store,
|
|
230
|
+
key: key
|
|
231
|
+
});
|
|
232
|
+
resolve();
|
|
233
|
+
});
|
|
234
|
+
return;
|
|
235
|
+
} else {
|
|
236
|
+
// TODO: support deleting whole context
|
|
237
|
+
runtime.log.audit({
|
|
238
|
+
event: 'context.get',
|
|
239
|
+
scope: scope,
|
|
240
|
+
id: id,
|
|
241
|
+
store: store,
|
|
242
|
+
key: key,
|
|
243
|
+
error: 'not_found'
|
|
244
|
+
});
|
|
245
|
+
var err = new Error();
|
|
246
|
+
err.code = 'not_found';
|
|
247
|
+
err.status = 404;
|
|
248
|
+
return reject(err);
|
|
249
|
+
// var stores;
|
|
250
|
+
// if (!store) {
|
|
251
|
+
// stores = availableStores.stores;
|
|
252
|
+
// } else {
|
|
253
|
+
// stores = [store];
|
|
254
|
+
// }
|
|
255
|
+
//
|
|
256
|
+
// var result = {};
|
|
257
|
+
// var c = stores.length;
|
|
258
|
+
// var errorReported = false;
|
|
259
|
+
// stores.forEach(function(store) {
|
|
260
|
+
// exportContextStore(scope,ctx,store,result,function(err) {
|
|
261
|
+
// if (err) {
|
|
262
|
+
// // TODO: proper error reporting
|
|
263
|
+
// if (!errorReported) {
|
|
264
|
+
// errorReported = true;
|
|
265
|
+
// runtime.log.audit({event: "context.delete",scope:scope,id:id,store:store,key:key,error:"unexpected_error"});
|
|
266
|
+
// var err = new Error();
|
|
267
|
+
// err.code = "unexpected_error";
|
|
268
|
+
// err.status = 400;
|
|
269
|
+
// return reject(err);
|
|
270
|
+
// }
|
|
271
|
+
//
|
|
272
|
+
// return;
|
|
273
|
+
// }
|
|
274
|
+
// c--;
|
|
275
|
+
// if (c === 0) {
|
|
276
|
+
// if (!errorReported) {
|
|
277
|
+
// runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key});
|
|
278
|
+
// resolve(result);
|
|
279
|
+
// }
|
|
280
|
+
// }
|
|
281
|
+
// });
|
|
282
|
+
// })
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
runtime.log.audit({
|
|
286
|
+
event: 'context.delete',
|
|
287
|
+
scope: scope,
|
|
288
|
+
id: id,
|
|
289
|
+
store: store,
|
|
290
|
+
key: key
|
|
291
|
+
});
|
|
292
|
+
resolve();
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
});
|