@ptkl/sdk 1.15.0 → 1.17.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.
- package/dist/index.0.10.js +171 -14
- package/dist/index.0.9.js +173 -14
- package/dist/package.json +1 -1
- package/dist/v0.10/api/integrations/dms.d.ts +56 -1
- package/dist/v0.10/api/integrations/payments.d.ts +7 -7
- package/dist/v0.10/index.cjs.js +171 -14
- package/dist/v0.10/index.esm.js +171 -14
- package/dist/v0.10/types/integrations.d.ts +44 -0
- package/dist/v0.9/api/integrations/dms.d.ts +58 -1
- package/dist/v0.9/api/integrations/payments.d.ts +7 -7
- package/dist/v0.9/index.cjs.js +173 -14
- package/dist/v0.9/index.esm.js +173 -14
- package/dist/v0.9/types/integrations.d.ts +44 -0
- package/package.json +1 -1
package/dist/v0.10/index.cjs.js
CHANGED
|
@@ -21082,6 +21082,7 @@ class IntegrationsBaseClient extends BaseClient {
|
|
|
21082
21082
|
// @ts-ignore
|
|
21083
21083
|
env = env !== null && env !== void 0 ? env : __global_env__ === null || __global_env__ === void 0 ? void 0 : __global_env__.PROJECT_ENV;
|
|
21084
21084
|
token = token !== null && token !== void 0 ? token : __global_env__ === null || __global_env__ === void 0 ? void 0 : __global_env__.PROJECT_API_TOKEN;
|
|
21085
|
+
project_uuid = __global_env__ === null || __global_env__ === void 0 ? void 0 : __global_env__.PROJECT_UUID;
|
|
21085
21086
|
if (isBrowser) {
|
|
21086
21087
|
if (sessionStorage.getItem('protokol_context') === 'forge') {
|
|
21087
21088
|
headers['X-Project-Env'] = (_b = sessionStorage.getItem('forge_app_env')) !== null && _b !== void 0 ? _b : 'dev';
|
|
@@ -21137,6 +21138,70 @@ class IntegrationsBaseClient extends BaseClient {
|
|
|
21137
21138
|
}
|
|
21138
21139
|
}
|
|
21139
21140
|
|
|
21141
|
+
/**
|
|
21142
|
+
* Build an RFC 7233 Range header value from the SDK's range options.
|
|
21143
|
+
*
|
|
21144
|
+
* Validation happens here rather than at the server so a typo (a float offset, a
|
|
21145
|
+
* negative length) fails immediately and locally instead of arriving as an opaque
|
|
21146
|
+
* 400 after a round trip.
|
|
21147
|
+
*/
|
|
21148
|
+
function buildRangeHeader(range) {
|
|
21149
|
+
const { offset, length, suffix } = range;
|
|
21150
|
+
if (suffix !== undefined) {
|
|
21151
|
+
if (offset !== undefined || length !== undefined) {
|
|
21152
|
+
throw new Error('readRange: `suffix` cannot be combined with `offset` or `length`');
|
|
21153
|
+
}
|
|
21154
|
+
if (!Number.isInteger(suffix) || suffix <= 0) {
|
|
21155
|
+
throw new Error('readRange: `suffix` must be a positive integer');
|
|
21156
|
+
}
|
|
21157
|
+
return `bytes=-${suffix}`;
|
|
21158
|
+
}
|
|
21159
|
+
const start = offset !== null && offset !== void 0 ? offset : 0;
|
|
21160
|
+
if (!Number.isInteger(start) || start < 0) {
|
|
21161
|
+
throw new Error('readRange: `offset` must be a non-negative integer');
|
|
21162
|
+
}
|
|
21163
|
+
if (length === undefined) {
|
|
21164
|
+
return `bytes=${start}-`;
|
|
21165
|
+
}
|
|
21166
|
+
if (!Number.isInteger(length) || length <= 0) {
|
|
21167
|
+
throw new Error('readRange: `length` must be a positive integer');
|
|
21168
|
+
}
|
|
21169
|
+
// Range end offsets are inclusive, so a length of N ends at start + N - 1.
|
|
21170
|
+
return `bytes=${start}-${start + length - 1}`;
|
|
21171
|
+
}
|
|
21172
|
+
/**
|
|
21173
|
+
* Turn a 206 response into a ByteRangeResult.
|
|
21174
|
+
*
|
|
21175
|
+
* The Content-Range check is the important part. Requests reach media-api through
|
|
21176
|
+
* two proxies, and if any hop ever dropped the Range header the response would be
|
|
21177
|
+
* a perfectly valid 200 carrying the *entire* file — a caller asking for 64 KiB
|
|
21178
|
+
* of a 2 GB object would quietly receive all 2 GB. Failing loudly here turns that
|
|
21179
|
+
* from a silent memory blow-up into an actionable error.
|
|
21180
|
+
*/
|
|
21181
|
+
function toByteRangeResult(resp) {
|
|
21182
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
21183
|
+
const contentRange = (_b = (_a = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _a === void 0 ? void 0 : _a['content-range']) !== null && _b !== void 0 ? _b : (_c = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _c === void 0 ? void 0 : _c['Content-Range'];
|
|
21184
|
+
const parsed = /^bytes\s+(\d+)-(\d+)\/(\d+)$/.exec(String(contentRange !== null && contentRange !== void 0 ? contentRange : '').trim());
|
|
21185
|
+
if (!parsed) {
|
|
21186
|
+
throw new Error('readRange: response did not include a Content-Range header, so the returned body ' +
|
|
21187
|
+
'may be the entire object rather than the requested range. ' +
|
|
21188
|
+
'Check that the media host supports ranged reads and that no proxy is stripping the Range header.');
|
|
21189
|
+
}
|
|
21190
|
+
const start = Number(parsed[1]);
|
|
21191
|
+
const end = Number(parsed[2]);
|
|
21192
|
+
const totalSize = Number(parsed[3]);
|
|
21193
|
+
const etag = (_e = (_d = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _d === void 0 ? void 0 : _d.etag) !== null && _e !== void 0 ? _e : (_f = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _f === void 0 ? void 0 : _f.ETag;
|
|
21194
|
+
return {
|
|
21195
|
+
data: resp.data,
|
|
21196
|
+
start,
|
|
21197
|
+
end,
|
|
21198
|
+
length: end - start + 1,
|
|
21199
|
+
totalSize,
|
|
21200
|
+
eof: end >= totalSize - 1,
|
|
21201
|
+
etag: typeof etag === 'string' ? etag.replace(/^"|"$/g, '') : undefined,
|
|
21202
|
+
contentType: (_g = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _g === void 0 ? void 0 : _g['content-type'],
|
|
21203
|
+
};
|
|
21204
|
+
}
|
|
21140
21205
|
/**
|
|
21141
21206
|
* Document Management System (DMS) API client
|
|
21142
21207
|
*
|
|
@@ -21311,6 +21376,93 @@ class DMS extends IntegrationsBaseClient {
|
|
|
21311
21376
|
responseType: (!encoding) ? 'blob' : null
|
|
21312
21377
|
});
|
|
21313
21378
|
}
|
|
21379
|
+
/**
|
|
21380
|
+
* Read a slice of a stored file without transferring the whole object.
|
|
21381
|
+
*
|
|
21382
|
+
* Uses an HTTP Range request, so only the requested bytes cross the wire.
|
|
21383
|
+
* Slicing is positional and format-agnostic — it works on any file.
|
|
21384
|
+
*
|
|
21385
|
+
* ```ts
|
|
21386
|
+
* // First 64 KiB
|
|
21387
|
+
* const head = await dms.readRange('reports/big.csv', { length: 65536 })
|
|
21388
|
+
*
|
|
21389
|
+
* // Continue from where that stopped
|
|
21390
|
+
* const next = await dms.readRange('reports/big.csv', { offset: head.end + 1, length: 65536 })
|
|
21391
|
+
*
|
|
21392
|
+
* // Final 1 KiB
|
|
21393
|
+
* const tail = await dms.readRange('reports/big.csv', { suffix: 1024 })
|
|
21394
|
+
* ```
|
|
21395
|
+
*
|
|
21396
|
+
* The server caps how much a single call may return, so `length` is an upper
|
|
21397
|
+
* bound rather than a guarantee: always advance using the returned `end`
|
|
21398
|
+
* rather than assuming the window you asked for. `eof` tells you when to stop.
|
|
21399
|
+
*
|
|
21400
|
+
* Byte ranges are not meaningful for .xlsx, .zip or .gz — their contents are
|
|
21401
|
+
* compressed as a unit, so no byte window corresponds to a range of rows.
|
|
21402
|
+
*
|
|
21403
|
+
* @param key Path of the file within the library
|
|
21404
|
+
* @param range Which bytes to read
|
|
21405
|
+
* @throws If the object is smaller than `offset` (nothing left to read), or if
|
|
21406
|
+
* the response came back without range metadata — see `readRange`'s
|
|
21407
|
+
* Content-Range check, which prevents silently receiving a whole file.
|
|
21408
|
+
*/
|
|
21409
|
+
async readRange(key, range = {}) {
|
|
21410
|
+
const { responseType = 'arraybuffer' } = range;
|
|
21411
|
+
const resp = await this.request('GET', `media/get/${key}`, {
|
|
21412
|
+
headers: { Range: buildRangeHeader(range) },
|
|
21413
|
+
responseType,
|
|
21414
|
+
});
|
|
21415
|
+
return toByteRangeResult(resp);
|
|
21416
|
+
}
|
|
21417
|
+
/**
|
|
21418
|
+
* Read a file as a sequence of byte windows, newest request issued only when
|
|
21419
|
+
* the previous window has been consumed.
|
|
21420
|
+
*
|
|
21421
|
+
* This is the memory-bounded way to process a large file: the whole object is
|
|
21422
|
+
* never held at once, and a caller can stop early simply by breaking out.
|
|
21423
|
+
*
|
|
21424
|
+
* ```ts
|
|
21425
|
+
* for await (const chunk of dms.streamRanges('logs/huge.ndjson', { chunkSize: 1 << 20 })) {
|
|
21426
|
+
* process(chunk.data) // one window at a time
|
|
21427
|
+
* if (foundWhatIWanted) break // no further requests are made
|
|
21428
|
+
* }
|
|
21429
|
+
* ```
|
|
21430
|
+
*
|
|
21431
|
+
* Windows are contiguous and non-overlapping, so concatenating every `data`
|
|
21432
|
+
* reproduces the file byte for byte. A record spanning a window boundary is
|
|
21433
|
+
* the caller's to reassemble — this yields bytes, not records.
|
|
21434
|
+
*
|
|
21435
|
+
* An empty object yields nothing rather than throwing.
|
|
21436
|
+
*
|
|
21437
|
+
* @param key Path of the file within the library
|
|
21438
|
+
* @param options Where to start and how large each window should be
|
|
21439
|
+
*/
|
|
21440
|
+
async *streamRanges(key, options = {}) {
|
|
21441
|
+
var _a, _b;
|
|
21442
|
+
const { chunkSize = 1024 * 1024, responseType = 'arraybuffer' } = options;
|
|
21443
|
+
let offset = (_a = options.offset) !== null && _a !== void 0 ? _a : 0;
|
|
21444
|
+
for (;;) {
|
|
21445
|
+
let chunk;
|
|
21446
|
+
try {
|
|
21447
|
+
chunk = await this.readRange(key, { offset, length: chunkSize, responseType });
|
|
21448
|
+
}
|
|
21449
|
+
catch (err) {
|
|
21450
|
+
// 416 means the offset is at or past the end. For the first request
|
|
21451
|
+
// that is an empty object; afterwards it is a benign race with a
|
|
21452
|
+
// truncating writer. Either way the stream is simply over.
|
|
21453
|
+
if (((_b = err === null || err === void 0 ? void 0 : err.response) === null || _b === void 0 ? void 0 : _b.status) === 416)
|
|
21454
|
+
return;
|
|
21455
|
+
throw err;
|
|
21456
|
+
}
|
|
21457
|
+
yield chunk;
|
|
21458
|
+
if (chunk.eof)
|
|
21459
|
+
return;
|
|
21460
|
+
// Advance from what the server actually returned, never from chunkSize:
|
|
21461
|
+
// the per-request cap can make a window shorter than requested, and
|
|
21462
|
+
// assuming otherwise would skip bytes.
|
|
21463
|
+
offset = chunk.end + 1;
|
|
21464
|
+
}
|
|
21465
|
+
}
|
|
21314
21466
|
async download(key) {
|
|
21315
21467
|
return this.request('POST', `media/download`, {
|
|
21316
21468
|
data: {
|
|
@@ -22287,36 +22439,41 @@ class MinFin extends IntegrationsBaseClient {
|
|
|
22287
22439
|
}
|
|
22288
22440
|
|
|
22289
22441
|
class Payments extends IntegrationsBaseClient {
|
|
22442
|
+
// FIXME: No backend route exists for listing/searching transactions (neither
|
|
22443
|
+
// monri.route.ts nor wspay.route.ts under karadjordje/src/routes/v1/payments/
|
|
22444
|
+
// expose a "list" endpoint). This method's URL is left as-is (still broken)
|
|
22445
|
+
// rather than being "fixed" to another guessed path that would still 404.
|
|
22446
|
+
// Do not call this method until a corresponding backend route is added.
|
|
22290
22447
|
async getTransactions(userId, params) {
|
|
22291
22448
|
return await this.client.get(`/karadjordje/v1/payment/${userId}/list`, {
|
|
22292
22449
|
params,
|
|
22293
22450
|
});
|
|
22294
22451
|
}
|
|
22295
|
-
async getTransaction(provider,
|
|
22296
|
-
return await this.client.get(`/karadjordje/v1/payment/${provider}
|
|
22452
|
+
async getTransaction(provider, transactionId) {
|
|
22453
|
+
return await this.client.get(`/karadjordje/v1/payment/${provider}/getTransaction`, {
|
|
22297
22454
|
params: { transactionId },
|
|
22298
22455
|
});
|
|
22299
22456
|
}
|
|
22300
22457
|
async settings(provider) {
|
|
22301
22458
|
return await this.client.get(`/karadjordje/v1/payment/${provider}/settings`);
|
|
22302
22459
|
}
|
|
22303
|
-
async deactivatePaymentLink(provider,
|
|
22304
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
22460
|
+
async deactivatePaymentLink(provider, transactionId) {
|
|
22461
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/deactivate/${transactionId}`);
|
|
22305
22462
|
}
|
|
22306
|
-
async voidTransaction(provider,
|
|
22307
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
22463
|
+
async voidTransaction(provider, transactionId) {
|
|
22464
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/void/${transactionId}`);
|
|
22308
22465
|
}
|
|
22309
|
-
async refund(provider,
|
|
22310
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
22466
|
+
async refund(provider, transactionId) {
|
|
22467
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/refund/${transactionId}`);
|
|
22311
22468
|
}
|
|
22312
|
-
async getPaymentLink(provider,
|
|
22313
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
22469
|
+
async getPaymentLink(provider, options) {
|
|
22470
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/getPaymentLink`, options);
|
|
22314
22471
|
}
|
|
22315
|
-
async getTokenRequestLink(provider,
|
|
22316
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
22472
|
+
async getTokenRequestLink(provider, options) {
|
|
22473
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/getTokenRequestLink`, options);
|
|
22317
22474
|
}
|
|
22318
|
-
async directPayUsingToken(provider,
|
|
22319
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
22475
|
+
async directPayUsingToken(provider, options) {
|
|
22476
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/directPayUsingToken`, options);
|
|
22320
22477
|
}
|
|
22321
22478
|
}
|
|
22322
22479
|
|
package/dist/v0.10/index.esm.js
CHANGED
|
@@ -2115,6 +2115,7 @@ class IntegrationsBaseClient extends BaseClient {
|
|
|
2115
2115
|
// @ts-ignore
|
|
2116
2116
|
env = env !== null && env !== void 0 ? env : __global_env__ === null || __global_env__ === void 0 ? void 0 : __global_env__.PROJECT_ENV;
|
|
2117
2117
|
token = token !== null && token !== void 0 ? token : __global_env__ === null || __global_env__ === void 0 ? void 0 : __global_env__.PROJECT_API_TOKEN;
|
|
2118
|
+
project_uuid = __global_env__ === null || __global_env__ === void 0 ? void 0 : __global_env__.PROJECT_UUID;
|
|
2118
2119
|
if (isBrowser) {
|
|
2119
2120
|
if (sessionStorage.getItem('protokol_context') === 'forge') {
|
|
2120
2121
|
headers['X-Project-Env'] = (_b = sessionStorage.getItem('forge_app_env')) !== null && _b !== void 0 ? _b : 'dev';
|
|
@@ -2170,6 +2171,70 @@ class IntegrationsBaseClient extends BaseClient {
|
|
|
2170
2171
|
}
|
|
2171
2172
|
}
|
|
2172
2173
|
|
|
2174
|
+
/**
|
|
2175
|
+
* Build an RFC 7233 Range header value from the SDK's range options.
|
|
2176
|
+
*
|
|
2177
|
+
* Validation happens here rather than at the server so a typo (a float offset, a
|
|
2178
|
+
* negative length) fails immediately and locally instead of arriving as an opaque
|
|
2179
|
+
* 400 after a round trip.
|
|
2180
|
+
*/
|
|
2181
|
+
function buildRangeHeader(range) {
|
|
2182
|
+
const { offset, length, suffix } = range;
|
|
2183
|
+
if (suffix !== undefined) {
|
|
2184
|
+
if (offset !== undefined || length !== undefined) {
|
|
2185
|
+
throw new Error('readRange: `suffix` cannot be combined with `offset` or `length`');
|
|
2186
|
+
}
|
|
2187
|
+
if (!Number.isInteger(suffix) || suffix <= 0) {
|
|
2188
|
+
throw new Error('readRange: `suffix` must be a positive integer');
|
|
2189
|
+
}
|
|
2190
|
+
return `bytes=-${suffix}`;
|
|
2191
|
+
}
|
|
2192
|
+
const start = offset !== null && offset !== void 0 ? offset : 0;
|
|
2193
|
+
if (!Number.isInteger(start) || start < 0) {
|
|
2194
|
+
throw new Error('readRange: `offset` must be a non-negative integer');
|
|
2195
|
+
}
|
|
2196
|
+
if (length === undefined) {
|
|
2197
|
+
return `bytes=${start}-`;
|
|
2198
|
+
}
|
|
2199
|
+
if (!Number.isInteger(length) || length <= 0) {
|
|
2200
|
+
throw new Error('readRange: `length` must be a positive integer');
|
|
2201
|
+
}
|
|
2202
|
+
// Range end offsets are inclusive, so a length of N ends at start + N - 1.
|
|
2203
|
+
return `bytes=${start}-${start + length - 1}`;
|
|
2204
|
+
}
|
|
2205
|
+
/**
|
|
2206
|
+
* Turn a 206 response into a ByteRangeResult.
|
|
2207
|
+
*
|
|
2208
|
+
* The Content-Range check is the important part. Requests reach media-api through
|
|
2209
|
+
* two proxies, and if any hop ever dropped the Range header the response would be
|
|
2210
|
+
* a perfectly valid 200 carrying the *entire* file — a caller asking for 64 KiB
|
|
2211
|
+
* of a 2 GB object would quietly receive all 2 GB. Failing loudly here turns that
|
|
2212
|
+
* from a silent memory blow-up into an actionable error.
|
|
2213
|
+
*/
|
|
2214
|
+
function toByteRangeResult(resp) {
|
|
2215
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2216
|
+
const contentRange = (_b = (_a = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _a === void 0 ? void 0 : _a['content-range']) !== null && _b !== void 0 ? _b : (_c = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _c === void 0 ? void 0 : _c['Content-Range'];
|
|
2217
|
+
const parsed = /^bytes\s+(\d+)-(\d+)\/(\d+)$/.exec(String(contentRange !== null && contentRange !== void 0 ? contentRange : '').trim());
|
|
2218
|
+
if (!parsed) {
|
|
2219
|
+
throw new Error('readRange: response did not include a Content-Range header, so the returned body ' +
|
|
2220
|
+
'may be the entire object rather than the requested range. ' +
|
|
2221
|
+
'Check that the media host supports ranged reads and that no proxy is stripping the Range header.');
|
|
2222
|
+
}
|
|
2223
|
+
const start = Number(parsed[1]);
|
|
2224
|
+
const end = Number(parsed[2]);
|
|
2225
|
+
const totalSize = Number(parsed[3]);
|
|
2226
|
+
const etag = (_e = (_d = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _d === void 0 ? void 0 : _d.etag) !== null && _e !== void 0 ? _e : (_f = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _f === void 0 ? void 0 : _f.ETag;
|
|
2227
|
+
return {
|
|
2228
|
+
data: resp.data,
|
|
2229
|
+
start,
|
|
2230
|
+
end,
|
|
2231
|
+
length: end - start + 1,
|
|
2232
|
+
totalSize,
|
|
2233
|
+
eof: end >= totalSize - 1,
|
|
2234
|
+
etag: typeof etag === 'string' ? etag.replace(/^"|"$/g, '') : undefined,
|
|
2235
|
+
contentType: (_g = resp === null || resp === void 0 ? void 0 : resp.headers) === null || _g === void 0 ? void 0 : _g['content-type'],
|
|
2236
|
+
};
|
|
2237
|
+
}
|
|
2173
2238
|
/**
|
|
2174
2239
|
* Document Management System (DMS) API client
|
|
2175
2240
|
*
|
|
@@ -2344,6 +2409,93 @@ class DMS extends IntegrationsBaseClient {
|
|
|
2344
2409
|
responseType: (!encoding) ? 'blob' : null
|
|
2345
2410
|
});
|
|
2346
2411
|
}
|
|
2412
|
+
/**
|
|
2413
|
+
* Read a slice of a stored file without transferring the whole object.
|
|
2414
|
+
*
|
|
2415
|
+
* Uses an HTTP Range request, so only the requested bytes cross the wire.
|
|
2416
|
+
* Slicing is positional and format-agnostic — it works on any file.
|
|
2417
|
+
*
|
|
2418
|
+
* ```ts
|
|
2419
|
+
* // First 64 KiB
|
|
2420
|
+
* const head = await dms.readRange('reports/big.csv', { length: 65536 })
|
|
2421
|
+
*
|
|
2422
|
+
* // Continue from where that stopped
|
|
2423
|
+
* const next = await dms.readRange('reports/big.csv', { offset: head.end + 1, length: 65536 })
|
|
2424
|
+
*
|
|
2425
|
+
* // Final 1 KiB
|
|
2426
|
+
* const tail = await dms.readRange('reports/big.csv', { suffix: 1024 })
|
|
2427
|
+
* ```
|
|
2428
|
+
*
|
|
2429
|
+
* The server caps how much a single call may return, so `length` is an upper
|
|
2430
|
+
* bound rather than a guarantee: always advance using the returned `end`
|
|
2431
|
+
* rather than assuming the window you asked for. `eof` tells you when to stop.
|
|
2432
|
+
*
|
|
2433
|
+
* Byte ranges are not meaningful for .xlsx, .zip or .gz — their contents are
|
|
2434
|
+
* compressed as a unit, so no byte window corresponds to a range of rows.
|
|
2435
|
+
*
|
|
2436
|
+
* @param key Path of the file within the library
|
|
2437
|
+
* @param range Which bytes to read
|
|
2438
|
+
* @throws If the object is smaller than `offset` (nothing left to read), or if
|
|
2439
|
+
* the response came back without range metadata — see `readRange`'s
|
|
2440
|
+
* Content-Range check, which prevents silently receiving a whole file.
|
|
2441
|
+
*/
|
|
2442
|
+
async readRange(key, range = {}) {
|
|
2443
|
+
const { responseType = 'arraybuffer' } = range;
|
|
2444
|
+
const resp = await this.request('GET', `media/get/${key}`, {
|
|
2445
|
+
headers: { Range: buildRangeHeader(range) },
|
|
2446
|
+
responseType,
|
|
2447
|
+
});
|
|
2448
|
+
return toByteRangeResult(resp);
|
|
2449
|
+
}
|
|
2450
|
+
/**
|
|
2451
|
+
* Read a file as a sequence of byte windows, newest request issued only when
|
|
2452
|
+
* the previous window has been consumed.
|
|
2453
|
+
*
|
|
2454
|
+
* This is the memory-bounded way to process a large file: the whole object is
|
|
2455
|
+
* never held at once, and a caller can stop early simply by breaking out.
|
|
2456
|
+
*
|
|
2457
|
+
* ```ts
|
|
2458
|
+
* for await (const chunk of dms.streamRanges('logs/huge.ndjson', { chunkSize: 1 << 20 })) {
|
|
2459
|
+
* process(chunk.data) // one window at a time
|
|
2460
|
+
* if (foundWhatIWanted) break // no further requests are made
|
|
2461
|
+
* }
|
|
2462
|
+
* ```
|
|
2463
|
+
*
|
|
2464
|
+
* Windows are contiguous and non-overlapping, so concatenating every `data`
|
|
2465
|
+
* reproduces the file byte for byte. A record spanning a window boundary is
|
|
2466
|
+
* the caller's to reassemble — this yields bytes, not records.
|
|
2467
|
+
*
|
|
2468
|
+
* An empty object yields nothing rather than throwing.
|
|
2469
|
+
*
|
|
2470
|
+
* @param key Path of the file within the library
|
|
2471
|
+
* @param options Where to start and how large each window should be
|
|
2472
|
+
*/
|
|
2473
|
+
async *streamRanges(key, options = {}) {
|
|
2474
|
+
var _a, _b;
|
|
2475
|
+
const { chunkSize = 1024 * 1024, responseType = 'arraybuffer' } = options;
|
|
2476
|
+
let offset = (_a = options.offset) !== null && _a !== void 0 ? _a : 0;
|
|
2477
|
+
for (;;) {
|
|
2478
|
+
let chunk;
|
|
2479
|
+
try {
|
|
2480
|
+
chunk = await this.readRange(key, { offset, length: chunkSize, responseType });
|
|
2481
|
+
}
|
|
2482
|
+
catch (err) {
|
|
2483
|
+
// 416 means the offset is at or past the end. For the first request
|
|
2484
|
+
// that is an empty object; afterwards it is a benign race with a
|
|
2485
|
+
// truncating writer. Either way the stream is simply over.
|
|
2486
|
+
if (((_b = err === null || err === void 0 ? void 0 : err.response) === null || _b === void 0 ? void 0 : _b.status) === 416)
|
|
2487
|
+
return;
|
|
2488
|
+
throw err;
|
|
2489
|
+
}
|
|
2490
|
+
yield chunk;
|
|
2491
|
+
if (chunk.eof)
|
|
2492
|
+
return;
|
|
2493
|
+
// Advance from what the server actually returned, never from chunkSize:
|
|
2494
|
+
// the per-request cap can make a window shorter than requested, and
|
|
2495
|
+
// assuming otherwise would skip bytes.
|
|
2496
|
+
offset = chunk.end + 1;
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2347
2499
|
async download(key) {
|
|
2348
2500
|
return this.request('POST', `media/download`, {
|
|
2349
2501
|
data: {
|
|
@@ -3320,36 +3472,41 @@ class MinFin extends IntegrationsBaseClient {
|
|
|
3320
3472
|
}
|
|
3321
3473
|
|
|
3322
3474
|
class Payments extends IntegrationsBaseClient {
|
|
3475
|
+
// FIXME: No backend route exists for listing/searching transactions (neither
|
|
3476
|
+
// monri.route.ts nor wspay.route.ts under karadjordje/src/routes/v1/payments/
|
|
3477
|
+
// expose a "list" endpoint). This method's URL is left as-is (still broken)
|
|
3478
|
+
// rather than being "fixed" to another guessed path that would still 404.
|
|
3479
|
+
// Do not call this method until a corresponding backend route is added.
|
|
3323
3480
|
async getTransactions(userId, params) {
|
|
3324
3481
|
return await this.client.get(`/karadjordje/v1/payment/${userId}/list`, {
|
|
3325
3482
|
params,
|
|
3326
3483
|
});
|
|
3327
3484
|
}
|
|
3328
|
-
async getTransaction(provider,
|
|
3329
|
-
return await this.client.get(`/karadjordje/v1/payment/${provider}
|
|
3485
|
+
async getTransaction(provider, transactionId) {
|
|
3486
|
+
return await this.client.get(`/karadjordje/v1/payment/${provider}/getTransaction`, {
|
|
3330
3487
|
params: { transactionId },
|
|
3331
3488
|
});
|
|
3332
3489
|
}
|
|
3333
3490
|
async settings(provider) {
|
|
3334
3491
|
return await this.client.get(`/karadjordje/v1/payment/${provider}/settings`);
|
|
3335
3492
|
}
|
|
3336
|
-
async deactivatePaymentLink(provider,
|
|
3337
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
3493
|
+
async deactivatePaymentLink(provider, transactionId) {
|
|
3494
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/deactivate/${transactionId}`);
|
|
3338
3495
|
}
|
|
3339
|
-
async voidTransaction(provider,
|
|
3340
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
3496
|
+
async voidTransaction(provider, transactionId) {
|
|
3497
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/void/${transactionId}`);
|
|
3341
3498
|
}
|
|
3342
|
-
async refund(provider,
|
|
3343
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
3499
|
+
async refund(provider, transactionId) {
|
|
3500
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/refund/${transactionId}`);
|
|
3344
3501
|
}
|
|
3345
|
-
async getPaymentLink(provider,
|
|
3346
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
3502
|
+
async getPaymentLink(provider, options) {
|
|
3503
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/getPaymentLink`, options);
|
|
3347
3504
|
}
|
|
3348
|
-
async getTokenRequestLink(provider,
|
|
3349
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
3505
|
+
async getTokenRequestLink(provider, options) {
|
|
3506
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/getTokenRequestLink`, options);
|
|
3350
3507
|
}
|
|
3351
|
-
async directPayUsingToken(provider,
|
|
3352
|
-
return await this.client.post(`/karadjordje/v1/payment/${provider}
|
|
3508
|
+
async directPayUsingToken(provider, options) {
|
|
3509
|
+
return await this.client.post(`/karadjordje/v1/payment/${provider}/directPayUsingToken`, options);
|
|
3353
3510
|
}
|
|
3354
3511
|
}
|
|
3355
3512
|
|
|
@@ -584,3 +584,47 @@ export type FileNotification = {
|
|
|
584
584
|
recipient_email?: string;
|
|
585
585
|
};
|
|
586
586
|
export type FileNotificationListResponse = FileNotification[];
|
|
587
|
+
/**
|
|
588
|
+
* Which bytes to read. Supply either `offset`/`length` or `suffix`, not both.
|
|
589
|
+
*/
|
|
590
|
+
export type ByteRangeRequest = {
|
|
591
|
+
/** First byte to read, 0-based. Defaults to 0. */
|
|
592
|
+
offset?: number;
|
|
593
|
+
/** How many bytes to read. Omit to read to the end of the object, subject to the server's per-request cap. */
|
|
594
|
+
length?: number;
|
|
595
|
+
/** Read the final N bytes instead. Mutually exclusive with `offset`/`length`. */
|
|
596
|
+
suffix?: number;
|
|
597
|
+
/** Axios response type for the body. Defaults to `arraybuffer`. */
|
|
598
|
+
responseType?: 'arraybuffer' | 'blob' | 'text';
|
|
599
|
+
};
|
|
600
|
+
/**
|
|
601
|
+
* A single window of bytes plus the position metadata needed to request the next one.
|
|
602
|
+
*/
|
|
603
|
+
export type ByteRangeResult<T = any> = {
|
|
604
|
+
/** The bytes, in the shape requested via `responseType`. */
|
|
605
|
+
data: T;
|
|
606
|
+
/** Offset of the first byte returned. */
|
|
607
|
+
start: number;
|
|
608
|
+
/** Offset of the last byte returned, inclusive. */
|
|
609
|
+
end: number;
|
|
610
|
+
/** Number of bytes returned. May be less than requested — see `ByteRangeRequest.length`. */
|
|
611
|
+
length: number;
|
|
612
|
+
/** Total size of the whole object. */
|
|
613
|
+
totalSize: number;
|
|
614
|
+
/** True when this window ends at the last byte of the object. */
|
|
615
|
+
eof: boolean;
|
|
616
|
+
/** Object validator. Changes if the object is replaced, so a multi-window scan can detect it. */
|
|
617
|
+
etag?: string;
|
|
618
|
+
contentType?: string;
|
|
619
|
+
};
|
|
620
|
+
/**
|
|
621
|
+
* Options for walking an object window by window.
|
|
622
|
+
*/
|
|
623
|
+
export type ByteStreamOptions = {
|
|
624
|
+
/** Byte offset to start from. Defaults to 0. */
|
|
625
|
+
offset?: number;
|
|
626
|
+
/** Bytes per window. Defaults to 1 MiB. The server may return less. */
|
|
627
|
+
chunkSize?: number;
|
|
628
|
+
/** Axios response type for each window. Defaults to `arraybuffer`. */
|
|
629
|
+
responseType?: 'arraybuffer' | 'blob' | 'text';
|
|
630
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import IntegrationsBaseClient from "../integrationsBaseClient";
|
|
2
2
|
import { AxiosResponse } from "axios";
|
|
3
|
-
import { PDFFillOptions, DataConversionParams, DataValidationParams, DataInfoParams, DataInfo, DataValidationResult, ConversionOptions, HTML2PDFOptions } from "../../types/integrations";
|
|
3
|
+
import { PDFFillOptions, DataConversionParams, DataValidationParams, DataInfoParams, DataInfo, DataValidationResult, ConversionOptions, HTML2PDFOptions, ByteRangeRequest, ByteRangeResult, ByteStreamOptions } from "../../types/integrations";
|
|
4
4
|
/**
|
|
5
5
|
* Document Management System (DMS) API client
|
|
6
6
|
*
|
|
@@ -87,6 +87,63 @@ export default class DMS extends IntegrationsBaseClient {
|
|
|
87
87
|
delete(data: any): Promise<AxiosResponse<any, any>>;
|
|
88
88
|
uploadBase64(data: any): Promise<AxiosResponse<any, any>>;
|
|
89
89
|
getMedia(lib: string, key: string, encoding: string): Promise<AxiosResponse<any, any>>;
|
|
90
|
+
/**
|
|
91
|
+
* Read a slice of a stored file without transferring the whole object.
|
|
92
|
+
*
|
|
93
|
+
* Uses an HTTP Range request, so only the requested bytes cross the wire.
|
|
94
|
+
* Slicing is positional and format-agnostic — it works on any file.
|
|
95
|
+
*
|
|
96
|
+
* ```ts
|
|
97
|
+
* // First 64 KiB
|
|
98
|
+
* const head = await dms.readRange(libraryUuid, 'reports/big.csv', { length: 65536 })
|
|
99
|
+
*
|
|
100
|
+
* // Continue from where that stopped
|
|
101
|
+
* const next = await dms.readRange(libraryUuid, 'reports/big.csv', { offset: head.end + 1, length: 65536 })
|
|
102
|
+
*
|
|
103
|
+
* // Final 1 KiB
|
|
104
|
+
* const tail = await dms.readRange(libraryUuid, 'reports/big.csv', { suffix: 1024 })
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* The server caps how much a single call may return, so `length` is an upper
|
|
108
|
+
* bound rather than a guarantee: always advance using the returned `end`
|
|
109
|
+
* rather than assuming the window you asked for. `eof` tells you when to stop.
|
|
110
|
+
*
|
|
111
|
+
* Byte ranges are not meaningful for .xlsx, .zip or .gz — their contents are
|
|
112
|
+
* compressed as a unit, so no byte window corresponds to a range of rows.
|
|
113
|
+
*
|
|
114
|
+
* @param lib Library UUID
|
|
115
|
+
* @param key Path of the file within the library
|
|
116
|
+
* @param range Which bytes to read
|
|
117
|
+
* @throws If the object is smaller than `offset` (nothing left to read), or if
|
|
118
|
+
* the response came back without range metadata — see `readRange`'s
|
|
119
|
+
* Content-Range check, which prevents silently receiving a whole file.
|
|
120
|
+
*/
|
|
121
|
+
readRange(lib: string, key: string, range?: ByteRangeRequest): Promise<ByteRangeResult>;
|
|
122
|
+
/**
|
|
123
|
+
* Read a file as a sequence of byte windows, newest request issued only when
|
|
124
|
+
* the previous window has been consumed.
|
|
125
|
+
*
|
|
126
|
+
* This is the memory-bounded way to process a large file: the whole object is
|
|
127
|
+
* never held at once, and a caller can stop early simply by breaking out.
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* for await (const chunk of dms.streamRanges(libraryUuid, 'logs/huge.ndjson', { chunkSize: 1 << 20 })) {
|
|
131
|
+
* process(chunk.data) // one window at a time
|
|
132
|
+
* if (foundWhatIWanted) break // no further requests are made
|
|
133
|
+
* }
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* Windows are contiguous and non-overlapping, so concatenating every `data`
|
|
137
|
+
* reproduces the file byte for byte. A record spanning a window boundary is
|
|
138
|
+
* the caller's to reassemble — this yields bytes, not records.
|
|
139
|
+
*
|
|
140
|
+
* An empty object yields nothing rather than throwing.
|
|
141
|
+
*
|
|
142
|
+
* @param lib Library UUID
|
|
143
|
+
* @param key Path of the file within the library
|
|
144
|
+
* @param options Where to start and how large each window should be
|
|
145
|
+
*/
|
|
146
|
+
streamRanges(lib: string, key: string, options?: ByteStreamOptions): AsyncGenerator<ByteRangeResult>;
|
|
90
147
|
download(lib: string, key: string): Promise<AxiosResponse<any, any>>;
|
|
91
148
|
getExifData(lib: string, key: string): Promise<AxiosResponse<any, any>>;
|
|
92
149
|
html2pdf(lib: string, data: HTML2PDFOptions): Promise<AxiosResponse<any, any>>;
|
|
@@ -13,27 +13,27 @@ export default class Payments extends IntegrationsBaseClient {
|
|
|
13
13
|
currentPage: number;
|
|
14
14
|
pageSize: number;
|
|
15
15
|
}>;
|
|
16
|
-
getTransaction(provider: PaymentProvider,
|
|
16
|
+
getTransaction(provider: PaymentProvider, transactionId: string): Promise<Transaction>;
|
|
17
17
|
settings(provider: PaymentProvider): Promise<{
|
|
18
18
|
merchant_key: string;
|
|
19
19
|
authenticity_token: string;
|
|
20
20
|
}>;
|
|
21
|
-
deactivatePaymentLink(provider: PaymentProvider,
|
|
22
|
-
voidTransaction(provider: PaymentProvider,
|
|
23
|
-
refund(provider: PaymentProvider,
|
|
24
|
-
getPaymentLink(provider: PaymentProvider,
|
|
21
|
+
deactivatePaymentLink(provider: PaymentProvider, transactionId: string): Promise<import("axios").AxiosResponse<any, any>>;
|
|
22
|
+
voidTransaction(provider: PaymentProvider, transactionId: string): Promise<import("axios").AxiosResponse<any, any>>;
|
|
23
|
+
refund(provider: PaymentProvider, transactionId: string): Promise<import("axios").AxiosResponse<any, any>>;
|
|
24
|
+
getPaymentLink(provider: PaymentProvider, options: PaymentAmount & {
|
|
25
25
|
description: string;
|
|
26
26
|
token?: string;
|
|
27
27
|
isTokenRequest?: boolean;
|
|
28
28
|
redirectUrl?: string;
|
|
29
29
|
lang?: "en" | "es" | "ba" | "hr";
|
|
30
30
|
}): Promise<import("axios").AxiosResponse<any, any>>;
|
|
31
|
-
getTokenRequestLink(provider: PaymentProvider,
|
|
31
|
+
getTokenRequestLink(provider: PaymentProvider, options: {
|
|
32
32
|
description: string;
|
|
33
33
|
redirectUrl?: string;
|
|
34
34
|
lang?: "en" | "es" | "ba" | "hr";
|
|
35
35
|
}): Promise<import("axios").AxiosResponse<any, any>>;
|
|
36
|
-
directPayUsingToken(provider: PaymentProvider,
|
|
36
|
+
directPayUsingToken(provider: PaymentProvider, options: PaymentAmount & {
|
|
37
37
|
description: string;
|
|
38
38
|
token: string;
|
|
39
39
|
}): Promise<import("axios").AxiosResponse<any, any>>;
|