@delopay/sdk 0.277.0 → 0.280.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/README.md +2 -0
- package/dist/{chunk-424242UX.js → chunk-3CHJT5YW.js} +611 -71
- package/dist/chunk-3CHJT5YW.js.map +1 -0
- package/dist/index-DmObtUEw.d.cts +29526 -0
- package/dist/index-DmObtUEw.d.ts +29526 -0
- package/dist/index.cjs +611 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -29117
- package/dist/index.d.ts +1 -29117
- package/dist/index.js +5 -1
- package/dist/internal.cjs +675 -70
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +45 -3
- package/dist/internal.d.ts +45 -3
- package/dist/internal.js +69 -1
- package/dist/internal.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-424242UX.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -83,6 +83,8 @@ __export(index_exports, {
|
|
|
83
83
|
InvoiceSettingsResource: () => InvoiceSettingsResource,
|
|
84
84
|
Invoices: () => Invoices,
|
|
85
85
|
LOCALIZABLE_COPY_FIELDS: () => LOCALIZABLE_COPY_FIELDS,
|
|
86
|
+
Live: () => Live,
|
|
87
|
+
LiveEventStream: () => LiveEventStream,
|
|
86
88
|
MAX_SECTION_LABEL_LENGTH: () => MAX_SECTION_LABEL_LENGTH,
|
|
87
89
|
MAX_SECTION_ORDER: () => MAX_SECTION_ORDER,
|
|
88
90
|
METHOD_SECTIONS: () => METHOD_SECTIONS,
|
|
@@ -308,6 +310,100 @@ var DelopayAuthenticationError = class extends DelopayError {
|
|
|
308
310
|
}
|
|
309
311
|
};
|
|
310
312
|
|
|
313
|
+
// src/eventStream.ts
|
|
314
|
+
var LF = 10;
|
|
315
|
+
var CR = 13;
|
|
316
|
+
var EventStreamParser = class {
|
|
317
|
+
/**
|
|
318
|
+
* @param lastEventId - The id the stream resumes after, as `EventSource`
|
|
319
|
+
* carries it into a reconnection: a dispatch before the server names an
|
|
320
|
+
* id keeps this one.
|
|
321
|
+
*/
|
|
322
|
+
constructor(lastEventId = "") {
|
|
323
|
+
this.line = "";
|
|
324
|
+
/** The previous chunk ended in CR: a LF opening the next one belongs to it. */
|
|
325
|
+
this.skipLf = false;
|
|
326
|
+
this.data = "";
|
|
327
|
+
this.hasData = false;
|
|
328
|
+
this.eventType = "";
|
|
329
|
+
this.retry = null;
|
|
330
|
+
this.idBuffer = lastEventId;
|
|
331
|
+
}
|
|
332
|
+
/** Feed the next piece of decoded text; returns the dispatches it completed. */
|
|
333
|
+
push(text) {
|
|
334
|
+
const out = [];
|
|
335
|
+
if (text.length === 0) return out;
|
|
336
|
+
let start = 0;
|
|
337
|
+
if (this.skipLf) {
|
|
338
|
+
this.skipLf = false;
|
|
339
|
+
if (text.charCodeAt(0) === LF) start = 1;
|
|
340
|
+
}
|
|
341
|
+
for (let i = start; i < text.length; i++) {
|
|
342
|
+
const c = text.charCodeAt(i);
|
|
343
|
+
if (c !== LF && c !== CR) continue;
|
|
344
|
+
const line = this.line + text.slice(start, i);
|
|
345
|
+
this.line = "";
|
|
346
|
+
this.processLine(line, out);
|
|
347
|
+
if (c === CR) {
|
|
348
|
+
if (i + 1 < text.length) {
|
|
349
|
+
if (text.charCodeAt(i + 1) === LF) i++;
|
|
350
|
+
} else {
|
|
351
|
+
this.skipLf = true;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
start = i + 1;
|
|
355
|
+
}
|
|
356
|
+
this.line += text.slice(start);
|
|
357
|
+
return out;
|
|
358
|
+
}
|
|
359
|
+
processLine(line, out) {
|
|
360
|
+
if (line === "") {
|
|
361
|
+
this.dispatch(out);
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (line.charCodeAt(0) === 58) return;
|
|
365
|
+
const colon = line.indexOf(":");
|
|
366
|
+
let field;
|
|
367
|
+
let value;
|
|
368
|
+
if (colon === -1) {
|
|
369
|
+
field = line;
|
|
370
|
+
value = "";
|
|
371
|
+
} else {
|
|
372
|
+
field = line.slice(0, colon);
|
|
373
|
+
value = line.slice(colon + 1);
|
|
374
|
+
if (value.charCodeAt(0) === 32) value = value.slice(1);
|
|
375
|
+
}
|
|
376
|
+
switch (field) {
|
|
377
|
+
case "event":
|
|
378
|
+
this.eventType = value;
|
|
379
|
+
break;
|
|
380
|
+
case "data":
|
|
381
|
+
this.data = this.hasData ? `${this.data}
|
|
382
|
+
${value}` : value;
|
|
383
|
+
this.hasData = true;
|
|
384
|
+
break;
|
|
385
|
+
case "id":
|
|
386
|
+
if (!value.includes("\0")) this.idBuffer = value;
|
|
387
|
+
break;
|
|
388
|
+
case "retry":
|
|
389
|
+
if (/^[0-9]+$/.test(value)) {
|
|
390
|
+
const ms = Number(value);
|
|
391
|
+
if (Number.isSafeInteger(ms)) this.retry = ms;
|
|
392
|
+
}
|
|
393
|
+
break;
|
|
394
|
+
default:
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
dispatch(out) {
|
|
399
|
+
const event = this.hasData ? { type: this.eventType || "message", data: this.data } : null;
|
|
400
|
+
out.push({ lastEventId: this.idBuffer, retry: this.retry, event });
|
|
401
|
+
this.data = "";
|
|
402
|
+
this.hasData = false;
|
|
403
|
+
this.eventType = "";
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
311
407
|
// src/resources/apiKeys.ts
|
|
312
408
|
var ApiKeys = class {
|
|
313
409
|
constructor(request) {
|
|
@@ -1553,8 +1649,8 @@ var Customers = class {
|
|
|
1553
1649
|
};
|
|
1554
1650
|
|
|
1555
1651
|
// src/recordCounter.ts
|
|
1556
|
-
var
|
|
1557
|
-
var
|
|
1652
|
+
var LF2 = 10;
|
|
1653
|
+
var CR2 = 13;
|
|
1558
1654
|
var QUOTE = 34;
|
|
1559
1655
|
var BACKSLASH = 92;
|
|
1560
1656
|
var OPEN_BRACE = 123;
|
|
@@ -1578,10 +1674,10 @@ var CsvRecordCounter = class {
|
|
|
1578
1674
|
lineHasContent = true;
|
|
1579
1675
|
} else if (inQuotes) {
|
|
1580
1676
|
lineHasContent = true;
|
|
1581
|
-
} else if (byte ===
|
|
1677
|
+
} else if (byte === LF2) {
|
|
1582
1678
|
newlines++;
|
|
1583
1679
|
lineHasContent = false;
|
|
1584
|
-
} else if (byte !==
|
|
1680
|
+
} else if (byte !== CR2) {
|
|
1585
1681
|
lineHasContent = true;
|
|
1586
1682
|
}
|
|
1587
1683
|
}
|
|
@@ -5102,6 +5198,33 @@ var Users = class {
|
|
|
5102
5198
|
body: params
|
|
5103
5199
|
});
|
|
5104
5200
|
}
|
|
5201
|
+
/**
|
|
5202
|
+
* Which checkout payment methods a member may change in your merchant.
|
|
5203
|
+
* `GET /user/employees/{user_id}/method-access`
|
|
5204
|
+
*
|
|
5205
|
+
* Needs the *Users* read permission, and answers only for a member
|
|
5206
|
+
* `listUsersInLineage` shows you (any other id is a 404 `UR_68` with
|
|
5207
|
+
* `data.reason: 'member_not_found'`). `can_edit` says whether you may
|
|
5208
|
+
* change it; `grant_all` and `grantable` say which methods you may grant.
|
|
5209
|
+
*/
|
|
5210
|
+
async getMemberMethodAccess(userId) {
|
|
5211
|
+
return this.request("GET", `/user/employees/${encodeURIComponent(userId)}/method-access`);
|
|
5212
|
+
}
|
|
5213
|
+
/**
|
|
5214
|
+
* Limit a member to some checkout payment methods, or give every method
|
|
5215
|
+
* back. `PUT /user/employees/{user_id}/method-access`
|
|
5216
|
+
*
|
|
5217
|
+
* Needs the *Connectors* edit and *Payment methods* write permissions and a
|
|
5218
|
+
* member within your reach, other than yourself. A caller limited itself
|
|
5219
|
+
* grants only within its own limit. The change is audited and applies to
|
|
5220
|
+
* the member's next request. A refusal is a `UR_68` whose `data` is
|
|
5221
|
+
* `{ reason: 'method_access', refusal }` (see {@link MethodAccessRefusal}).
|
|
5222
|
+
*/
|
|
5223
|
+
async updateMemberMethodAccess(userId, params) {
|
|
5224
|
+
return this.request("PUT", `/user/employees/${encodeURIComponent(userId)}/method-access`, {
|
|
5225
|
+
body: params
|
|
5226
|
+
});
|
|
5227
|
+
}
|
|
5105
5228
|
/** Sign in via OIDC. `POST /user/oidc` */
|
|
5106
5229
|
async signInOidc(params) {
|
|
5107
5230
|
return this.request("POST", "/user/oidc", { body: params });
|
|
@@ -9115,6 +9238,133 @@ var Risk = class {
|
|
|
9115
9238
|
}
|
|
9116
9239
|
};
|
|
9117
9240
|
|
|
9241
|
+
// src/resources/live.ts
|
|
9242
|
+
function readField(data, key) {
|
|
9243
|
+
let value;
|
|
9244
|
+
try {
|
|
9245
|
+
value = JSON.parse(data);
|
|
9246
|
+
} catch {
|
|
9247
|
+
return void 0;
|
|
9248
|
+
}
|
|
9249
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
9250
|
+
return Object.getOwnPropertyDescriptor(value, key)?.value;
|
|
9251
|
+
}
|
|
9252
|
+
function toLiveStreamEvent(event, id, retry) {
|
|
9253
|
+
switch (event.type) {
|
|
9254
|
+
case "ready": {
|
|
9255
|
+
const resumed = readField(event.data, "resumed");
|
|
9256
|
+
return { type: "ready", id, retry, resumed: typeof resumed === "boolean" ? resumed : null };
|
|
9257
|
+
}
|
|
9258
|
+
case "change": {
|
|
9259
|
+
const changes = readField(event.data, "changes");
|
|
9260
|
+
if (!Array.isArray(changes)) return { type: "resync", id };
|
|
9261
|
+
return { type: "change", id, changes };
|
|
9262
|
+
}
|
|
9263
|
+
case "resync":
|
|
9264
|
+
return { type: "resync", id };
|
|
9265
|
+
default:
|
|
9266
|
+
return null;
|
|
9267
|
+
}
|
|
9268
|
+
}
|
|
9269
|
+
var LiveEventStream = class {
|
|
9270
|
+
constructor(connection, lastEventId = null) {
|
|
9271
|
+
this.connection = connection;
|
|
9272
|
+
this._retry = null;
|
|
9273
|
+
this._lastEventId = lastEventId || null;
|
|
9274
|
+
}
|
|
9275
|
+
/**
|
|
9276
|
+
* The position to resume after: the id of the last event read, advanced by
|
|
9277
|
+
* keepalives too. `null` before the server named one. Send it as
|
|
9278
|
+
* `lastEventId` when reconnecting.
|
|
9279
|
+
*/
|
|
9280
|
+
get lastEventId() {
|
|
9281
|
+
return this._lastEventId;
|
|
9282
|
+
}
|
|
9283
|
+
/** The wait before reconnecting the server asked for, in ms; `null` until it says. */
|
|
9284
|
+
get retry() {
|
|
9285
|
+
return this._retry;
|
|
9286
|
+
}
|
|
9287
|
+
/** Close the stream; the iteration ends without an error. */
|
|
9288
|
+
close() {
|
|
9289
|
+
this.connection.close();
|
|
9290
|
+
}
|
|
9291
|
+
[Symbol.asyncIterator]() {
|
|
9292
|
+
this.iterator ?? (this.iterator = this.events());
|
|
9293
|
+
return this.iterator;
|
|
9294
|
+
}
|
|
9295
|
+
async *events() {
|
|
9296
|
+
for await (const dispatch of this.connection.dispatches) {
|
|
9297
|
+
const event = this.read(dispatch);
|
|
9298
|
+
if (event) yield event;
|
|
9299
|
+
}
|
|
9300
|
+
}
|
|
9301
|
+
read(dispatch) {
|
|
9302
|
+
this._lastEventId = dispatch.lastEventId || null;
|
|
9303
|
+
if (dispatch.retry !== null) this._retry = dispatch.retry;
|
|
9304
|
+
if (!dispatch.event) return null;
|
|
9305
|
+
return toLiveStreamEvent(dispatch.event, this._lastEventId, this._retry);
|
|
9306
|
+
}
|
|
9307
|
+
};
|
|
9308
|
+
async function openLiveStream(openStream, path, options = {}) {
|
|
9309
|
+
const connection = await openStream(path, {
|
|
9310
|
+
...options.lastEventId ? { lastEventId: options.lastEventId } : {},
|
|
9311
|
+
...options.signal ? { signal: options.signal } : {},
|
|
9312
|
+
...options.idleTimeoutMs !== void 0 ? { idleTimeoutMs: options.idleTimeoutMs } : {},
|
|
9313
|
+
...options.headers ? { headers: options.headers } : {}
|
|
9314
|
+
});
|
|
9315
|
+
return new LiveEventStream(connection, options.lastEventId ?? null);
|
|
9316
|
+
}
|
|
9317
|
+
var Live = class {
|
|
9318
|
+
constructor(request, openStream) {
|
|
9319
|
+
this.request = request;
|
|
9320
|
+
this.openStream = openStream;
|
|
9321
|
+
}
|
|
9322
|
+
/**
|
|
9323
|
+
* Open the stream of what changed in the caller's merchant, as their role
|
|
9324
|
+
* may read it. Resolves once the server answered; a `401` rejects with
|
|
9325
|
+
* `DelopayAuthenticationError`.
|
|
9326
|
+
*
|
|
9327
|
+
* The first event is `ready`. `change` names the kinds of record and, when
|
|
9328
|
+
* few, the ids that changed: read them again through the usual endpoints.
|
|
9329
|
+
* `resync`, and `ready` with `resumed: false`, mean read everything again.
|
|
9330
|
+
* The SDK does not reconnect — see {@link LiveEventStream}.
|
|
9331
|
+
*
|
|
9332
|
+
* `GET /live/stream`
|
|
9333
|
+
*
|
|
9334
|
+
* @example
|
|
9335
|
+
* ```typescript
|
|
9336
|
+
* const stream = await delopay.live.stream({ lastEventId, signal });
|
|
9337
|
+
* for await (const event of stream) {
|
|
9338
|
+
* if (event.type === 'change') refresh(event.changes);
|
|
9339
|
+
* else if (event.type === 'resync' || event.resumed === false) refreshAll();
|
|
9340
|
+
* }
|
|
9341
|
+
* lastEventId = stream.lastEventId; // reconnect after stream.retry
|
|
9342
|
+
* ```
|
|
9343
|
+
*/
|
|
9344
|
+
async stream(options) {
|
|
9345
|
+
return openLiveStream(this.openStream, "/live/stream", options);
|
|
9346
|
+
}
|
|
9347
|
+
/**
|
|
9348
|
+
* The current version of each kind of record named, in the caller's
|
|
9349
|
+
* merchant and shop. Read it before the record and send the entry's
|
|
9350
|
+
* `if_match` in the `If-Match` header of the save: a save over a newer
|
|
9351
|
+
* version is refused with `IR_16` (400), `error.data` a
|
|
9352
|
+
* `LiveChangedElsewhere` naming who made the change.
|
|
9353
|
+
*
|
|
9354
|
+
* `GET /live/versions`
|
|
9355
|
+
*/
|
|
9356
|
+
async versions(params, options) {
|
|
9357
|
+
return this.request("GET", "/live/versions", {
|
|
9358
|
+
query: {
|
|
9359
|
+
entities: params.entities.join(","),
|
|
9360
|
+
profile_id: params.profile_id,
|
|
9361
|
+
record_id: params.record_id
|
|
9362
|
+
},
|
|
9363
|
+
...options
|
|
9364
|
+
});
|
|
9365
|
+
}
|
|
9366
|
+
};
|
|
9367
|
+
|
|
9118
9368
|
// src/client.ts
|
|
9119
9369
|
var PRODUCTION_URL = "https://api.delopay.net";
|
|
9120
9370
|
var SANDBOX_URL = "https://sandbox.delopay.net";
|
|
@@ -9138,6 +9388,40 @@ function truncateRawBody(raw) {
|
|
|
9138
9388
|
if (!raw) return void 0;
|
|
9139
9389
|
return raw.length > MAX_RAW_BODY_BYTES ? raw.slice(0, MAX_RAW_BODY_BYTES) + "\u2026" : raw;
|
|
9140
9390
|
}
|
|
9391
|
+
async function errorFromResponse(response, requestId) {
|
|
9392
|
+
const rawBody = await response.text().catch(() => "");
|
|
9393
|
+
let parsed = {};
|
|
9394
|
+
if (rawBody) {
|
|
9395
|
+
try {
|
|
9396
|
+
parsed = JSON.parse(rawBody);
|
|
9397
|
+
} catch {
|
|
9398
|
+
}
|
|
9399
|
+
}
|
|
9400
|
+
const err = parsed.error ?? parsed;
|
|
9401
|
+
const message = err.message ?? `Request failed with status ${response.status}`;
|
|
9402
|
+
const code = err.code ?? "";
|
|
9403
|
+
const type = err.error_type ?? err.type ?? "";
|
|
9404
|
+
const data = err.data && typeof err.data === "object" && !Array.isArray(err.data) ? err.data : void 0;
|
|
9405
|
+
const truncatedRaw = truncateRawBody(rawBody);
|
|
9406
|
+
const isConnectorPassthrough = type === "connector" || code.startsWith("CE_");
|
|
9407
|
+
if (response.status === 401 && !isConnectorPassthrough) {
|
|
9408
|
+
return new DelopayAuthenticationError(message, {
|
|
9409
|
+
code,
|
|
9410
|
+
type,
|
|
9411
|
+
requestId,
|
|
9412
|
+
rawBody: truncatedRaw,
|
|
9413
|
+
data
|
|
9414
|
+
});
|
|
9415
|
+
}
|
|
9416
|
+
return new DelopayError(message, {
|
|
9417
|
+
status: response.status,
|
|
9418
|
+
code,
|
|
9419
|
+
type,
|
|
9420
|
+
requestId,
|
|
9421
|
+
rawBody: truncatedRaw,
|
|
9422
|
+
data
|
|
9423
|
+
});
|
|
9424
|
+
}
|
|
9141
9425
|
function findIdempotencyKey(headers) {
|
|
9142
9426
|
for (const [k, v] of Object.entries(headers)) {
|
|
9143
9427
|
if (k.toLowerCase() === "idempotency-key") return v;
|
|
@@ -9298,6 +9582,7 @@ function redactUrlForLogging(url) {
|
|
|
9298
9582
|
});
|
|
9299
9583
|
return `${base}?${parts.join("&")}`;
|
|
9300
9584
|
}
|
|
9585
|
+
var DEFAULT_STREAM_IDLE_TIMEOUT_MS = 45e3;
|
|
9301
9586
|
var Delopay = class {
|
|
9302
9587
|
/**
|
|
9303
9588
|
* Create a new Delopay client.
|
|
@@ -9320,6 +9605,7 @@ var Delopay = class {
|
|
|
9320
9605
|
this.baseUrl = PRODUCTION_URL;
|
|
9321
9606
|
}
|
|
9322
9607
|
const request = this.request.bind(this);
|
|
9608
|
+
const openStream = this.openEventStream.bind(this);
|
|
9323
9609
|
this.payments = new Payments(request);
|
|
9324
9610
|
this.refunds = new Refunds(request);
|
|
9325
9611
|
this.customers = new Customers(request);
|
|
@@ -9356,6 +9642,7 @@ var Delopay = class {
|
|
|
9356
9642
|
this.settings = new Settings(request);
|
|
9357
9643
|
this.messageTemplates = new MessageTemplates(request);
|
|
9358
9644
|
this.risk = new Risk(request);
|
|
9645
|
+
this.live = new Live(request, openStream);
|
|
9359
9646
|
this.subscriptions = new Subscriptions(request);
|
|
9360
9647
|
this.buyerPortal = new BuyerPortal(request);
|
|
9361
9648
|
this.buyerAccount = new BuyerAccount(request);
|
|
@@ -9432,24 +9719,12 @@ var Delopay = class {
|
|
|
9432
9719
|
this.setJwtToken(response.token);
|
|
9433
9720
|
return response;
|
|
9434
9721
|
}
|
|
9435
|
-
/**
|
|
9436
|
-
|
|
9437
|
-
*
|
|
9438
|
-
* You rarely need to call this directly — prefer the typed resource methods.
|
|
9439
|
-
* Use it only for endpoints not yet covered by a resource class.
|
|
9440
|
-
*
|
|
9441
|
-
* @param method - HTTP method (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`).
|
|
9442
|
-
* @param path - API path starting with `/` (e.g. `/payments`).
|
|
9443
|
-
* @param options - Optional body, query parameters, and headers.
|
|
9444
|
-
* @returns Parsed JSON response body typed as `T`.
|
|
9445
|
-
* @throws {DelopayAuthenticationError} On 401 responses.
|
|
9446
|
-
* @throws {DelopayError} On all other non-2xx responses, timeouts, and network errors.
|
|
9447
|
-
*/
|
|
9448
|
-
async request(method, path, options) {
|
|
9722
|
+
/** `path` on the base URL, with the query string `query` makes. */
|
|
9723
|
+
buildUrl(path, query) {
|
|
9449
9724
|
let url = `${this.baseUrl}${path}`;
|
|
9450
|
-
if (
|
|
9725
|
+
if (query) {
|
|
9451
9726
|
const params = new URLSearchParams();
|
|
9452
|
-
for (const [key, value] of Object.entries(
|
|
9727
|
+
for (const [key, value] of Object.entries(query)) {
|
|
9453
9728
|
if (value === void 0 || value === null) continue;
|
|
9454
9729
|
if (Array.isArray(value)) {
|
|
9455
9730
|
for (const v of value) {
|
|
@@ -9464,8 +9739,189 @@ var Delopay = class {
|
|
|
9464
9739
|
url += `?${qs}`;
|
|
9465
9740
|
}
|
|
9466
9741
|
}
|
|
9742
|
+
return url;
|
|
9743
|
+
}
|
|
9744
|
+
/** The credential header: the JWT when one is set, else the API key. */
|
|
9745
|
+
authHeaders() {
|
|
9746
|
+
if (this.jwtToken) return { Authorization: `Bearer ${this.jwtToken}` };
|
|
9747
|
+
if (this.apiKey) return { "api-key": this.apiKey };
|
|
9748
|
+
return {};
|
|
9749
|
+
}
|
|
9750
|
+
/** One debug event, when `debug` is on. */
|
|
9751
|
+
log(event, data) {
|
|
9752
|
+
if (!this.debug) return;
|
|
9753
|
+
if (this.logger) {
|
|
9754
|
+
this.logger(event, data);
|
|
9755
|
+
return;
|
|
9756
|
+
}
|
|
9757
|
+
if (event === "request")
|
|
9758
|
+
console.log(`[delopay] ${data.method} ${data.url}`);
|
|
9759
|
+
else if (event === "response")
|
|
9760
|
+
console.log(
|
|
9761
|
+
`[delopay] ${data.status} ${data.method} ${data.path}`
|
|
9762
|
+
);
|
|
9763
|
+
else
|
|
9764
|
+
console.log(
|
|
9765
|
+
`[delopay] retry ${data.attempt}/${data.maxRetries} ${data.method} ${data.path}`
|
|
9766
|
+
);
|
|
9767
|
+
}
|
|
9768
|
+
/**
|
|
9769
|
+
* Open a `GET` `text/event-stream` and read it as it arrives.
|
|
9770
|
+
*
|
|
9771
|
+
* `request()` keeps every chunk of a body until the body ends, which a
|
|
9772
|
+
* stream that stays open for half an hour must not do; this reads the body
|
|
9773
|
+
* chunk by chunk through {@link EventStreamParser} and keeps nothing it has
|
|
9774
|
+
* dispatched. Credentials, the base URL, debug logging and the mapping of a
|
|
9775
|
+
* non-2xx answer to `DelopayError` / `DelopayAuthenticationError` are the
|
|
9776
|
+
* ones `request()` uses.
|
|
9777
|
+
*
|
|
9778
|
+
* Never retried, and never reconnected: the caller owns reconnection.
|
|
9779
|
+
* Resolves once the response headers arrive; rejects on a non-2xx answer,
|
|
9780
|
+
* on a 2xx that is not `text/event-stream` (code `NOT_EVENT_STREAM`), and
|
|
9781
|
+
* with `TIMEOUT`, `NETWORK` or `ABORTED` like `request()`.
|
|
9782
|
+
*/
|
|
9783
|
+
async openEventStream(path, options = {}) {
|
|
9784
|
+
const url = this.buildUrl(path, options.query);
|
|
9785
|
+
const lastEventId = options.lastEventId ?? "";
|
|
9786
|
+
const headers = {
|
|
9787
|
+
...this.authHeaders(),
|
|
9788
|
+
Accept: "text/event-stream",
|
|
9789
|
+
...lastEventId ? { "Last-Event-ID": lastEventId } : {},
|
|
9790
|
+
...options.headers
|
|
9791
|
+
};
|
|
9792
|
+
const idleMs = options.idleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS;
|
|
9793
|
+
const callerSignal = options.signal;
|
|
9794
|
+
const aborted = () => new DelopayError("Request aborted", { status: 0, code: "ABORTED", type: "abort_error" });
|
|
9795
|
+
if (callerSignal?.aborted) throw aborted();
|
|
9796
|
+
const idleCtrl = new AbortController();
|
|
9797
|
+
const closeCtrl = new AbortController();
|
|
9798
|
+
let timer;
|
|
9799
|
+
const stopIdleTimer = () => {
|
|
9800
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
9801
|
+
timer = void 0;
|
|
9802
|
+
};
|
|
9803
|
+
const startIdleTimer = () => {
|
|
9804
|
+
stopIdleTimer();
|
|
9805
|
+
if (!idleCtrl.signal.aborted) timer = setTimeout(() => idleCtrl.abort(), idleMs);
|
|
9806
|
+
};
|
|
9807
|
+
const combined = combineSignals(
|
|
9808
|
+
callerSignal ? [idleCtrl.signal, closeCtrl.signal, callerSignal] : [idleCtrl.signal, closeCtrl.signal]
|
|
9809
|
+
);
|
|
9810
|
+
const release = () => {
|
|
9811
|
+
stopIdleTimer();
|
|
9812
|
+
combined.dispose();
|
|
9813
|
+
};
|
|
9814
|
+
const timedOut = () => new DelopayError(`Event stream silent for ${idleMs} ms`, {
|
|
9815
|
+
status: 0,
|
|
9816
|
+
code: "TIMEOUT",
|
|
9817
|
+
type: "timeout_error"
|
|
9818
|
+
});
|
|
9819
|
+
const network = (cause) => new DelopayError(
|
|
9820
|
+
`Network error: ${cause instanceof Error ? cause.message : String(cause ?? "stream failed")}`,
|
|
9821
|
+
{ status: 0, code: "NETWORK", type: "network_error" }
|
|
9822
|
+
);
|
|
9823
|
+
this.log("request", { method: "GET", url: redactUrlForLogging(url), path });
|
|
9824
|
+
startIdleTimer();
|
|
9825
|
+
let response;
|
|
9826
|
+
try {
|
|
9827
|
+
response = await fetch(url, { method: "GET", headers, signal: combined.signal });
|
|
9828
|
+
} catch (err) {
|
|
9829
|
+
release();
|
|
9830
|
+
if (callerSignal?.aborted) throw aborted();
|
|
9831
|
+
if (idleCtrl.signal.aborted) throw timedOut();
|
|
9832
|
+
throw network(err);
|
|
9833
|
+
}
|
|
9834
|
+
const requestId = response.headers?.get("x-request-id") ?? response.headers?.get("x-trace-id") ?? void 0;
|
|
9835
|
+
this.log("response", { status: response.status, method: "GET", path, requestId });
|
|
9836
|
+
if (!response.ok) {
|
|
9837
|
+
const error = await errorFromResponse(response, requestId);
|
|
9838
|
+
release();
|
|
9839
|
+
throw error;
|
|
9840
|
+
}
|
|
9841
|
+
const body = response.body;
|
|
9842
|
+
const contentType = response.headers?.get("content-type") ?? "";
|
|
9843
|
+
const mediaType = (contentType.split(";")[0] ?? "").trim().toLowerCase();
|
|
9844
|
+
if (mediaType !== "text/event-stream" || !body || typeof body.getReader !== "function") {
|
|
9845
|
+
release();
|
|
9846
|
+
body?.cancel().catch(noop);
|
|
9847
|
+
throw new DelopayError(
|
|
9848
|
+
mediaType === "text/event-stream" ? "The event stream has no readable body" : `Expected a text/event-stream response, got ${contentType ? `"${contentType}"` : "no content type"}`,
|
|
9849
|
+
{
|
|
9850
|
+
status: response.status,
|
|
9851
|
+
code: "NOT_EVENT_STREAM",
|
|
9852
|
+
type: "invalid_response",
|
|
9853
|
+
requestId
|
|
9854
|
+
}
|
|
9855
|
+
);
|
|
9856
|
+
}
|
|
9857
|
+
stopIdleTimer();
|
|
9858
|
+
const reader = body.getReader();
|
|
9859
|
+
const parser = new EventStreamParser(lastEventId);
|
|
9860
|
+
const decoder = new TextDecoder();
|
|
9861
|
+
const stopped = () => Boolean(callerSignal?.aborted) || closeCtrl.signal.aborted;
|
|
9862
|
+
let finished = false;
|
|
9863
|
+
const finish = () => {
|
|
9864
|
+
if (finished) return;
|
|
9865
|
+
finished = true;
|
|
9866
|
+
release();
|
|
9867
|
+
reader.cancel().catch(noop);
|
|
9868
|
+
};
|
|
9869
|
+
async function* dispatches() {
|
|
9870
|
+
try {
|
|
9871
|
+
for (; ; ) {
|
|
9872
|
+
let result;
|
|
9873
|
+
startIdleTimer();
|
|
9874
|
+
try {
|
|
9875
|
+
result = await readChunk(reader, combined.signal);
|
|
9876
|
+
} catch (err) {
|
|
9877
|
+
if (callerSignal?.aborted || closeCtrl.signal.aborted) return;
|
|
9878
|
+
if (idleCtrl.signal.aborted) throw timedOut();
|
|
9879
|
+
throw network(err instanceof BodyStreamFailure ? err.cause : err);
|
|
9880
|
+
} finally {
|
|
9881
|
+
stopIdleTimer();
|
|
9882
|
+
}
|
|
9883
|
+
if (result.done) {
|
|
9884
|
+
for (const dispatch of parser.push(decoder.decode())) {
|
|
9885
|
+
if (stopped()) return;
|
|
9886
|
+
yield dispatch;
|
|
9887
|
+
}
|
|
9888
|
+
return;
|
|
9889
|
+
}
|
|
9890
|
+
if (!result.value || result.value.byteLength === 0) continue;
|
|
9891
|
+
for (const dispatch of parser.push(decoder.decode(result.value, { stream: true }))) {
|
|
9892
|
+
if (stopped()) return;
|
|
9893
|
+
yield dispatch;
|
|
9894
|
+
}
|
|
9895
|
+
}
|
|
9896
|
+
} finally {
|
|
9897
|
+
finish();
|
|
9898
|
+
}
|
|
9899
|
+
}
|
|
9900
|
+
return {
|
|
9901
|
+
dispatches: dispatches(),
|
|
9902
|
+
close: () => {
|
|
9903
|
+
closeCtrl.abort();
|
|
9904
|
+
finish();
|
|
9905
|
+
}
|
|
9906
|
+
};
|
|
9907
|
+
}
|
|
9908
|
+
/**
|
|
9909
|
+
* Make a raw HTTP request to the Delopay API.
|
|
9910
|
+
*
|
|
9911
|
+
* You rarely need to call this directly — prefer the typed resource methods.
|
|
9912
|
+
* Use it only for endpoints not yet covered by a resource class.
|
|
9913
|
+
*
|
|
9914
|
+
* @param method - HTTP method (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`).
|
|
9915
|
+
* @param path - API path starting with `/` (e.g. `/payments`).
|
|
9916
|
+
* @param options - Optional body, query parameters, and headers.
|
|
9917
|
+
* @returns Parsed JSON response body typed as `T`.
|
|
9918
|
+
* @throws {DelopayAuthenticationError} On 401 responses.
|
|
9919
|
+
* @throws {DelopayError} On all other non-2xx responses, timeouts, and network errors.
|
|
9920
|
+
*/
|
|
9921
|
+
async request(method, path, options) {
|
|
9922
|
+
const url = this.buildUrl(path, options?.query);
|
|
9467
9923
|
let headers = {
|
|
9468
|
-
...this.
|
|
9924
|
+
...this.authHeaders(),
|
|
9469
9925
|
...options?.headers
|
|
9470
9926
|
};
|
|
9471
9927
|
const isRawBody = options?.body !== void 0 && options?.body !== null && (options.body instanceof FormData || options.body instanceof Blob || options.body instanceof ArrayBuffer || options.body instanceof URLSearchParams);
|
|
@@ -9518,23 +9974,7 @@ var Delopay = class {
|
|
|
9518
9974
|
let lastError;
|
|
9519
9975
|
let retryAfterOverrideMs = null;
|
|
9520
9976
|
const safeUrl = () => redactUrlForLogging(url);
|
|
9521
|
-
const emit = (event, data) =>
|
|
9522
|
-
if (!this.debug) return;
|
|
9523
|
-
if (this.logger) {
|
|
9524
|
-
this.logger(event, data);
|
|
9525
|
-
return;
|
|
9526
|
-
}
|
|
9527
|
-
if (event === "request")
|
|
9528
|
-
console.log(`[delopay] ${data.method} ${data.url}`);
|
|
9529
|
-
else if (event === "response")
|
|
9530
|
-
console.log(
|
|
9531
|
-
`[delopay] ${data.status} ${data.method} ${data.path}`
|
|
9532
|
-
);
|
|
9533
|
-
else
|
|
9534
|
-
console.log(
|
|
9535
|
-
`[delopay] retry ${data.attempt}/${data.maxRetries} ${data.method} ${data.path}`
|
|
9536
|
-
);
|
|
9537
|
-
};
|
|
9977
|
+
const emit = (event, data) => this.log(event, data);
|
|
9538
9978
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
9539
9979
|
if (attempt > 0) {
|
|
9540
9980
|
const base = Math.min(500 * 2 ** (attempt - 1), 5e3);
|
|
@@ -9566,38 +10006,7 @@ var Delopay = class {
|
|
|
9566
10006
|
const requestId = response.headers?.get("x-request-id") ?? response.headers?.get("x-trace-id") ?? void 0;
|
|
9567
10007
|
emit("response", { status: response.status, method, path, requestId });
|
|
9568
10008
|
if (!response.ok) {
|
|
9569
|
-
const
|
|
9570
|
-
let parsed = {};
|
|
9571
|
-
if (rawBody) {
|
|
9572
|
-
try {
|
|
9573
|
-
parsed = JSON.parse(rawBody);
|
|
9574
|
-
} catch {
|
|
9575
|
-
}
|
|
9576
|
-
}
|
|
9577
|
-
const err = parsed.error ?? parsed;
|
|
9578
|
-
const message = err.message ?? `Request failed with status ${response.status}`;
|
|
9579
|
-
const code = err.code ?? "";
|
|
9580
|
-
const type = err.error_type ?? err.type ?? "";
|
|
9581
|
-
const data = err.data && typeof err.data === "object" && !Array.isArray(err.data) ? err.data : void 0;
|
|
9582
|
-
const truncatedRaw = truncateRawBody(rawBody);
|
|
9583
|
-
const isConnectorPassthrough = type === "connector" || code.startsWith("CE_");
|
|
9584
|
-
if (response.status === 401 && !isConnectorPassthrough) {
|
|
9585
|
-
throw new DelopayAuthenticationError(message, {
|
|
9586
|
-
code,
|
|
9587
|
-
type,
|
|
9588
|
-
requestId,
|
|
9589
|
-
rawBody: truncatedRaw,
|
|
9590
|
-
data
|
|
9591
|
-
});
|
|
9592
|
-
}
|
|
9593
|
-
const error = new DelopayError(message, {
|
|
9594
|
-
status: response.status,
|
|
9595
|
-
code,
|
|
9596
|
-
type,
|
|
9597
|
-
requestId,
|
|
9598
|
-
rawBody: truncatedRaw,
|
|
9599
|
-
data
|
|
9600
|
-
});
|
|
10009
|
+
const error = await errorFromResponse(response, requestId);
|
|
9601
10010
|
const isTransientStatus = response.status >= 500 || response.status === 429;
|
|
9602
10011
|
if (isTransientStatus && isRetryable && attempt < this.maxRetries) {
|
|
9603
10012
|
if (response.status === 429) {
|
|
@@ -11065,6 +11474,13 @@ var DEFAULT_BRANDING_BASE = {
|
|
|
11065
11474
|
paypalFocusRing: "strong",
|
|
11066
11475
|
mollieFocusRing: "strong",
|
|
11067
11476
|
paypalValidTint: false,
|
|
11477
|
+
epayoutsCardLayout: "split",
|
|
11478
|
+
epayoutsLabelStyle: "above",
|
|
11479
|
+
epayoutsFieldChrome: "outlined",
|
|
11480
|
+
epayoutsFieldFontSize: "md",
|
|
11481
|
+
epayoutsFieldWeight: "regular",
|
|
11482
|
+
epayoutsFocusRing: "strong",
|
|
11483
|
+
epayoutsValidTint: false,
|
|
11068
11484
|
nomupayFormStyle: "plain",
|
|
11069
11485
|
nomupayShowLabels: true,
|
|
11070
11486
|
nomupayShowPlaceholders: true,
|
|
@@ -12095,6 +12511,66 @@ function decodeBranding(source) {
|
|
|
12095
12511
|
DEFAULT_BRANDING.whopSelection
|
|
12096
12512
|
),
|
|
12097
12513
|
paypalValidTint: parseBool(extras["paypalValidTint"], DEFAULT_BRANDING.paypalValidTint),
|
|
12514
|
+
// A look stored before todos#412 has no e-Payouts keys: the form keeps
|
|
12515
|
+
// the PayPal values it was drawn with until then.
|
|
12516
|
+
epayoutsCardLayout: pickEnum(
|
|
12517
|
+
extras["epayoutsCardLayout"],
|
|
12518
|
+
PAYPAL_CARD_LAYOUTS,
|
|
12519
|
+
pickEnum(
|
|
12520
|
+
extras["paypalCardLayout"],
|
|
12521
|
+
PAYPAL_CARD_LAYOUTS,
|
|
12522
|
+
DEFAULT_BRANDING.epayoutsCardLayout
|
|
12523
|
+
)
|
|
12524
|
+
),
|
|
12525
|
+
epayoutsLabelStyle: pickEnum(
|
|
12526
|
+
extras["epayoutsLabelStyle"],
|
|
12527
|
+
PAYPAL_LABEL_STYLES,
|
|
12528
|
+
pickEnum(
|
|
12529
|
+
extras["paypalLabelStyle"],
|
|
12530
|
+
PAYPAL_LABEL_STYLES,
|
|
12531
|
+
DEFAULT_BRANDING.epayoutsLabelStyle
|
|
12532
|
+
)
|
|
12533
|
+
),
|
|
12534
|
+
epayoutsFieldChrome: pickEnum(
|
|
12535
|
+
extras["epayoutsFieldChrome"],
|
|
12536
|
+
CARD_FIELD_CHROMES,
|
|
12537
|
+
pickEnum(
|
|
12538
|
+
extras["paypalFieldChrome"],
|
|
12539
|
+
CARD_FIELD_CHROMES,
|
|
12540
|
+
DEFAULT_BRANDING.epayoutsFieldChrome
|
|
12541
|
+
)
|
|
12542
|
+
),
|
|
12543
|
+
epayoutsFieldFontSize: pickEnum(
|
|
12544
|
+
extras["epayoutsFieldFontSize"],
|
|
12545
|
+
CARD_FIELD_FONT_SIZES,
|
|
12546
|
+
pickEnum(
|
|
12547
|
+
extras["paypalFieldFontSize"],
|
|
12548
|
+
CARD_FIELD_FONT_SIZES,
|
|
12549
|
+
DEFAULT_BRANDING.epayoutsFieldFontSize
|
|
12550
|
+
)
|
|
12551
|
+
),
|
|
12552
|
+
epayoutsFieldWeight: pickEnum(
|
|
12553
|
+
extras["epayoutsFieldWeight"],
|
|
12554
|
+
CARD_FIELD_WEIGHTS,
|
|
12555
|
+
pickEnum(
|
|
12556
|
+
extras["paypalFieldWeight"],
|
|
12557
|
+
CARD_FIELD_WEIGHTS,
|
|
12558
|
+
DEFAULT_BRANDING.epayoutsFieldWeight
|
|
12559
|
+
)
|
|
12560
|
+
),
|
|
12561
|
+
epayoutsFocusRing: pickEnum(
|
|
12562
|
+
extras["epayoutsFocusRing"],
|
|
12563
|
+
CARD_FOCUS_RINGS,
|
|
12564
|
+
pickEnum(
|
|
12565
|
+
extras["paypalFocusRing"],
|
|
12566
|
+
CARD_FOCUS_RINGS,
|
|
12567
|
+
DEFAULT_BRANDING.epayoutsFocusRing
|
|
12568
|
+
)
|
|
12569
|
+
),
|
|
12570
|
+
epayoutsValidTint: parseBool(
|
|
12571
|
+
extras["epayoutsValidTint"],
|
|
12572
|
+
parseBool(extras["paypalValidTint"], DEFAULT_BRANDING.epayoutsValidTint)
|
|
12573
|
+
),
|
|
12098
12574
|
nomupayFormStyle: pickEnum(
|
|
12099
12575
|
extras["nomupayFormStyle"],
|
|
12100
12576
|
NOMUPAY_FORM_STYLES,
|
|
@@ -12256,6 +12732,13 @@ function encodeBranding(branding, base) {
|
|
|
12256
12732
|
whopMethodIcons: String(branding.whopMethodIcons),
|
|
12257
12733
|
whopSelection: branding.whopSelection,
|
|
12258
12734
|
paypalValidTint: String(branding.paypalValidTint),
|
|
12735
|
+
epayoutsCardLayout: branding.epayoutsCardLayout,
|
|
12736
|
+
epayoutsLabelStyle: branding.epayoutsLabelStyle,
|
|
12737
|
+
epayoutsFieldChrome: branding.epayoutsFieldChrome,
|
|
12738
|
+
epayoutsFieldFontSize: branding.epayoutsFieldFontSize,
|
|
12739
|
+
epayoutsFieldWeight: branding.epayoutsFieldWeight,
|
|
12740
|
+
epayoutsFocusRing: branding.epayoutsFocusRing,
|
|
12741
|
+
epayoutsValidTint: String(branding.epayoutsValidTint),
|
|
12259
12742
|
nomupayFormStyle: branding.nomupayFormStyle,
|
|
12260
12743
|
nomupayShowLabels: String(branding.nomupayShowLabels),
|
|
12261
12744
|
nomupayShowPlaceholders: String(branding.nomupayShowPlaceholders),
|
|
@@ -12717,6 +13200,62 @@ function parseImportedBranding(raw) {
|
|
|
12717
13200
|
dflt.whopSelection
|
|
12718
13201
|
),
|
|
12719
13202
|
paypalValidTint: parseBool(root["paypalValidTint"], dflt.paypalValidTint),
|
|
13203
|
+
// A look stored before todos#412 has no e-Payouts keys: the form keeps
|
|
13204
|
+
// the PayPal values it was drawn with until then.
|
|
13205
|
+
epayoutsCardLayout: pickEnum(
|
|
13206
|
+
root["epayoutsCardLayout"],
|
|
13207
|
+
PAYPAL_CARD_LAYOUTS,
|
|
13208
|
+
pickEnum(
|
|
13209
|
+
root["paypalCardLayout"],
|
|
13210
|
+
PAYPAL_CARD_LAYOUTS,
|
|
13211
|
+
dflt.epayoutsCardLayout
|
|
13212
|
+
)
|
|
13213
|
+
),
|
|
13214
|
+
epayoutsLabelStyle: pickEnum(
|
|
13215
|
+
root["epayoutsLabelStyle"],
|
|
13216
|
+
PAYPAL_LABEL_STYLES,
|
|
13217
|
+
pickEnum(
|
|
13218
|
+
root["paypalLabelStyle"],
|
|
13219
|
+
PAYPAL_LABEL_STYLES,
|
|
13220
|
+
dflt.epayoutsLabelStyle
|
|
13221
|
+
)
|
|
13222
|
+
),
|
|
13223
|
+
epayoutsFieldChrome: pickEnum(
|
|
13224
|
+
root["epayoutsFieldChrome"],
|
|
13225
|
+
CARD_FIELD_CHROMES,
|
|
13226
|
+
pickEnum(
|
|
13227
|
+
root["paypalFieldChrome"],
|
|
13228
|
+
CARD_FIELD_CHROMES,
|
|
13229
|
+
dflt.epayoutsFieldChrome
|
|
13230
|
+
)
|
|
13231
|
+
),
|
|
13232
|
+
epayoutsFieldFontSize: pickEnum(
|
|
13233
|
+
root["epayoutsFieldFontSize"],
|
|
13234
|
+
CARD_FIELD_FONT_SIZES,
|
|
13235
|
+
pickEnum(
|
|
13236
|
+
root["paypalFieldFontSize"],
|
|
13237
|
+
CARD_FIELD_FONT_SIZES,
|
|
13238
|
+
dflt.epayoutsFieldFontSize
|
|
13239
|
+
)
|
|
13240
|
+
),
|
|
13241
|
+
epayoutsFieldWeight: pickEnum(
|
|
13242
|
+
root["epayoutsFieldWeight"],
|
|
13243
|
+
CARD_FIELD_WEIGHTS,
|
|
13244
|
+
pickEnum(
|
|
13245
|
+
root["paypalFieldWeight"],
|
|
13246
|
+
CARD_FIELD_WEIGHTS,
|
|
13247
|
+
dflt.epayoutsFieldWeight
|
|
13248
|
+
)
|
|
13249
|
+
),
|
|
13250
|
+
epayoutsFocusRing: pickEnum(
|
|
13251
|
+
root["epayoutsFocusRing"],
|
|
13252
|
+
CARD_FOCUS_RINGS,
|
|
13253
|
+
pickEnum(root["paypalFocusRing"], CARD_FOCUS_RINGS, dflt.epayoutsFocusRing)
|
|
13254
|
+
),
|
|
13255
|
+
epayoutsValidTint: parseBool(
|
|
13256
|
+
root["epayoutsValidTint"],
|
|
13257
|
+
parseBool(root["paypalValidTint"], dflt.epayoutsValidTint)
|
|
13258
|
+
),
|
|
12720
13259
|
nomupayFormStyle: pickEnum(
|
|
12721
13260
|
root["nomupayFormStyle"],
|
|
12722
13261
|
NOMUPAY_FORM_STYLES,
|
|
@@ -14255,6 +14794,8 @@ var encodeNativePanes = encodePanes;
|
|
|
14255
14794
|
InvoiceSettingsResource,
|
|
14256
14795
|
Invoices,
|
|
14257
14796
|
LOCALIZABLE_COPY_FIELDS,
|
|
14797
|
+
Live,
|
|
14798
|
+
LiveEventStream,
|
|
14258
14799
|
MAX_SECTION_LABEL_LENGTH,
|
|
14259
14800
|
MAX_SECTION_ORDER,
|
|
14260
14801
|
METHOD_SECTIONS,
|