@yvhitxcel/opencode-remote 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +82 -0
  2. package/bin/opencode-remote.js +70 -0
  3. package/bin/opencode-weixin.js +10 -0
  4. package/dist/AGENTS.md +20 -0
  5. package/dist/MEMORY.md +21 -0
  6. package/dist/bot-runner.js +180 -0
  7. package/dist/cli.js +256 -0
  8. package/dist/core/approval.js +95 -0
  9. package/dist/core/auth.js +119 -0
  10. package/dist/core/config.js +61 -0
  11. package/dist/core/notifications.js +134 -0
  12. package/dist/core/qiniu.js +267 -0
  13. package/dist/core/registry.js +86 -0
  14. package/dist/core/router.js +344 -0
  15. package/dist/core/session.js +403 -0
  16. package/dist/core/setup.js +418 -0
  17. package/dist/core/types.js +16 -0
  18. package/dist/feishu/adapter.js +72 -0
  19. package/dist/feishu/bot.js +168 -0
  20. package/dist/feishu/commands.js +601 -0
  21. package/dist/feishu/handler.js +380 -0
  22. package/dist/index.js +60 -0
  23. package/dist/opencode/client.js +823 -0
  24. package/dist/package-lock.json +762 -0
  25. package/dist/patch_spawn.js +28 -0
  26. package/dist/plugins/agents/acp/acp-adapter.js +42 -0
  27. package/dist/plugins/agents/claude-code/index.js +69 -0
  28. package/dist/plugins/agents/codex/index.js +44 -0
  29. package/dist/plugins/agents/copilot/index.js +44 -0
  30. package/dist/plugins/agents/opencode/index.js +66 -0
  31. package/dist/telegram/bot.js +288 -0
  32. package/dist/utils/message-split.js +38 -0
  33. package/dist/web/code-viewer.js +266 -0
  34. package/dist/weixin/adapter.js +135 -0
  35. package/dist/weixin/api.js +179 -0
  36. package/dist/weixin/bot.js +183 -0
  37. package/dist/weixin/commands.js +758 -0
  38. package/dist/weixin/handler.js +577 -0
  39. package/dist/weixin/node_modules/encodeurl/LICENSE +22 -0
  40. package/dist/weixin/node_modules/encodeurl/README.md +109 -0
  41. package/dist/weixin/node_modules/encodeurl/index.js +60 -0
  42. package/dist/weixin/node_modules/encodeurl/package.json +40 -0
  43. package/dist/weixin/node_modules/qiniu/.claude/settings.local.json +7 -0
  44. package/dist/weixin/node_modules/qiniu/.github/workflows/ci-test.yml +36 -0
  45. package/dist/weixin/node_modules/qiniu/.github/workflows/npm-publish.yml +20 -0
  46. package/dist/weixin/node_modules/qiniu/.github/workflows/version-check.yml +19 -0
  47. package/dist/weixin/node_modules/qiniu/.idea/MarsCodeWorkspaceAppSettings.xml +7 -0
  48. package/dist/weixin/node_modules/qiniu/.idea/codeStyles/Project.xml +44 -0
  49. package/dist/weixin/node_modules/qiniu/.idea/codeStyles/codeStyleConfig.xml +5 -0
  50. package/dist/weixin/node_modules/qiniu/.idea/git_toolbox_blame.xml +6 -0
  51. package/dist/weixin/node_modules/qiniu/.idea/inspectionProfiles/Project_Default.xml +6 -0
  52. package/dist/weixin/node_modules/qiniu/.idea/jsLibraryMappings.xml +6 -0
  53. package/dist/weixin/node_modules/qiniu/.idea/modules.xml +8 -0
  54. package/dist/weixin/node_modules/qiniu/.idea/nodejs-sdk.iml +12 -0
  55. package/dist/weixin/node_modules/qiniu/.idea/vcs.xml +6 -0
  56. package/dist/weixin/node_modules/qiniu/CHANGELOG.md +292 -0
  57. package/dist/weixin/node_modules/qiniu/README.md +56 -0
  58. package/dist/weixin/node_modules/qiniu/StorageResponseInterface.d.ts +239 -0
  59. package/dist/weixin/node_modules/qiniu/codecov.yml +28 -0
  60. package/dist/weixin/node_modules/qiniu/index.d.ts +1995 -0
  61. package/dist/weixin/node_modules/qiniu/index.js +32 -0
  62. package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/HISTORY.md +14 -0
  63. package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/LICENSE +22 -0
  64. package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/README.md +128 -0
  65. package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/index.js +60 -0
  66. package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/package.json +40 -0
  67. package/dist/weixin/node_modules/qiniu/package.json +80 -0
  68. package/dist/weixin/node_modules/qiniu/qiniu/auth/digest.js +13 -0
  69. package/dist/weixin/node_modules/qiniu/qiniu/cdn.js +149 -0
  70. package/dist/weixin/node_modules/qiniu/qiniu/conf.js +254 -0
  71. package/dist/weixin/node_modules/qiniu/qiniu/fop.js +112 -0
  72. package/dist/weixin/node_modules/qiniu/qiniu/httpc/client.js +253 -0
  73. package/dist/weixin/node_modules/qiniu/qiniu/httpc/endpoint.js +66 -0
  74. package/dist/weixin/node_modules/qiniu/qiniu/httpc/endpointsProvider.js +27 -0
  75. package/dist/weixin/node_modules/qiniu/qiniu/httpc/endpointsRetryPolicy.js +76 -0
  76. package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/base.js +31 -0
  77. package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/index.js +9 -0
  78. package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/qiniuAuth.js +53 -0
  79. package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/retryDomains.js +101 -0
  80. package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/ua.js +36 -0
  81. package/dist/weixin/node_modules/qiniu/qiniu/httpc/region.js +349 -0
  82. package/dist/weixin/node_modules/qiniu/qiniu/httpc/regionsProvider.js +788 -0
  83. package/dist/weixin/node_modules/qiniu/qiniu/httpc/regionsRetryPolicy.js +242 -0
  84. package/dist/weixin/node_modules/qiniu/qiniu/httpc/responseWrapper.js +40 -0
  85. package/dist/weixin/node_modules/qiniu/qiniu/retry/index.js +4 -0
  86. package/dist/weixin/node_modules/qiniu/qiniu/retry/retrier.js +99 -0
  87. package/dist/weixin/node_modules/qiniu/qiniu/retry/retryPolicy.js +55 -0
  88. package/dist/weixin/node_modules/qiniu/qiniu/rpc.js +237 -0
  89. package/dist/weixin/node_modules/qiniu/qiniu/rtc/app.js +123 -0
  90. package/dist/weixin/node_modules/qiniu/qiniu/rtc/credentials.js +57 -0
  91. package/dist/weixin/node_modules/qiniu/qiniu/rtc/room.js +118 -0
  92. package/dist/weixin/node_modules/qiniu/qiniu/rtc/util.js +16 -0
  93. package/dist/weixin/node_modules/qiniu/qiniu/sms/message.js +58 -0
  94. package/dist/weixin/node_modules/qiniu/qiniu/storage/form.js +442 -0
  95. package/dist/weixin/node_modules/qiniu/qiniu/storage/internal.js +214 -0
  96. package/dist/weixin/node_modules/qiniu/qiniu/storage/resume.js +1272 -0
  97. package/dist/weixin/node_modules/qiniu/qiniu/storage/rs.js +1764 -0
  98. package/dist/weixin/node_modules/qiniu/qiniu/util.js +382 -0
  99. package/dist/weixin/node_modules/qiniu/qiniu/zone.js +230 -0
  100. package/dist/weixin/node_modules/qiniu/tsconfig.json +112 -0
  101. package/dist/weixin/types.js +25 -0
  102. package/package.json +56 -0
@@ -0,0 +1,1764 @@
1
+ const querystring = require('querystring');
2
+ const encodeUrl = require('encodeurl');
3
+ const client = require('../httpc/client');
4
+ const conf = require('../conf');
5
+ const digest = require('../auth/digest');
6
+ const util = require('../util');
7
+ const middleware = require('../httpc/middleware');
8
+ const { SERVICE_NAME } = require('../httpc/region');
9
+ const { EndpointsRetryPolicy } = require('../httpc/endpointsRetryPolicy');
10
+ const { RegionsRetryPolicy } = require('../httpc/regionsRetryPolicy');
11
+ const { Retrier } = require('../retry');
12
+ const pkg = require('../../package.json');
13
+
14
+ const { handleReqCallback } = require('./internal');
15
+
16
+ exports.BucketManager = BucketManager;
17
+ exports.PutPolicy = PutPolicy;
18
+
19
+ /**
20
+ * @typedef {function(Error, any, IncomingMessage)} BucketOperationCallback
21
+ */
22
+
23
+ /**
24
+ * @param {digest.Mac} [mac]
25
+ * @param {conf.Config} [config]
26
+ * @constructor
27
+ */
28
+ function BucketManager (mac, config) {
29
+ this.mac = mac || new digest.Mac();
30
+ this.config = config || new conf.Config();
31
+
32
+ let uaMiddleware = new middleware.UserAgentMiddleware(pkg.version);
33
+ // compact set UA by conf.USER_AGENT
34
+ uaMiddleware = Object.defineProperty(uaMiddleware, 'userAgent', {
35
+ get: function () {
36
+ return conf.USER_AGENT;
37
+ }
38
+ });
39
+ this._httpClient = new client.HttpClient({
40
+ middlewares: [
41
+ uaMiddleware,
42
+ new middleware.QiniuAuthMiddleware({
43
+ mac: this.mac
44
+ })
45
+ ]
46
+ });
47
+ }
48
+
49
+ /**
50
+ * @private
51
+ * @param {Endpoint} endpoint
52
+ * @returns {string}
53
+ */
54
+ function _getEndpointVal (endpoint) {
55
+ const preferredScheme = this.config.useHttpsDomain ? 'https' : 'http';
56
+ return endpoint.getValue({
57
+ scheme: preferredScheme
58
+ });
59
+ }
60
+
61
+ /**
62
+ * @private
63
+ * @param {RegionsProvider} options.regionsProvider
64
+ * @param {SERVICE_NAME} options.serviceName
65
+ * @returns {RetryPolicy[]}
66
+ */
67
+ function _getRetryPolicies (options) {
68
+ const {
69
+ regionsProvider,
70
+ serviceName
71
+ } = options;
72
+ return [
73
+ new EndpointsRetryPolicy({
74
+ skipInitContext: true
75
+ }),
76
+ new RegionsRetryPolicy({
77
+ regionsProvider,
78
+ serviceNames: [serviceName]
79
+ })
80
+ ];
81
+ }
82
+
83
+ /**
84
+ * @private
85
+ * @param {Object} options
86
+ * @param {string} options.bucketName
87
+ * @param {SERVICE_NAME} options.serviceName
88
+ * @returns {Promise<Retrier>}
89
+ */
90
+ function _getRegionsRetrier (options) {
91
+ const {
92
+ bucketName,
93
+ serviceName
94
+ } = options;
95
+ return this.config.getRegionsProvider({
96
+ bucketName,
97
+ accessKey: this.mac.accessKey
98
+ })
99
+ .then(regionsProvider => {
100
+ const retryPolicies = _getRetryPolicies.call(this, {
101
+ regionsProvider,
102
+ serviceName
103
+ });
104
+ return new Retrier({
105
+ retryPolicies,
106
+ onBeforeRetry: context => {
107
+ if (context.error) {
108
+ return true;
109
+ }
110
+ return context.result && context.result.needRetry();
111
+ }
112
+ });
113
+ });
114
+ }
115
+
116
+ /**
117
+ * @private
118
+ * @param {Object} options
119
+ * @param {EndpointsProvider} options.ucProvider
120
+ * @returns {RetryPolicy[]}
121
+ */
122
+ function _getUcRetryPolices (options) {
123
+ const {
124
+ ucProvider
125
+ } = options;
126
+ return [
127
+ new EndpointsRetryPolicy({
128
+ endpointsProvider: ucProvider
129
+ })
130
+ ];
131
+ }
132
+
133
+ /**
134
+ * @private
135
+ * @returns {Retrier}
136
+ */
137
+ function _getUcRetrier () {
138
+ const ucProvider = this.config.getUcEndpointsProvider();
139
+ return new Retrier({
140
+ retryPolicies: _getUcRetryPolices.call(this, {
141
+ ucProvider
142
+ }),
143
+ onBeforeRetry: context => {
144
+ if (context.error) {
145
+ return true;
146
+ }
147
+ return context.result && context.result.needRetry();
148
+ }
149
+ });
150
+ }
151
+
152
+ /**
153
+ * @param {string} [options.bucketName]
154
+ * @param {SERVICE_NAME} options.serviceName
155
+ * @param {function(RegionsRetryPolicyContext | EndpointsRetryPolicyContext): Promise<any>} options.func
156
+ * @param {BucketOperationCallback} [options.callbackFunc]
157
+ * @returns {Promise<any>}
158
+ * @private
159
+ */
160
+ function _tryReq (options) {
161
+ const {
162
+ bucketName,
163
+ serviceName,
164
+ func,
165
+ callbackFunc
166
+ } = options;
167
+
168
+ if (serviceName === SERVICE_NAME.UC) {
169
+ const retrier = _getUcRetrier.call(this);
170
+ const result = retrier.initContext()
171
+ .then(context => retrier.retry({
172
+ func,
173
+ context
174
+ }));
175
+ handleReqCallback(result, callbackFunc);
176
+ return result;
177
+ }
178
+
179
+ if (!bucketName) {
180
+ return Promise.reject(new Error('Must provide bucket name for non-uc services'));
181
+ }
182
+
183
+ const result = _getRegionsRetrier.call(this, {
184
+ bucketName,
185
+ serviceName
186
+ })
187
+ .then(retrier => Promise.all([
188
+ retrier,
189
+ retrier.initContext()
190
+ ]))
191
+ .then(([retrier, context]) => retrier.retry({
192
+ func,
193
+ context
194
+ }));
195
+ handleReqCallback(result, callbackFunc);
196
+ return result;
197
+ }
198
+
199
+ /**
200
+ * 获取资源信息
201
+ * @link https://developer.qiniu.com/kodo/api/1308/stat
202
+ * @param {string} bucket 空间名称
203
+ * @param {string} key 文件名称
204
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
205
+ * @returns {Promise<any>}
206
+ */
207
+ BucketManager.prototype.stat = function (bucket, key, callbackFunc) {
208
+ const statOp = exports.statOp(bucket, key);
209
+ return _tryReq.call(this, {
210
+ bucketName: bucket,
211
+ serviceName: SERVICE_NAME.RS,
212
+ func: context => {
213
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + statOp;
214
+ return this._httpClient.get({
215
+ url: requestURL
216
+ });
217
+ },
218
+ callbackFunc
219
+ });
220
+ };
221
+
222
+ /**
223
+ * 修改文件的类型
224
+ * @link https://developer.qiniu.com/kodo/api/1252/chgm
225
+ * @param {string} bucket 空间名称
226
+ * @param {string} key 文件名称
227
+ * @param {string} newMime 新文件类型
228
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
229
+ * @returns {Promise<any>}
230
+ */
231
+ BucketManager.prototype.changeMime = function (
232
+ bucket,
233
+ key,
234
+ newMime,
235
+ callbackFunc
236
+ ) {
237
+ const changeMimeOp = exports.changeMimeOp(bucket, key, newMime);
238
+ return _tryReq.call(this, {
239
+ bucketName: bucket,
240
+ serviceName: SERVICE_NAME.RS,
241
+ func: context => {
242
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + changeMimeOp;
243
+ return this._httpClient.post({
244
+ url: requestURL
245
+ });
246
+ },
247
+ callbackFunc
248
+ });
249
+ };
250
+
251
+ /**
252
+ * 修改文件返回的 Headers 内容
253
+ * @link https://developer.qiniu.com/kodo/1252/chgm
254
+ * @param {string} bucket 空间名称
255
+ * @param {string} key 文件名称
256
+ * @param {Object.<string, string>} headers 需要修改的 headers
257
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
258
+ * @returns {Promise<any>}
259
+ */
260
+ BucketManager.prototype.changeHeaders = function (
261
+ bucket,
262
+ key,
263
+ headers,
264
+ callbackFunc
265
+ ) {
266
+ const changeHeadersOp = exports.changeHeadersOp(bucket, key, headers);
267
+ return _tryReq.call(this, {
268
+ bucketName: bucket,
269
+ serviceName: SERVICE_NAME.RS,
270
+ func: context => {
271
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + changeHeadersOp;
272
+ return this._httpClient.post({
273
+ url: requestURL
274
+ });
275
+ },
276
+ callbackFunc
277
+ });
278
+ };
279
+
280
+ /**
281
+ * 移动或重命名文件,当 bucketSrc == bucketDest 相同的时候,就是重命名文件操作
282
+ * @link https://developer.qiniu.com/kodo/1288/move
283
+ * @param {string} srcBucket 源空间名称
284
+ * @param {string} srcKey 源文件名称
285
+ * @param {string} destBucket 目标空间名称
286
+ * @param {string} destKey 目标文件名称
287
+ * @param {Object} [options] 可选参数
288
+ * @param {boolean} [options.force] 强制覆盖
289
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
290
+ * @returns {Promise<any>}
291
+ */
292
+ BucketManager.prototype.move = function (
293
+ srcBucket,
294
+ srcKey,
295
+ destBucket,
296
+ destKey,
297
+ options,
298
+ callbackFunc
299
+ ) {
300
+ const moveOp = exports.moveOp(srcBucket, srcKey, destBucket, destKey, options);
301
+ return _tryReq.call(this, {
302
+ bucketName: srcBucket,
303
+ serviceName: SERVICE_NAME.RS,
304
+ func: context => {
305
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + moveOp;
306
+ return this._httpClient.post({
307
+ url: requestURL
308
+ });
309
+ },
310
+ callbackFunc
311
+ });
312
+ };
313
+
314
+ /**
315
+ * 复制一个文件
316
+ * @link https://developer.qiniu.com/kodo/1254/copy
317
+ * @param {string} srcBucket 源空间名称
318
+ * @param {string} srcKey 源文件名称
319
+ * @param {string} destBucket 目标空间名称
320
+ * @param {string} destKey 目标文件名称
321
+ * @param {Object} [options] 可选参数
322
+ * @param {boolean} [options.force] 强制覆盖
323
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
324
+ * @returns {Promise<any>}
325
+ */
326
+ BucketManager.prototype.copy = function (
327
+ srcBucket,
328
+ srcKey,
329
+ destBucket,
330
+ destKey,
331
+ options,
332
+ callbackFunc
333
+ ) {
334
+ const copyOp = exports.copyOp(srcBucket, srcKey, destBucket, destKey, options);
335
+ return _tryReq.call(this, {
336
+ bucketName: srcBucket,
337
+ serviceName: SERVICE_NAME.RS,
338
+ func: context => {
339
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + copyOp;
340
+ return this._httpClient.post({
341
+ url: requestURL
342
+ });
343
+ },
344
+ callbackFunc
345
+ });
346
+ };
347
+
348
+ /**
349
+ * 删除资源
350
+ * @link https://developer.qiniu.com/kodo/1257/delete
351
+ * @param {string} bucket 空间名称
352
+ * @param {string} key 文件名称
353
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
354
+ * @returns {Promise<any>}
355
+ */
356
+ BucketManager.prototype.delete = function (bucket, key, callbackFunc) {
357
+ const deleteOp = exports.deleteOp(bucket, key);
358
+ return _tryReq.call(this, {
359
+ bucketName: bucket,
360
+ serviceName: SERVICE_NAME.RS,
361
+ func: context => {
362
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + deleteOp;
363
+ return this._httpClient.post({
364
+ url: requestURL
365
+ });
366
+ },
367
+ callbackFunc
368
+ });
369
+ };
370
+
371
+ /**
372
+ * 更新文件的生命周期
373
+ * @link https://developer.qiniu.com/kodo/1732/update-file-lifecycle
374
+ * @param {string} bucket 空间名称
375
+ * @param {string} key 文件名称
376
+ * @param {number} days 有效期天数
377
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
378
+ * @returns {Promise<any>}
379
+ */
380
+ BucketManager.prototype.deleteAfterDays = function (
381
+ bucket,
382
+ key,
383
+ days,
384
+ callbackFunc
385
+ ) {
386
+ const deleteAfterDaysOp = exports.deleteAfterDaysOp(bucket, key, days);
387
+ return _tryReq.call(this, {
388
+ bucketName: bucket,
389
+ serviceName: SERVICE_NAME.RS,
390
+ func: context => {
391
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + deleteAfterDaysOp;
392
+ return this._httpClient.post({
393
+ url: requestURL
394
+ });
395
+ },
396
+ callbackFunc
397
+ });
398
+ };
399
+
400
+ /**
401
+ * @param {string} bucket - 空间名称
402
+ * @param {string} key - 文件名称
403
+ * @param {Object} [options] - 配置项
404
+ * @param {number} [options.toIaAfterDays] - 多少天后将文件转为低频存储,设置为 -1 表示取消已设置的转低频存储的生命周期规则, 0 表示不修改转低频生命周期规则。
405
+ * @param {number} [options.toArchiveAfterDays] - 多少天后将文件转为归档存储,设置为 -1 表示取消已设置的转归档存储的生命周期规则, 0 表示不修改转归档生命周期规则。
406
+ * @param {number} [options.toArchiveIRAfterDays] - 多少天后将文件转为归档直读存储,设置为 -1 表示取消已设置的转归档直读存储的生命周期规则, 0 表示不修改转归档直读生命周期规则。
407
+ * @param {number} [options.toDeepArchiveAfterDays] - 多少天后将文件转为深度归档存储,设置为 -1 表示取消已设置的转深度归档存储的生命周期规则, 0 表示不修改转深度归档生命周期规则。
408
+ * @param {number} [options.deleteAfterDays] - 多少天后将文件删除,设置为 -1 表示取消已设置的删除存储的生命周期规则, 0 表示不修改删除存储的生命周期规则。
409
+ * @param {Object} [options.cond] - 匹配条件,只有条件匹配才会设置成功
410
+ * @param {string} [options.cond.hash]
411
+ * @param {string} [options.cond.mime]
412
+ * @param {number} [options.cond.fsize]
413
+ * @param {number} [options.cond.putTime]
414
+ * @param {function} [callbackFunc] - 回调函数
415
+ * @returns {Promise<any>}
416
+ */
417
+ BucketManager.prototype.setObjectLifeCycle = function (
418
+ bucket,
419
+ key,
420
+ options,
421
+ callbackFunc
422
+ ) {
423
+ options = options || {};
424
+ const setObjectLifecycleOp = exports.setObjectLifecycleOp(bucket, key, options);
425
+ return _tryReq.call(this, {
426
+ bucketName: bucket,
427
+ serviceName: SERVICE_NAME.RS,
428
+ func: context => {
429
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + setObjectLifecycleOp;
430
+ return this._httpClient.post({
431
+ url: requestURL
432
+ });
433
+ },
434
+ callbackFunc
435
+ });
436
+ };
437
+
438
+ /**
439
+ * 抓取资源
440
+ * @link https://developer.qiniu.com/kodo/1263/fetch
441
+ * @param {string} resUrl 资源链接
442
+ * @param {string} bucket 空间名称
443
+ * @param {string} key 文件名称
444
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
445
+ * @returns {Promise<any>}
446
+ */
447
+ BucketManager.prototype.fetch = function (resUrl, bucket, key, callbackFunc) {
448
+ const encodedEntryURI = util.encodedEntry(bucket, key);
449
+ const encodedResURL = util.urlsafeBase64Encode(resUrl);
450
+ const fetchOp = `/fetch/${encodedResURL}/to/${encodedEntryURI}`;
451
+
452
+ return _tryReq.call(this, {
453
+ bucketName: bucket,
454
+ serviceName: SERVICE_NAME.IO,
455
+ func: context => {
456
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + fetchOp;
457
+ return this._httpClient.post({
458
+ url: requestURL
459
+ });
460
+ },
461
+ callbackFunc
462
+ });
463
+ };
464
+
465
+ /**
466
+ * 镜像资源更新
467
+ * @link https://developer.qiniu.com/kodo/1293/prefetch
468
+ * @param {string} bucket 空间名称
469
+ * @param {string} key 文件名称
470
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
471
+ * @returns {Promise<any>}
472
+ */
473
+ BucketManager.prototype.prefetch = function (bucket, key, callbackFunc) {
474
+ const encodedEntryURI = util.encodedEntry(bucket, key);
475
+ const prefetchOp = `/prefetch/${encodedEntryURI}`;
476
+ return _tryReq.call(this, {
477
+ bucketName: bucket,
478
+ serviceName: SERVICE_NAME.IO,
479
+ func: context => {
480
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + prefetchOp;
481
+ return this._httpClient.post({
482
+ url: requestURL
483
+ });
484
+ },
485
+ callbackFunc
486
+ });
487
+ };
488
+
489
+ /**
490
+ * 修改文件的存储类型
491
+ * @link https://developer.qiniu.com/kodo/3710/chtype
492
+ * @param {string} bucket 空间名称
493
+ * @param {string} key 文件名称
494
+ * @param {number} newType 新文件存储类型
495
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
496
+ * @returns {Promise<any>}
497
+ */
498
+ BucketManager.prototype.changeType = function (
499
+ bucket,
500
+ key,
501
+ newType,
502
+ callbackFunc
503
+ ) {
504
+ const changeTypeOp = exports.changeTypeOp(bucket, key, newType);
505
+ return _tryReq.call(this, {
506
+ bucketName: bucket,
507
+ serviceName: SERVICE_NAME.RS,
508
+ func: context => {
509
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + changeTypeOp;
510
+ return this._httpClient.post({
511
+ url: requestURL
512
+ });
513
+ },
514
+ callbackFunc
515
+ });
516
+ };
517
+
518
+ /**
519
+ * 设置空间镜像源
520
+ * @link https://developer.qiniu.com/kodo/3966/bucket-image-source
521
+ * @param {string} bucket 空间名称
522
+ * @param {string} srcSiteUrl 镜像源地址
523
+ * @param {string} [srcHost] 镜像Host
524
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
525
+ * @returns {Promise<any>}
526
+ */
527
+ BucketManager.prototype.image = function (
528
+ bucket,
529
+ srcSiteUrl,
530
+ srcHost,
531
+ callbackFunc
532
+ ) {
533
+ const encodedSrcSite = util.urlsafeBase64Encode(srcSiteUrl);
534
+ let reqOp = `/image/${bucket}/from/${encodedSrcSite}`;
535
+ if (srcHost) {
536
+ const encodedHost = util.urlsafeBase64Encode(srcHost);
537
+ reqOp += `/host/${encodedHost}`;
538
+ }
539
+ return _tryReq.call(this, {
540
+ bucketName: bucket,
541
+ serviceName: SERVICE_NAME.UC,
542
+ func: context => {
543
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
544
+ return this._httpClient.post({
545
+ url: requestURL
546
+ });
547
+ },
548
+ callbackFunc
549
+ });
550
+ };
551
+
552
+ /**
553
+ * 取消设置空间镜像源
554
+ * @param {string} bucket 空间名称
555
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
556
+ * @returns {Promise<any>}
557
+ */
558
+ BucketManager.prototype.unimage = function (bucket, callbackFunc) {
559
+ const reqOp = `/unimage/${bucket}`;
560
+ return _tryReq.call(this, {
561
+ bucketName: bucket,
562
+ serviceName: SERVICE_NAME.UC,
563
+ func: context => {
564
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
565
+ return this._httpClient.post({
566
+ url: requestURL
567
+ });
568
+ },
569
+ callbackFunc
570
+ });
571
+ };
572
+
573
+ /**
574
+ * 获取指定前缀的文件列表
575
+ * @link https://developer.qiniu.com/kodo/api/1284/list
576
+ *
577
+ * @param {string} bucket 空间名称
578
+ * @param {Object} [options] 列举操作的可选参数
579
+ * @param {string} [options.prefix] 列举的文件前缀
580
+ * @param {string} [options.marker] 上一次列举返回的位置标记,作为本次列举的起点信息
581
+ * @param {number} [options.limit] 每次返回的最大列举文件数量
582
+ * @param {string} [options.delimiter] 指定目录分隔符
583
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
584
+ * @returns {Promise<any>}
585
+ */
586
+ BucketManager.prototype.listPrefix = function (bucket, options, callbackFunc) {
587
+ options = options || {};
588
+ // 必须参数
589
+ const reqParams = {
590
+ bucket: bucket
591
+ };
592
+
593
+ if (options.prefix) {
594
+ reqParams.prefix = options.prefix;
595
+ } else {
596
+ reqParams.prefix = '';
597
+ }
598
+
599
+ if (options.limit >= 1 && options.limit <= 1000) {
600
+ reqParams.limit = options.limit;
601
+ } else {
602
+ reqParams.limit = 1000;
603
+ }
604
+
605
+ if (options.marker) {
606
+ reqParams.marker = options.marker;
607
+ } else {
608
+ reqParams.marker = '';
609
+ }
610
+
611
+ if (options.delimiter) {
612
+ reqParams.delimiter = options.delimiter;
613
+ } else {
614
+ reqParams.delimiter = '';
615
+ }
616
+
617
+ const reqSpec = querystring.stringify(reqParams);
618
+ const reqOp = `/list?${reqSpec}`;
619
+
620
+ return _tryReq.call(this, {
621
+ bucketName: bucket,
622
+ serviceName: SERVICE_NAME.RSF,
623
+ func: context => {
624
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
625
+ return this._httpClient.post({
626
+ url: requestURL
627
+ });
628
+ },
629
+ callbackFunc
630
+ });
631
+ };
632
+
633
+ /**
634
+ * 获取指定前缀的文件列表 V2
635
+ *
636
+ * @deprecated API 可能返回仅包含 marker,不包含 item 或 dir 的项,请使用 {@link listPrefix}
637
+ *
638
+ * @param bucket 空间名称
639
+ * @param {Object} [options] 列举操作的可选参数
640
+ * @param {string} [options.prefix] 列举的文件前缀
641
+ * @param {string} [options.marker] 上一次列举返回的位置标记,作为本次列举的起点信息
642
+ * @param {number} [options.limit] 每次返回的最大列举文件数量
643
+ * @param {string} [options.delimiter] 指定目录分隔符
644
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
645
+ * @returns {Promise<any>}
646
+ */
647
+ BucketManager.prototype.listPrefixV2 = function (bucket, options, callbackFunc) {
648
+ options = options || {};
649
+ // 必须参数
650
+ const reqParams = {
651
+ bucket: bucket
652
+ };
653
+
654
+ if (options.prefix) {
655
+ reqParams.prefix = options.prefix;
656
+ } else {
657
+ reqParams.prefix = '';
658
+ }
659
+
660
+ if (options.limit) {
661
+ reqParams.limit = Math.min(1000, Math.max(0, options.limit));
662
+ } else {
663
+ reqParams.limit = 0;
664
+ }
665
+
666
+ if (options.marker) {
667
+ reqParams.marker = options.marker;
668
+ } else {
669
+ reqParams.marker = '';
670
+ }
671
+
672
+ if (options.delimiter) {
673
+ reqParams.delimiter = options.delimiter;
674
+ } else {
675
+ reqParams.delimiter = '';
676
+ }
677
+
678
+ const reqSpec = querystring.stringify(reqParams);
679
+ const reqOp = `/v2/list?${reqSpec}`;
680
+
681
+ return _tryReq.call(this, {
682
+ bucketName: bucket,
683
+ serviceName: SERVICE_NAME.RSF,
684
+ func: context => {
685
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
686
+ return this._httpClient.post(
687
+ {
688
+ url: requestURL
689
+ },
690
+ {
691
+ dataType: 'text'
692
+ }
693
+ );
694
+ },
695
+ callbackFunc
696
+ });
697
+ };
698
+
699
+ /**
700
+ * 批量文件管理请求,支持stat,chgm,chtype,delete,copy,move
701
+ * @param {string[]} operations 操作
702
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
703
+ * @returns {Promise<any>}
704
+ */
705
+ BucketManager.prototype.batch = function (operations, callbackFunc) {
706
+ if (!operations.length) {
707
+ const error = new Error('Empty operations');
708
+ if (typeof callbackFunc === 'function') {
709
+ callbackFunc(error, null, null);
710
+ }
711
+ return Promise.reject(error);
712
+ }
713
+
714
+ let bucket;
715
+ for (const op of operations) {
716
+ const [, , entry] = op.split('/');
717
+ if (!entry) {
718
+ continue;
719
+ }
720
+ [bucket] = util.decodedEntry(entry);
721
+ if (bucket) {
722
+ break;
723
+ }
724
+ }
725
+ if (!bucket) {
726
+ const error = new Error('Empty bucket');
727
+ callbackFunc(error, null, null);
728
+ return Promise.reject(error);
729
+ }
730
+
731
+ const reqOp = '/batch';
732
+ const reqParams = {
733
+ op: operations
734
+ };
735
+ const reqData = querystring.stringify(reqParams);
736
+
737
+ return _tryReq.call(this, {
738
+ bucketName: bucket,
739
+ serviceName: SERVICE_NAME.RS,
740
+ func: context => {
741
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
742
+ return this._httpClient.post({
743
+ url: requestURL,
744
+ data: reqData
745
+ });
746
+ },
747
+ callbackFunc
748
+ });
749
+ };
750
+
751
+ /**
752
+ * 批量操作支持的指令构造器
753
+ * @param {string} bucket
754
+ * @param {string} key
755
+ * @returns {string}
756
+ */
757
+ exports.statOp = function (bucket, key) {
758
+ return '/stat/' + util.encodedEntry(bucket, key);
759
+ };
760
+
761
+ /**
762
+ * @param {string} bucket
763
+ * @param {string} key
764
+ * @returns {string}
765
+ */
766
+ exports.deleteOp = function (bucket, key) {
767
+ return `/delete/${util.encodedEntry(bucket, key)}`;
768
+ };
769
+
770
+ /**
771
+ * @param {string} bucket
772
+ * @param {string} key
773
+ * @param {number} days
774
+ * @returns {string}
775
+ */
776
+ exports.deleteAfterDaysOp = function (bucket, key, days) {
777
+ const encodedEntryURI = util.encodedEntry(bucket, key);
778
+ return `/deleteAfterDays/${encodedEntryURI}/${days}`;
779
+ };
780
+
781
+ /**
782
+ * @param {string} bucket 空间名称
783
+ * @param {string} key 文件名称
784
+ * @param {Object} [options] 配置项
785
+ * @param {number} [options.toIaAfterDays] 多少天后将文件转为低频存储,设置为 -1 表示取消已设置的转低频存储的生命周期规则, 0 表示不修改转低频生命周期规则。
786
+ * @param {number} [options.toArchiveAfterDays] 多少天后将文件转为归档存储,设置为 -1 表示取消已设置的转归档存储的生命周期规则, 0 表示不修改转归档生命周期规则。
787
+ * @param {number} [options.toArchiveIRAfterDays] 多少天后将文件转为归档直读存储,设置为 -1 表示取消已设置的转归档直读存储的生命周期规则, 0 表示不修改转归档直读生命周期规则。
788
+ * @param {number} [options.toDeepArchiveAfterDays] 多少天后将文件转为深度归档存储,设置为 -1 表示取消已设置的转深度归档存储的生命周期规则, 0 表示不修改转深度归档生命周期规则。
789
+ * @param {number} [options.deleteAfterDays] 多少天后将文件删除,设置为 -1 表示取消已设置的删除存储的生命周期规则, 0 表示不修改删除存储的生命周期规则。
790
+ * @param {Object} [options.cond] 匹配条件,只有条件匹配才会设置成功
791
+ * @param {string} [options.cond.hash]
792
+ * @param {string} [options.cond.mime]
793
+ * @param {number} [options.cond.fsize]
794
+ * @param {number} [options.cond.putTime]
795
+ * @returns {string}
796
+ */
797
+ exports.setObjectLifecycleOp = function (bucket, key, options) {
798
+ const encodedEntry = util.encodedEntry(bucket, key);
799
+ let result = '/lifecycle/' + encodedEntry +
800
+ '/toIAAfterDays/' + (options.toIaAfterDays || 0) +
801
+ '/toArchiveIRAfterDays/' + (options.toArchiveIRAfterDays || 0) +
802
+ '/toArchiveAfterDays/' + (options.toArchiveAfterDays || 0) +
803
+ '/toDeepArchiveAfterDays/' + (options.toDeepArchiveAfterDays || 0) +
804
+ '/deleteAfterDays/' + (options.deleteAfterDays || 0);
805
+ if (options.cond) {
806
+ const condStr = Object.keys(options.cond)
807
+ .reduce(function (acc, key) {
808
+ acc.push(key + '=' + options.cond[key]);
809
+ return acc;
810
+ }, [])
811
+ .join('&');
812
+ result += '/cond/' + util.urlsafeBase64Encode(condStr);
813
+ }
814
+ return result;
815
+ };
816
+
817
+ /**
818
+ * @param {string} bucket
819
+ * @param {string} key
820
+ * @param {string} newMime
821
+ * @returns {string}
822
+ */
823
+ exports.changeMimeOp = function (bucket, key, newMime) {
824
+ const encodedEntryURI = util.encodedEntry(bucket, key);
825
+ const encodedMime = util.urlsafeBase64Encode(newMime);
826
+ return `/chgm/${encodedEntryURI}/mime/${encodedMime}`;
827
+ };
828
+
829
+ /**
830
+ * @param {string} bucket
831
+ * @param {string} key
832
+ * @param {Object<string, string>} headers
833
+ * @returns {string}
834
+ */
835
+ exports.changeHeadersOp = function (bucket, key, headers) {
836
+ const encodedEntryURI = util.encodedEntry(bucket, key);
837
+ const prefix = 'x-qn-meta-!';
838
+ let path = `/chgm/${encodedEntryURI}`;
839
+ for (const headerKey in headers) {
840
+ const encodedValue = util.urlsafeBase64Encode(headers[headerKey]);
841
+ const prefixedHeaderKey = prefix + headerKey;
842
+ path += `/${prefixedHeaderKey}/${encodedValue}`;
843
+ }
844
+
845
+ return path;
846
+ };
847
+
848
+ /**
849
+ * @param {string} bucket
850
+ * @param {string} key
851
+ * @param {number} newType
852
+ * @returns {string}
853
+ */
854
+ exports.changeTypeOp = function (bucket, key, newType) {
855
+ const encodedEntryURI = util.encodedEntry(bucket, key);
856
+ return `/chtype/${encodedEntryURI}/type/${newType}`;
857
+ };
858
+
859
+ /**
860
+ * @param {string} bucket
861
+ * @param {string} key
862
+ * @param {number} newStatus
863
+ * @returns {string}
864
+ */
865
+ exports.changeStatusOp = function (bucket, key, newStatus) {
866
+ const encodedEntryURI = util.encodedEntry(bucket, key);
867
+ return `/chstatus/${encodedEntryURI}/status/${newStatus}`;
868
+ };
869
+
870
+ /**
871
+ * @param {string} srcBucket
872
+ * @param {string} srcKey
873
+ * @param {string} destBucket
874
+ * @param {string} destKey
875
+ * @param {Object} [options]
876
+ * @param {boolean} [options.force]
877
+ * @returns {string}
878
+ */
879
+ exports.moveOp = function (srcBucket, srcKey, destBucket, destKey, options) {
880
+ options = options || {};
881
+ const encodedEntryURISrc = util.encodedEntry(srcBucket, srcKey);
882
+ const encodedEntryURIDest = util.encodedEntry(destBucket, destKey);
883
+ let op = `/move/${encodedEntryURISrc}/${encodedEntryURIDest}`;
884
+ if (options.force) {
885
+ op += '/force/true';
886
+ }
887
+ return op;
888
+ };
889
+
890
+ /**
891
+ * @param {string} srcBucket
892
+ * @param {string} srcKey
893
+ * @param {string} destBucket
894
+ * @param {string} destKey
895
+ * @param {Object} [options]
896
+ * @param {boolean} [options.force]
897
+ * @returns {string}
898
+ */
899
+ exports.copyOp = function (srcBucket, srcKey, destBucket, destKey, options) {
900
+ options = options || {};
901
+ const encodedEntryURISrc = util.encodedEntry(srcBucket, srcKey);
902
+ const encodedEntryURIDest = util.encodedEntry(destBucket, destKey);
903
+ let op = `/copy/${encodedEntryURISrc}/${encodedEntryURIDest}`;
904
+ if (options.force) {
905
+ op += '/force/true';
906
+ }
907
+ return op;
908
+ };
909
+
910
+ /**
911
+ * 获取下载链接
912
+ * @param domain 空间绑定的域名,比如以http或https开头
913
+ * @param fileName 原始文件名
914
+ * @param deadline 文件有效期时间戳(单位秒)
915
+ * @returns {string} 私有下载链接
916
+ */
917
+ BucketManager.prototype.privateDownloadUrl = function (
918
+ domain,
919
+ fileName,
920
+ deadline
921
+ ) {
922
+ let baseUrl = this.publicDownloadUrl(domain, fileName);
923
+ if (baseUrl.indexOf('?') >= 0) {
924
+ baseUrl += '&e=';
925
+ } else {
926
+ baseUrl += '?e=';
927
+ }
928
+ baseUrl += deadline;
929
+
930
+ const signature = util.hmacSha1(baseUrl, this.mac.secretKey);
931
+ const encodedSign = util.base64ToUrlSafe(signature);
932
+ const downloadToken = `${this.mac.accessKey}:${encodedSign}`;
933
+ return `${baseUrl}&token=${downloadToken}`;
934
+ };
935
+
936
+ /**
937
+ * 获取公开空间的下载链接
938
+ * @param {string} domain 空间绑定的域名,比如以 http 或 https 开头
939
+ * @param {string} fileName 原始文件名
940
+ * @returns {string} 公开下载链接
941
+ */
942
+ BucketManager.prototype.publicDownloadUrl = function (domain, fileName) {
943
+ return domain + '/' + encodeUrl(fileName);
944
+ };
945
+
946
+ /**
947
+ * 修改文件状态
948
+ * @link https://developer.qiniu.com/kodo/4173/modify-the-file-status
949
+ * @param {string} bucket 空间名称
950
+ * @param {string} key 文件名称
951
+ * @param {number} status 文件状态
952
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
953
+ * @returns {Promise<void>}
954
+ */
955
+ BucketManager.prototype.updateObjectStatus = function (
956
+ bucket,
957
+ key,
958
+ status,
959
+ callbackFunc
960
+ ) {
961
+ const changeStatusOp = exports.changeStatusOp(bucket, key, status);
962
+ return _tryReq.call(this, {
963
+ bucketName: bucket,
964
+ serviceName: SERVICE_NAME.RS,
965
+ func: context => {
966
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + changeStatusOp;
967
+ return this._httpClient.post({
968
+ url: requestURL
969
+ });
970
+ },
971
+ callbackFunc
972
+ });
973
+ };
974
+
975
+ /**
976
+ * 列举 bucket
977
+ * @link https://developer.qiniu.com/kodo/3926/get-service
978
+ * @param {Object.<string, string>} [options]
979
+ * @param {string} [options.shared] 可传入 `'rd'` 列举出读权限的空间
980
+ * @param {Object.<string, string>} [options.tagCondition] 过滤空间的标签或标签值条件,指定多个标签或标签值时同时满足条件的空间才会返回
981
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
982
+ * @returns {Promise<any>}
983
+ */
984
+ BucketManager.prototype.listBucket = function (options, callbackFunc) {
985
+ let shared;
986
+ let tagCondition;
987
+ if (typeof options === 'function') {
988
+ callbackFunc = options;
989
+ } else {
990
+ options = options || {};
991
+ shared = options.shared;
992
+ tagCondition = options.tagCondition;
993
+ }
994
+
995
+ const reqParams = {};
996
+ if (shared) {
997
+ reqParams.shared = shared;
998
+ }
999
+ if (tagCondition) {
1000
+ reqParams.tagCondition = util.urlsafeBase64Encode(
1001
+ // use Object.entries when min version of Node.js update to ≥ v7.5.0
1002
+ // the `querystring.stringify` will convert unsafe characters to percent encode,
1003
+ // so stringify with below
1004
+ Object.keys(tagCondition)
1005
+ .map(k => {
1006
+ let cond = 'key=' + k;
1007
+ if (tagCondition[k]) {
1008
+ cond += '&value=' + tagCondition[k];
1009
+ }
1010
+ return cond;
1011
+ })
1012
+ .join(';')
1013
+ );
1014
+ }
1015
+ const reqSpec = Object.keys(reqParams).length > 0
1016
+ ? '?' + querystring.stringify(reqParams)
1017
+ : '';
1018
+ const listBucketOp = '/buckets' + reqSpec;
1019
+
1020
+ return _tryReq.call(this, {
1021
+ serviceName: SERVICE_NAME.UC,
1022
+ func: context => {
1023
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + listBucketOp;
1024
+ return this._httpClient.post({
1025
+ url: requestURL
1026
+ });
1027
+ },
1028
+ callbackFunc
1029
+ });
1030
+ };
1031
+
1032
+ /**
1033
+ * 创建 bucket
1034
+ * @param {string} bucket 空间名
1035
+ * @param {Object} [options] 选项
1036
+ * @param {string} [options.regionId] 区域 ID
1037
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
1038
+ * @returns {Promise<any>}
1039
+ */
1040
+ BucketManager.prototype.createBucket = function (bucket, options, callbackFunc) {
1041
+ options = options || {};
1042
+ let createBucketOp = `/mkbucketv3/${bucket}`;
1043
+ if (options.regionId) {
1044
+ createBucketOp += `/region/${options.regionId}`;
1045
+ }
1046
+ return _tryReq.call(this, {
1047
+ serviceName: SERVICE_NAME.UC,
1048
+ func: context => {
1049
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + createBucketOp;
1050
+ return this._httpClient.post({
1051
+ url: requestURL
1052
+ });
1053
+ },
1054
+ callbackFunc
1055
+ });
1056
+ };
1057
+
1058
+ /**
1059
+ * 删除 bucket
1060
+ * @param {string} bucket 空间名
1061
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
1062
+ * @returns {Promise<any>}
1063
+ */
1064
+ BucketManager.prototype.deleteBucket = function (bucket, callbackFunc) {
1065
+ const deleteBucketOp = `/drop/${bucket}`;
1066
+
1067
+ return _tryReq.call(this, {
1068
+ serviceName: SERVICE_NAME.UC,
1069
+ func: context => {
1070
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + deleteBucketOp;
1071
+ return this._httpClient.post({
1072
+ url: requestURL
1073
+ });
1074
+ },
1075
+ callbackFunc
1076
+ });
1077
+ };
1078
+
1079
+ /**
1080
+ * 获取 bucket 信息
1081
+ * @param {string} bucket 空间名
1082
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
1083
+ * @returns {Promise<any>}
1084
+ */
1085
+ BucketManager.prototype.getBucketInfo = function (bucket, callbackFunc) {
1086
+ const bucketInfoOp = `/v2/bucketInfo?bucket=${bucket}`;
1087
+ return _tryReq.call(this, {
1088
+ serviceName: SERVICE_NAME.UC,
1089
+ func: context => {
1090
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + bucketInfoOp;
1091
+ return this._httpClient.post({
1092
+ url: requestURL
1093
+ });
1094
+ },
1095
+ callbackFunc
1096
+ });
1097
+ };
1098
+
1099
+ /**
1100
+ * 增加 bucket 规则
1101
+ * @param { string } bucket 空间名
1102
+ *
1103
+ * @param {Object} options 配置项
1104
+ * @param {string} options.name 规则名称 bucket 内唯一,长度小于50,不能为空,只能为字母、数字、下划线
1105
+ * @param {string} [options.prefix] 同一个 bucket 里面前缀不能重复
1106
+ * @param {number} [options.to_line_after_days] 指定文件上传多少天后转低频存储。指定为0表示不转低频存储
1107
+ * @param {number} [options.to_archive_ir_after_days] 指定文件上传多少天后转归档直读存储。指定为0表示不转归档直读
1108
+ * @param {number} [options.to_archive_after_days] 指定文件上传多少天后转归档存储。指定为0表示不转归档存储
1109
+ * @param {number} [options.to_deep_archive_after_days] 指定文件上传多少天后转深度归档存储。指定为0表示不转深度归档存储
1110
+ * @param {number} [options.delete_after_days] 指定上传文件多少天后删除,指定为0表示不删除,大于0表示多少天后删除
1111
+ * @param {number} [options.history_delete_after_days] 指定文件成为历史版本多少天后删除,指定为0表示不删除,大于0表示多少天后删除
1112
+ * @param {number} [options.history_to_line_after_days] 指定文件成为历史版本多少天后转低频存储。指定为0表示不转低频存储
1113
+ *
1114
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
1115
+ *
1116
+ * @returns {Promise<any>}
1117
+ */
1118
+ BucketManager.prototype.putBucketLifecycleRule = function (
1119
+ bucket,
1120
+ options,
1121
+ callbackFunc
1122
+ ) {
1123
+ const reqParams = Object.assign(
1124
+ {
1125
+ bucket
1126
+ },
1127
+ {
1128
+ prefix: '',
1129
+ to_line_after_days: 0,
1130
+ to_archive_ir_after_days: 0,
1131
+ to_archive_after_days: 0,
1132
+ to_deep_archive_after_days: 0,
1133
+ delete_after_days: 0,
1134
+ history_delete_after_days: 0,
1135
+ history_to_line_after_days: 0
1136
+ },
1137
+ options
1138
+ );
1139
+ const reqSpec = querystring.stringify(reqParams);
1140
+ const reqOp = '/rules/add';
1141
+
1142
+ return _tryReq.call(this, {
1143
+ serviceName: SERVICE_NAME.UC,
1144
+ func: context => {
1145
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1146
+ return this._httpClient.post({
1147
+ url: requestURL,
1148
+ data: reqSpec
1149
+ });
1150
+ },
1151
+ callbackFunc
1152
+ });
1153
+ };
1154
+
1155
+ /**
1156
+ * 删除 bucket 规则
1157
+ * @param {string} bucket 空间名
1158
+ * @param {string} name 规则名称 bucket 内唯一,长度小于50,不能为空,只能为字母、数字、下划线
1159
+ * @param {function} [callbackFunc] 回调函数
1160
+ *
1161
+ * @returns {Promise<any>}
1162
+ */
1163
+ BucketManager.prototype.deleteBucketLifecycleRule = function (bucket, name, callbackFunc) {
1164
+ const reqParams = {
1165
+ bucket: bucket,
1166
+ name: name
1167
+ };
1168
+ const reqSpec = querystring.stringify(reqParams);
1169
+ const reqOp = '/rules/delete';
1170
+ return _tryReq.call(this, {
1171
+ serviceName: SERVICE_NAME.UC,
1172
+ func: context => {
1173
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1174
+ return this._httpClient.post({
1175
+ url: requestURL,
1176
+ data: reqSpec
1177
+ });
1178
+ },
1179
+ callbackFunc
1180
+ });
1181
+ };
1182
+
1183
+ /**
1184
+ * 更新 bucket 规则
1185
+ * @param bucket 空间名
1186
+ *
1187
+ * @param {Object} options 配置项
1188
+ * @param {string} options.name 规则名称 bucket 内唯一,长度小于50,不能为空,只能为字母、数字、下划线:
1189
+ * @param {string} [options.prefix] 同一个 bucket 里面前缀不能重复
1190
+ * @param {number} [options.to_line_after_days] 指定文件上传多少天后转低频存储。指定为0表示不转低频存储
1191
+ * @param {number} [options.to_archive_ir_after_days] 指定文件上传多少天后转归档直读存储。指定为0表示不转归档直读存储
1192
+ * @param {number} [options.to_archive_after_days] 指定文件上传多少天后转归档存储。指定为0表示不转归档存储
1193
+ * @param {number} [options.to_deep_archive_after_days] 指定文件上传多少天后转深度归档存储。指定为0表示不转深度归档存储
1194
+ * @param {number} [options.delete_after_days] 指定上传文件多少天后删除,指定为0表示不删除,大于0表示多少天后删除
1195
+ * @param {number} [options.history_delete_after_days] 指定文件成为历史版本多少天后删除,指定为0表示不删除,大于0表示多少天后删除
1196
+ * @param {number} [options.history_to_line_after_days] 指定文件成为历史版本多少天后转低频存储。指定为0表示不转低频存储
1197
+ *
1198
+ * @param { function } callbackFunc - 回调函数
1199
+ *
1200
+ * @returns {Promise<any>}
1201
+ */
1202
+ BucketManager.prototype.updateBucketLifecycleRule = function (bucket, options, callbackFunc) {
1203
+ const reqParams = Object.assign(
1204
+ {
1205
+ bucket
1206
+ },
1207
+ options
1208
+ );
1209
+ const reqSpec = querystring.stringify(reqParams);
1210
+ const reqOp = '/rules/update';
1211
+
1212
+ return _tryReq.call(this, {
1213
+ serviceName: SERVICE_NAME.UC,
1214
+ func: context => {
1215
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1216
+ return this._httpClient.post({
1217
+ url: requestURL,
1218
+ data: reqSpec
1219
+ });
1220
+ },
1221
+ callbackFunc
1222
+ });
1223
+ };
1224
+
1225
+ /**
1226
+ * 获取 bucket 规则
1227
+ * @param {string} bucket 空间名
1228
+ * @param {BucketOperationCallback} [callbackFunc] 回调函数
1229
+ *
1230
+ * @returns {Promise<any>}
1231
+ */
1232
+ BucketManager.prototype.getBucketLifecycleRule = function (bucket, callbackFunc) {
1233
+ const reqOp = `/rules/get?bucket=${bucket}`;
1234
+ return _tryReq.call(this, {
1235
+ serviceName: SERVICE_NAME.UC,
1236
+ func: context => {
1237
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1238
+ return this._httpClient.get({
1239
+ url: requestURL
1240
+ });
1241
+ },
1242
+ callbackFunc
1243
+ });
1244
+ };
1245
+
1246
+ /**
1247
+ * 增加事件通知规则
1248
+ * @param {string} bucket
1249
+ * @param {Object} options
1250
+ * @param {string} options.name
1251
+ * @param {string} options.event
1252
+ * @param {string | string[]} options.callbackURL
1253
+ * @param {string} [options.prefix]
1254
+ * @param {string} [options.suffix]
1255
+ * @param {string} [options.access_key]
1256
+ * @param {string} [options.host]
1257
+ * @param {BucketOperationCallback} [callbackFunc]
1258
+ *
1259
+ * @returns {Promise<any>}
1260
+ */
1261
+ BucketManager.prototype.putBucketEvent = function (bucket, options, callbackFunc) {
1262
+ const reqParams = Object.assign(
1263
+ { // 必填参数
1264
+ bucket: bucket
1265
+ },
1266
+ // the flowing fields is optional in server
1267
+ // keep compatibility with old sdk versions
1268
+ {
1269
+ prefix: '',
1270
+ suffix: '',
1271
+ access_key: '',
1272
+ host: ''
1273
+ },
1274
+ options
1275
+ );
1276
+
1277
+ const reqSpec = querystring.stringify(reqParams);
1278
+
1279
+ // in docs the params should be putted into body
1280
+ // keep compatibility with old sdk versions
1281
+ const reqOp = '/events/add';
1282
+
1283
+ return _tryReq.call(this, {
1284
+ serviceName: SERVICE_NAME.UC,
1285
+ func: context => {
1286
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1287
+ return this._httpClient.post({
1288
+ url: requestURL,
1289
+ data: reqSpec
1290
+ });
1291
+ },
1292
+ callbackFunc
1293
+ });
1294
+ };
1295
+
1296
+ /**
1297
+ * 更新事件通知规则
1298
+ * @param {string} bucket
1299
+ * @param {Object} options
1300
+ * @param {string} options.name
1301
+ * @param {string} [options.prefix]
1302
+ * @param {string} [options.suffix]
1303
+ * @param {string} [options.event]
1304
+ * @param {string | string[]} [options.callbackURL]
1305
+ * @param {string} [options.access_key]
1306
+ * @param {string} [options.host]
1307
+ * @param {BucketOperationCallback} [callbackFunc]
1308
+ */
1309
+ BucketManager.prototype.updateBucketEvent = function (bucket, options, callbackFunc) {
1310
+ const reqParams = Object.assign(
1311
+ {
1312
+ bucket: bucket
1313
+ },
1314
+ options
1315
+ );
1316
+
1317
+ const reqSpec = querystring.stringify(reqParams);
1318
+ const reqOp = '/events/update';
1319
+
1320
+ return _tryReq.call(this, {
1321
+ serviceName: SERVICE_NAME.UC,
1322
+ func: context => {
1323
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1324
+ return this._httpClient.post({
1325
+ url: requestURL,
1326
+ data: reqSpec
1327
+ });
1328
+ },
1329
+ callbackFunc
1330
+ });
1331
+ };
1332
+
1333
+ /**
1334
+ * 获取事件通知规则
1335
+ * @param {string} bucket
1336
+ * @param {BucketOperationCallback} [callbackFunc]
1337
+ */
1338
+ BucketManager.prototype.getBucketEvent = function (bucket, callbackFunc) {
1339
+ const reqOp = `/events/get?bucket=${bucket}`;
1340
+
1341
+ return _tryReq.call(this, {
1342
+ serviceName: SERVICE_NAME.UC,
1343
+ func: context => {
1344
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1345
+ return this._httpClient.get({
1346
+ url: requestURL
1347
+ });
1348
+ },
1349
+ callbackFunc
1350
+ });
1351
+ };
1352
+
1353
+ /**
1354
+ * 删除事件通知规则
1355
+ * @param {string} bucket
1356
+ * @param {string} name
1357
+ * @param {BucketOperationCallback} [callbackFunc]
1358
+ * @returns {Promise<any>}
1359
+ */
1360
+ BucketManager.prototype.deleteBucketEvent = function (bucket, name, callbackFunc) {
1361
+ const reqParams = {
1362
+ bucket: bucket,
1363
+ name: name
1364
+ };
1365
+ const reqSpec = querystring.stringify(reqParams);
1366
+ const reqOp = '/events/delete';
1367
+
1368
+ return _tryReq.call(this, {
1369
+ serviceName: SERVICE_NAME.UC,
1370
+ func: context => {
1371
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1372
+ return this._httpClient.post({
1373
+ url: requestURL,
1374
+ data: reqSpec
1375
+ });
1376
+ },
1377
+ callbackFunc
1378
+ });
1379
+ };
1380
+
1381
+ /**
1382
+ * 设置防盗链
1383
+ * @param {string} bucket 空间名
1384
+ * @param {Object} options
1385
+ * @param {number} options.mode 防盗链模式。0: 表示关闭; 1: 表示设置Referer白名单; 2: 表示设置Referer黑名单
1386
+ * @param {number} options.norefer 是否支持空 Referer 访问。0: 表示不允许空 Refer 访问; 1: 表示允许空 Refer 访问
1387
+ * @param {string} options.pattern Referer 规则,多个规则之间用 `;` 隔开。当前支持规则:
1388
+ * - 空主机头域名, 比如 foo.com
1389
+ * - 泛域名, 比如 *.foo.com
1390
+ * - 完全通配符, 即一个 *
1391
+ * @param {string} [options.source_enabled] 是否为源站开启。默认为 0 只给 CDN 配置, 设置为 1 表示开启源站防盗链
1392
+ * @param {BucketOperationCallback} [callbackFunc]
1393
+ * @returns {Promise<any>}
1394
+ */
1395
+ BucketManager.prototype.putReferAntiLeech = function (bucket, options, callbackFunc) {
1396
+ const reqParams = Object.assign(
1397
+ {
1398
+ bucket
1399
+ },
1400
+ {
1401
+ mode: 0,
1402
+ norefer: 0,
1403
+ pattern: '*',
1404
+ source_enabled: 0
1405
+ },
1406
+ options
1407
+ );
1408
+
1409
+ const reqSpec = querystring.stringify(reqParams);
1410
+ const reqOp = `/referAntiLeech?${reqSpec}`;
1411
+
1412
+ return _tryReq.call(this, {
1413
+ serviceName: SERVICE_NAME.UC,
1414
+ func: context => {
1415
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1416
+ return this._httpClient.post({
1417
+ url: requestURL
1418
+ });
1419
+ },
1420
+ callbackFunc
1421
+ });
1422
+ };
1423
+
1424
+ /**
1425
+ * @typedef CorsRule
1426
+ * @property {string[]} allowed_origin
1427
+ * @property {string[]} allowed_method
1428
+ * @property {string[]} [allowed_header]
1429
+ * @property {string[]} [exposed_header]
1430
+ * @property {number} [max_age]
1431
+ */
1432
+
1433
+ /**
1434
+ * 设置空间的 cors(跨域)规则
1435
+ * @param {string} bucket
1436
+ * @param {CorsRule[]} body
1437
+ * @param [callbackFunc]
1438
+ * @returns {Promise<any>}
1439
+ */
1440
+ BucketManager.prototype.putCorsRules = function (bucket, body, callbackFunc) {
1441
+ const reqBody = JSON.stringify(body);
1442
+ const reqOp = `/corsRules/set/${bucket}`;
1443
+
1444
+ return _tryReq.call(this, {
1445
+ serviceName: SERVICE_NAME.UC,
1446
+ func: context => {
1447
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1448
+ return this._httpClient.post({
1449
+ url: requestURL,
1450
+ data: reqBody
1451
+ });
1452
+ },
1453
+ callbackFunc
1454
+ });
1455
+ };
1456
+
1457
+ /**
1458
+ * 获取空间跨域规则
1459
+ * @param {string} bucket
1460
+ * @param {BucketOperationCallback} [callbackFunc]
1461
+ */
1462
+ BucketManager.prototype.getCorsRules = function (bucket, callbackFunc) {
1463
+ const reqOp = '/corsRules/get/' + bucket;
1464
+
1465
+ return _tryReq.call(this, {
1466
+ serviceName: SERVICE_NAME.UC,
1467
+ func: context => {
1468
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1469
+ return this._httpClient.post({
1470
+ url: requestURL
1471
+ });
1472
+ },
1473
+ callbackFunc
1474
+ });
1475
+ };
1476
+
1477
+ /**
1478
+ * 设置空间原图保护
1479
+ * @param {string} bucket 空间名称
1480
+ * @param {number} mode 为 1 表示开启原图保护,0 表示关闭
1481
+ * @param {BucketOperationCallback} [callbackFunc]
1482
+ */
1483
+ BucketManager.prototype.putBucketAccessStyleMode = function (bucket, mode, callbackFunc) {
1484
+ const reqOp = `/accessMode/${bucket}/mode/${mode}`;
1485
+
1486
+ return _tryReq.call(this, {
1487
+ serviceName: SERVICE_NAME.UC,
1488
+ func: context => {
1489
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1490
+ return this._httpClient.post({
1491
+ url: requestURL
1492
+ });
1493
+ },
1494
+ callbackFunc
1495
+ });
1496
+ };
1497
+
1498
+ /**
1499
+ * 设置缓存策略的 max-age 属性
1500
+ * @param {string} bucket
1501
+ * @param {Object} options
1502
+ * @param {number} options.maxAge 为 0 或者负数表示为默认值(31536000)
1503
+ * @param {BucketOperationCallback} [callbackFunc]
1504
+ */
1505
+ BucketManager.prototype.putBucketMaxAge = function (bucket, options, callbackFunc) {
1506
+ let maxAge = options.maxAge;
1507
+ if (maxAge <= 0) {
1508
+ maxAge = 31536000;
1509
+ }
1510
+ const reqParams = {
1511
+ bucket: bucket,
1512
+ maxAge: maxAge
1513
+ };
1514
+ const reqSpec = querystring.stringify(reqParams);
1515
+ const reqOp = '/maxAge?' + reqSpec;
1516
+
1517
+ return _tryReq.call(this, {
1518
+ serviceName: SERVICE_NAME.UC,
1519
+ func: context => {
1520
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1521
+ return this._httpClient.post({
1522
+ url: requestURL
1523
+ });
1524
+ },
1525
+ callbackFunc
1526
+ });
1527
+ };
1528
+
1529
+ /**
1530
+ * 设置空间私有属性
1531
+ * @param {string} bucket
1532
+ * @param {Object} options
1533
+ * @param {number} [options.private] 为 0 表示公开,为 1 表示私有,默认为 0
1534
+ * @param {BucketOperationCallback} [callbackFunc]
1535
+ */
1536
+ BucketManager.prototype.putBucketAccessMode = function (bucket, options, callbackFunc) {
1537
+ const reqParams = Object.assign(
1538
+ {
1539
+ bucket: bucket
1540
+ },
1541
+ {
1542
+ private: 0
1543
+ },
1544
+ options
1545
+ );
1546
+
1547
+ const reqSpec = querystring.stringify(reqParams);
1548
+ const reqOp = `/private?${reqSpec}`;
1549
+
1550
+ return _tryReq.call(this, {
1551
+ serviceName: SERVICE_NAME.UC,
1552
+ func: context => {
1553
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1554
+ return this._httpClient.post({
1555
+ url: requestURL
1556
+ });
1557
+ },
1558
+ callbackFunc
1559
+ });
1560
+ };
1561
+
1562
+ /**
1563
+ * 设置配额
1564
+ * @param {string} bucket 空间名称,不支持授权空间
1565
+ * @param {Object} options
1566
+ * @param {number} [options.size] 空间存储量配额,参数传入 0 或不传表示不更改当前配置,传入 -1 表示取消限额,新创建的空间默认没有限额。
1567
+ * @param {number} [options.count] 空间文件数配额,参数含义同<size>
1568
+ * @param {BucketOperationCallback} [callbackFunc]
1569
+ */
1570
+ BucketManager.prototype.putBucketQuota = function (bucket, options, callbackFunc) {
1571
+ options = options || {};
1572
+ const reqParams = {
1573
+ bucket: bucket
1574
+ };
1575
+
1576
+ if (options.size) {
1577
+ reqParams.size = options.size;
1578
+ } else {
1579
+ reqParams.size = 0;
1580
+ }
1581
+
1582
+ if (options.count) {
1583
+ reqParams.count = options.count;
1584
+ } else {
1585
+ reqParams.count = 0;
1586
+ }
1587
+
1588
+ const reqSpec = `${reqParams.bucket}/size/${reqParams.size}/count/${reqParams.count}`;
1589
+ const reqOp = `/setbucketquota/${reqSpec}`;
1590
+
1591
+ return _tryReq.call(this, {
1592
+ serviceName: SERVICE_NAME.UC,
1593
+ func: context => {
1594
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1595
+ return this._httpClient.post({
1596
+ url: requestURL
1597
+ });
1598
+ },
1599
+ callbackFunc
1600
+ });
1601
+ };
1602
+
1603
+ /**
1604
+ * 获取配额
1605
+ * @param {string} bucket 空间名称,不支持授权空间
1606
+ * @param {BucketOperationCallback} [callbackFunc]
1607
+ */
1608
+ BucketManager.prototype.getBucketQuota = function (bucket, callbackFunc) {
1609
+ const reqOp = '/getbucketquota/' + bucket;
1610
+
1611
+ return _tryReq.call(this, {
1612
+ serviceName: SERVICE_NAME.UC,
1613
+ func: context => {
1614
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1615
+ return this._httpClient.post({
1616
+ url: requestURL
1617
+ });
1618
+ },
1619
+ callbackFunc
1620
+ });
1621
+ };
1622
+
1623
+ /**
1624
+ * 获取空间的所有域名
1625
+ * @param {string} bucket
1626
+ * @param {BucketOperationCallback} [callbackFunc]
1627
+ * @returns {Promise<any>}
1628
+ */
1629
+ BucketManager.prototype.listBucketDomains = function (bucket, callbackFunc) {
1630
+ const reqOp = `/v3/domains?tbl=${bucket}`;
1631
+
1632
+ return _tryReq.call(this, {
1633
+ serviceName: SERVICE_NAME.UC,
1634
+ func: context => {
1635
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + reqOp;
1636
+ return this._httpClient.post({
1637
+ url: requestURL
1638
+ });
1639
+ },
1640
+ callbackFunc
1641
+ });
1642
+ };
1643
+
1644
+ /**
1645
+ * 解冻归档存储文件
1646
+ * @param {string} entry
1647
+ * @param {number} freezeAfterDays
1648
+ * @param [callbackFunc]
1649
+ * @returns {Promise<any>}
1650
+ */
1651
+ BucketManager.prototype.restoreAr = function (entry, freezeAfterDays, callbackFunc) {
1652
+ const [bucket] = entry.split(':');
1653
+ const restoreArOp = '/restoreAr/' + util.urlsafeBase64Encode(entry) + '/freezeAfterDays/' + freezeAfterDays;
1654
+
1655
+ return _tryReq.call(this, {
1656
+ bucketName: bucket,
1657
+ serviceName: SERVICE_NAME.RS,
1658
+ func: context => {
1659
+ const requestURL = _getEndpointVal.call(this, context.endpoint) + restoreArOp;
1660
+ return this._httpClient.post({
1661
+ url: requestURL
1662
+ });
1663
+ },
1664
+ callbackFunc
1665
+ });
1666
+ };
1667
+
1668
+ // just for compatibility with old sdk versions
1669
+ function _putPolicyBuildInKeys () {
1670
+ return ['scope', 'isPrefixalScope', 'insertOnly', 'saveKey', 'forceSaveKey',
1671
+ 'endUser', 'returnUrl', 'returnBody', 'callbackUrl', 'callbackHost',
1672
+ 'callbackBody', 'callbackBodyType', 'callbackFetchKey', 'persistentOps',
1673
+ 'persistentNotifyUrl', 'persistentPipeline', 'fsizeLimit', 'fsizeMin',
1674
+ 'detectMime', 'mimeLimit', 'deleteAfterDays', 'fileType'
1675
+ ];
1676
+ }
1677
+
1678
+ /**
1679
+ * @typedef PutPolicyOptions
1680
+ * @extends Object.<string, string | number>
1681
+ * @property {string} scope
1682
+ * @property {number} [isPrefixalScope]
1683
+ * @property {number} [expires]
1684
+ * @property {number} [insertOnly]
1685
+ * @property {string} [saveKey]
1686
+ * @property {string} [forceSaveKey]
1687
+ * @property {string} [endUser]
1688
+ * @property {string} [returnUrl]
1689
+ * @property {string} [returnBody]
1690
+ * @property {string} [callbackUrl]
1691
+ * @property {string} [callbackHost]
1692
+ * @property {string} [callbackBody]
1693
+ * @property {string} [callbackBodyType]
1694
+ * @property {number} [callbackFetchKey]
1695
+ * @property {string} [persistentOps] conflict with `persistentWorkflowTemplateID`
1696
+ * @property {string} [persistentNotifyUrl]
1697
+ * @property {string} [persistentPipeline]
1698
+ * @property {number} [persistentType]
1699
+ * @property {string} [persistentWorkflowTemplateID] conflict with `persistentOps`
1700
+ * @property {number} [fsizeLimit]
1701
+ * @property {number} [fsizeMin]
1702
+ * @property {string} [mimeLimit]
1703
+ * @property {number} [detectMime]
1704
+ * @property {number} [deleteAfterDays]
1705
+ * @property {number} [fileType]
1706
+ * @property {string} [transform] Deprecated
1707
+ * @property {string} [transformFallbackMode] Deprecated
1708
+ * @property {string} [transformFallbackKey] Deprecated
1709
+ */
1710
+
1711
+ /**
1712
+ * 上传策略
1713
+ * @link https://developer.qiniu.com/kodo/manual/1206/put-policy
1714
+ * @param {PutPolicyOptions} options
1715
+ * @constructor
1716
+ * @extends Object.<string, string | number>
1717
+ */
1718
+ function PutPolicy (options) {
1719
+ if (typeof options !== 'object') {
1720
+ throw new Error('invalid putpolicy options');
1721
+ }
1722
+
1723
+ Object.keys(options).forEach(k => {
1724
+ if (k === 'expires') {
1725
+ return;
1726
+ }
1727
+ this[k] = options[k];
1728
+ });
1729
+
1730
+ this.expires = options.expires || 3600;
1731
+ _putPolicyBuildInKeys().forEach(k => {
1732
+ if (this[k] === undefined) {
1733
+ this[k] = this[k] || null;
1734
+ }
1735
+ });
1736
+ }
1737
+
1738
+ PutPolicy.prototype.getFlags = function () {
1739
+ const flags = {};
1740
+
1741
+ Object.keys(this).forEach(k => {
1742
+ if (k === 'expires' || this[k] === null) {
1743
+ return;
1744
+ }
1745
+ flags[k] = this[k];
1746
+ });
1747
+
1748
+ flags.deadline = this.expires + Math.floor(Date.now() / 1000);
1749
+
1750
+ return flags;
1751
+ };
1752
+
1753
+ PutPolicy.prototype.uploadToken = function (mac) {
1754
+ mac = mac || new digest.Mac();
1755
+ const flags = this.getFlags();
1756
+ const encodedFlags = util.urlsafeBase64Encode(JSON.stringify(flags));
1757
+ const encoded = util.hmacSha1(encodedFlags, mac.secretKey);
1758
+ const encodedSign = util.base64ToUrlSafe(encoded);
1759
+ return [
1760
+ mac.accessKey,
1761
+ encodedSign,
1762
+ encodedFlags
1763
+ ].join(':');
1764
+ };