@clipwright/core 0.18.0 → 0.20.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/CHANGELOG.md +44 -0
- package/dist/__fixtures__/queue-promises.d.ts +5 -84
- package/dist/__fixtures__/queue-promises.js +7 -84
- package/dist/__fixtures__/queue-promises.js.map +1 -1
- package/dist/account-actors.d.ts +25 -25
- package/dist/account-actors.js +25 -25
- package/dist/account-actors.js.map +1 -1
- package/dist/account.d.ts +4 -10
- package/dist/account.js +6 -12
- package/dist/account.js.map +1 -1
- package/dist/actor-bounds.d.ts +4 -4
- package/dist/actor-bounds.js +4 -4
- package/dist/actor-bounds.js.map +1 -1
- package/dist/actor-qualities.d.ts +3 -3
- package/dist/actor-qualities.js +3 -3
- package/dist/actor-qualities.js.map +1 -1
- package/dist/actors.d.ts +8 -8
- package/dist/actors.js +9 -9
- package/dist/actors.js.map +1 -1
- package/dist/api-failure.d.ts +28 -129
- package/dist/api-failure.js +52 -225
- package/dist/api-failure.js.map +1 -1
- package/dist/aspect.d.ts +26 -96
- package/dist/aspect.js +32 -108
- package/dist/aspect.js.map +1 -1
- package/dist/contract-dispositions.d.ts +42 -167
- package/dist/contract-dispositions.js +54 -184
- package/dist/contract-dispositions.js.map +1 -1
- package/dist/endpoints.d.ts +5 -5
- package/dist/endpoints.js +3 -3
- package/dist/endpoints.js.map +1 -1
- package/dist/errors.d.ts +33 -101
- package/dist/errors.js +42 -108
- package/dist/errors.js.map +1 -1
- package/dist/faceless-cut-style.d.ts +115 -0
- package/dist/faceless-cut-style.js +109 -0
- package/dist/faceless-cut-style.js.map +1 -0
- package/dist/faceless-image-qualification.d.ts +97 -0
- package/dist/faceless-image-qualification.js +145 -0
- package/dist/faceless-image-qualification.js.map +1 -0
- package/dist/faceless-short-61.d.ts +83 -0
- package/dist/faceless-short-61.js +152 -0
- package/dist/faceless-short-61.js.map +1 -0
- package/dist/faceless-storyboard-timing.d.ts +40 -0
- package/dist/faceless-storyboard-timing.js +97 -0
- package/dist/faceless-storyboard-timing.js.map +1 -0
- package/dist/faceless-storyboard-v2-plan.d.ts +3 -0
- package/dist/faceless-storyboard-v2-plan.js +112 -0
- package/dist/faceless-storyboard-v2-plan.js.map +1 -0
- package/dist/faceless-storyboard-v2-timing.d.ts +52 -0
- package/dist/faceless-storyboard-v2-timing.js +136 -0
- package/dist/faceless-storyboard-v2-timing.js.map +1 -0
- package/dist/faceless-storyboard-v2.d.ts +44 -0
- package/dist/faceless-storyboard-v2.js +43 -0
- package/dist/faceless-storyboard-v2.js.map +1 -0
- package/dist/faceless-storyboard.d.ts +55 -0
- package/dist/faceless-storyboard.js +105 -0
- package/dist/faceless-storyboard.js.map +1 -0
- package/dist/idempotency.d.ts +8 -44
- package/dist/idempotency.js +10 -44
- package/dist/idempotency.js.map +1 -1
- package/dist/index.js +21 -25
- package/dist/index.js.map +1 -1
- package/dist/long-form-pricing.d.ts +4 -4
- package/dist/long-form-pricing.js +4 -4
- package/dist/long-form-pricing.js.map +1 -1
- package/dist/long-form-profile.d.ts +2 -2
- package/dist/long-form-profile.js +2 -2
- package/dist/long-form-profile.js.map +1 -1
- package/dist/pacing.d.ts +1 -1
- package/dist/pacing.js +1 -1
- package/dist/pacing.js.map +1 -1
- package/dist/public-endpoints.d.ts +9 -11
- package/dist/public-endpoints.js +11 -13
- package/dist/public-endpoints.js.map +1 -1
- package/dist/rate-limit.d.ts +23 -130
- package/dist/rate-limit.js +27 -132
- package/dist/rate-limit.js.map +1 -1
- package/dist/render-backend.d.ts +30 -145
- package/dist/render-backend.js +4 -27
- package/dist/render-backend.js.map +1 -1
- package/dist/run-preflight.d.ts +4 -4
- package/dist/run-preflight.js +10 -10
- package/dist/run-preflight.js.map +1 -1
- package/dist/run-static-warnings.d.ts +8 -8
- package/dist/run-static-warnings.js +24 -24
- package/dist/run-static-warnings.js.map +1 -1
- package/dist/runs.d.ts +18 -55
- package/dist/runs.js +26 -94
- package/dist/runs.js.map +1 -1
- package/dist/script-integrity.d.ts +6 -7
- package/dist/script-integrity.js +7 -8
- package/dist/script-integrity.js.map +1 -1
- package/dist/semantic-inserts.d.ts +4 -4
- package/dist/semantic-inserts.js +6 -6
- package/dist/semantic-inserts.js.map +1 -1
- package/dist/skills.d.ts +33 -107
- package/dist/skills.js +72 -161
- package/dist/skills.js.map +1 -1
- package/dist/tts-backend.d.ts +13 -42
- package/dist/tts-backend.js +2 -10
- package/dist/tts-backend.js.map +1 -1
- package/dist/uploads.d.ts +4 -4
- package/dist/uploads.js +4 -4
- package/dist/uploads.js.map +1 -1
- package/dist/vendor-response.d.ts +17 -80
- package/dist/vendor-response.js +19 -67
- package/dist/vendor-response.js.map +1 -1
- package/dist/voice-admission.d.ts +5 -5
- package/dist/voice-admission.js +6 -6
- package/dist/voice-admission.js.map +1 -1
- package/dist/voice-catalog-data.d.ts +2 -2
- package/dist/voice-catalog-data.js +2 -2
- package/dist/voice-catalog-data.js.map +1 -1
- package/dist/voice-catalog.d.ts +5 -5
- package/dist/voice-catalog.js +6 -6
- package/dist/voice-catalog.js.map +1 -1
- package/dist/voice-listing.d.ts +4 -4
- package/dist/voice-listing.js +6 -6
- package/dist/voice-listing.js.map +1 -1
- package/dist/voices.d.ts +40 -82
- package/dist/voices.js +56 -99
- package/dist/voices.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Test ceiling, not a claim that this profile has passed live qualification. */
|
|
2
2
|
export const LONG_FORM_QUALIFICATION_MAX_DURATION_SEC = 300;
|
|
3
|
-
/**
|
|
4
|
-
/**
|
|
3
|
+
/** Slot cap of a frozen timeline; MAX_INSERTS is derived from it, so the numbers */
|
|
4
|
+
/** cannot drift. */
|
|
5
5
|
export const RESOLVED_TIMELINE_MAX_SLOTS = 100;
|
|
6
6
|
//# sourceMappingURL=long-form-profile.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"long-form-profile.js","sourceRoot":"","sources":["../src/long-form-profile.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,CAAC,MAAM,wCAAwC,GAAG,GAAG,CAAC;AAE5D,
|
|
1
|
+
{"version":3,"file":"long-form-profile.js","sourceRoot":"","sources":["../src/long-form-profile.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,CAAC,MAAM,wCAAwC,GAAG,GAAG,CAAC;AAE5D,oFAAoF;AACpF,oBAAoB;AACpB,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC"}
|
package/dist/pacing.d.ts
CHANGED
package/dist/pacing.js
CHANGED
package/dist/pacing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pacing.js","sourceRoot":"","sources":["../src/pacing.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"pacing.js","sourceRoot":"","sources":["../src/pacing.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAEtC,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AAC3D,CAAC"}
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
/**
|
|
3
|
-
/**
|
|
1
|
+
/** Public product addresses, one constant for everyone: the client and the landing page */
|
|
2
|
+
/** must name the same address. */
|
|
3
|
+
/** Our own domain; the platform-generated address still answers and is not retired. */
|
|
4
4
|
export declare const PUBLIC_API_BASE_URL = "https://api.clipwright.io";
|
|
5
|
-
/**
|
|
5
|
+
/** The dashboard; paths are appended to it. NOT `APP_ORIGIN`, which comes from the environment. */
|
|
6
6
|
export declare const PUBLIC_APP_BASE_URL = "https://app.clipwright.io";
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
* `--help`, и документация — значит это тоже контракт, а не текст страницы.
|
|
10
|
-
*/
|
|
7
|
+
/** npm packages the product is called through. The landing page, `--help` and docs print */
|
|
8
|
+
/** these names, so they are contract, not page copy. */
|
|
11
9
|
export declare const CLI_PACKAGE = "@clipwright/cli";
|
|
12
10
|
export declare const CLI_BIN = "clipwright";
|
|
13
11
|
export declare const MCP_PACKAGE = "@clipwright/mcp-server";
|
|
14
12
|
export declare const SDK_PACKAGE = "@clipwright/sdk";
|
|
15
|
-
/**
|
|
13
|
+
/** Node major from the client packages' `engines`; the quickstart names it. */
|
|
16
14
|
export declare const NODE_MIN_MAJOR = 20;
|
|
17
|
-
/**
|
|
18
|
-
/**
|
|
15
|
+
/** API address FROM THE ENVIRONMENT, `https:` only: `Authorization: Bearer cw_…` goes there. */
|
|
16
|
+
/** An embedder's programmatic `baseUrl` is left alone; the code's author chooses it. */
|
|
19
17
|
export declare function apiBaseUrlFromEnv(raw: string | undefined): string | undefined;
|
package/dist/public-endpoints.js
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
/**
|
|
2
|
-
/**
|
|
3
|
-
/**
|
|
1
|
+
/** Public product addresses, one constant for everyone: the client and the landing page */
|
|
2
|
+
/** must name the same address. */
|
|
3
|
+
/** Our own domain; the platform-generated address still answers and is not retired. */
|
|
4
4
|
export const PUBLIC_API_BASE_URL = "https://api.clipwright.io";
|
|
5
|
-
/**
|
|
5
|
+
/** The dashboard; paths are appended to it. NOT `APP_ORIGIN`, which comes from the environment. */
|
|
6
6
|
export const PUBLIC_APP_BASE_URL = "https://app.clipwright.io";
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
* `--help`, и документация — значит это тоже контракт, а не текст страницы.
|
|
10
|
-
*/
|
|
7
|
+
/** npm packages the product is called through. The landing page, `--help` and docs print */
|
|
8
|
+
/** these names, so they are contract, not page copy. */
|
|
11
9
|
export const CLI_PACKAGE = "@clipwright/cli";
|
|
12
10
|
export const CLI_BIN = "clipwright";
|
|
13
11
|
export const MCP_PACKAGE = "@clipwright/mcp-server";
|
|
14
12
|
export const SDK_PACKAGE = "@clipwright/sdk";
|
|
15
|
-
/**
|
|
13
|
+
/** Node major from the client packages' `engines`; the quickstart names it. */
|
|
16
14
|
export const NODE_MIN_MAJOR = 20;
|
|
17
|
-
/**
|
|
18
|
-
/**
|
|
15
|
+
/** Loopback names are the only ones allowed `http:`: a local API goes nowhere, and */
|
|
16
|
+
/** requiring a certificate there would forbid development. */
|
|
19
17
|
const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
|
|
20
|
-
/**
|
|
21
|
-
/**
|
|
18
|
+
/** API address FROM THE ENVIRONMENT, `https:` only: `Authorization: Bearer cw_…` goes there. */
|
|
19
|
+
/** An embedder's programmatic `baseUrl` is left alone; the code's author chooses it. */
|
|
22
20
|
export function apiBaseUrlFromEnv(raw) {
|
|
23
21
|
if (raw === undefined || raw === "")
|
|
24
22
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-endpoints.js","sourceRoot":"","sources":["../src/public-endpoints.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"public-endpoints.js","sourceRoot":"","sources":["../src/public-endpoints.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,kCAAkC;AAElC,uFAAuF;AACvF,MAAM,CAAC,MAAM,mBAAmB,GAAG,2BAA2B,CAAC;AAE/D,mGAAmG;AACnG,MAAM,CAAC,MAAM,mBAAmB,GAAG,2BAA2B,CAAC;AAE/D,4FAA4F;AAC5F,wDAAwD;AACxD,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAC7C,MAAM,CAAC,MAAM,OAAO,GAAG,YAAY,CAAC;AACpC,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,CAAC;AACpD,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAE7C,+EAA+E;AAC/E,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AAEjC,sFAAsF;AACtF,8DAA8D;AAC9D,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;AAE3E,gGAAgG;AAChG,wFAAwF;AACxF,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAEtD,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IAC1C,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,GAAG,CAAC;IAE7E,MAAM,IAAI,KAAK,CACb,gEAAgE,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,IAAI;QAC/F,yEAAyE,CAC5E,CAAC;AACJ,CAAC"}
|
package/dist/rate-limit.d.ts
CHANGED
|
@@ -1,96 +1,28 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
/**
|
|
3
|
-
* RATE LIMIT — ФОРМА ОТВЕТА И ИМЕНА ЗАГОЛОВКОВ, ОДНИМ ДОМОМ (US-605).
|
|
4
|
-
*
|
|
5
|
-
* `spec.md` и `docs/03-api.md` объявляли «60 rpm, заголовки
|
|
6
|
-
* `X-RateLimit-Remaining`/`X-RateLimit-Reset`, код `rate_limited` 429» — и в
|
|
7
|
-
* коде не было ничего. Строить это тремя литералами в трёх пакетах значило бы
|
|
8
|
-
* воспроизвести ровно тот разрыв между объявлением и реализацией, ради
|
|
9
|
-
* закрытия которого стори и заведена: имя заголовка, разъехавшееся между
|
|
10
|
-
* сервером и клиентом, не ловится ни компилятором, ни тестом одной стороны.
|
|
11
|
-
*
|
|
12
|
-
* Поэтому здесь лежат И схема тела, И имена заголовков, И числа лимитов.
|
|
13
|
-
* REST, SDK и MCP берут их отсюда; тест `rate-limit.contract.test.ts` в
|
|
14
|
-
* `apps/api` проверяет, что литерала `rate_limited` нет ни в одной из трёх
|
|
15
|
-
* поверхностей (правило проекта №2, блокер 9 внешнего ревью плана).
|
|
16
|
-
*/
|
|
17
|
-
/** Имя заголовка с потолком ведра — сколько запросов в окне разрешено всего. */
|
|
2
|
+
/** Header with the bucket size: how many requests the window allows in total. */
|
|
18
3
|
export declare const RATE_LIMIT_LIMIT_HEADER = "X-RateLimit-Limit";
|
|
19
|
-
/**
|
|
4
|
+
/** How many requests remain in the current window. Zero is a legal value. */
|
|
20
5
|
export declare const RATE_LIMIT_REMAINING_HEADER = "X-RateLimit-Remaining";
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
*
|
|
24
|
-
* ЕДИНИЦА — ДЕЛЬТА, А НЕ UNIX-ВРЕМЯ, и это осознанное расхождение с GitHub.
|
|
25
|
-
* Дельта не зависит от часов клиента: агент на машине с уехавшим временем,
|
|
26
|
-
* вычитая epoch из своего `Date.now()`, ждал бы неверно и упирался бы в лимит
|
|
27
|
-
* повторно. Направление то же, что у черновика IETF (`RateLimit-Reset`), и то
|
|
28
|
-
* же, что у `Retry-After` ниже — две единицы в одном ответе путали бы сильнее,
|
|
29
|
-
* чем расхождение с чужой реализацией.
|
|
30
|
-
*
|
|
31
|
-
* СМЫСЛ ИМЕННО «ВЫРАСТЕТ НА ЕДИНИЦУ», а не «обнулится счётчик»: окно
|
|
32
|
-
* скользящее, и полного обнуления в нём не происходит — запросы выпадают из
|
|
33
|
-
* окна по одному. Для отказа это ровно момент, когда можно повторить.
|
|
34
|
-
*/
|
|
6
|
+
/** SECONDS until the remainder grows by at least one: a delta, not Unix time, so client */
|
|
7
|
+
/** clock skew does not matter, matching `Retry-After`. The window slides; it never resets. */
|
|
35
8
|
export declare const RATE_LIMIT_RESET_HEADER = "X-RateLimit-Reset";
|
|
36
|
-
/**
|
|
9
|
+
/** Standard `Retry-After` (RFC 9110), in seconds. Only on 429. */
|
|
37
10
|
export declare const RETRY_AFTER_HEADER = "Retry-After";
|
|
38
|
-
/**
|
|
11
|
+
/** Window length, shared by both buckets: "per minute" is what is published. */
|
|
39
12
|
export declare const RATE_LIMIT_WINDOW_SECONDS = 60;
|
|
40
|
-
/**
|
|
41
|
-
* ПЛАТНОЕ ВЕДРО — 60 запросов в минуту. Число не выбрано здесь, а взято из
|
|
42
|
-
* объявления (`spec.md`, `docs/03-api.md`): стори закрывает разрыв «объявлено,
|
|
43
|
-
* но не построено», и менять заодно само объявление значило бы закрыть его
|
|
44
|
-
* подгонкой.
|
|
45
|
-
*/
|
|
13
|
+
/** PAID bucket: 60 requests per minute, the published figure. */
|
|
46
14
|
export declare const RATE_LIMIT_PAID_PER_MINUTE = 60;
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
*
|
|
50
|
-
* ПОЧЕМУ ОТДЕЛЬНО. Общее ведро с платным путём отравило бы ШТАТНЫЙ агентный
|
|
51
|
-
* цикл: по ADR-009 клиент поллит `GET /v1/runs/:id` каждые ~5 с, то есть 12
|
|
52
|
-
* запросов в минуту НА РАН. При потолке в три параллельных рана (та же стори)
|
|
53
|
-
* один только поллинг съедает 36 из 60, и агент упирался бы в лимит, ничего не
|
|
54
|
-
* заказывая — отказ там, где нет ни траты, ни нагрузки на вендора.
|
|
55
|
-
*
|
|
56
|
-
* ОТКУДА 300. Пол — те самые 36 плюс `quote` перед каждым запуском и редкий
|
|
57
|
-
* `voices`: около 40 в минуту на аккаунт, работающий на полном потолке
|
|
58
|
-
* параллельности. 300 даёт запас в 7.5 раза (место для ретраев, нескольких
|
|
59
|
-
* агентов на одном аккаунте и более частого поллинга), но остаётся ПОТОЛКОМ:
|
|
60
|
-
* зациклившийся клиент упирается в него на пятой секунде, а не выкачивает
|
|
61
|
-
* базу минутами. Число живёт здесь, а не в переменной окружения, потому что
|
|
62
|
-
* оно часть публичного контракта и объявлено в `docs/03-api.md`.
|
|
63
|
-
*/
|
|
15
|
+
/** FREE bucket: 300 per minute, counted separately so run polling (~12/min per run, three */
|
|
16
|
+
/** runs at once) never starves paid calls. A ceiling: a looping client hits it in seconds. */
|
|
64
17
|
export declare const RATE_LIMIT_FREE_PER_MINUTE = 300;
|
|
65
|
-
/**
|
|
66
|
-
|
|
67
|
-
*
|
|
68
|
-
* Число живёт рядом с лимитом частоты, потому что они считают одно и то же
|
|
69
|
-
* сверху: сколько работы аккаунт может держать у нас в моменте. Из него же
|
|
70
|
-
* выведен пол бесплатного ведра (три рана × 12 опросов в минуту).
|
|
71
|
-
*
|
|
72
|
-
* ПРЕВЫШЕНИЕ СТАВИТ В ОЧЕРЕДЬ, А НЕ ОТВЕРГАЕТ. Четвёртый ран получает 202 и
|
|
73
|
-
* ждёт своей очереди; отказ здесь был бы хуже для агента, чем ожидание, —
|
|
74
|
-
* ему пришлось бы городить собственный планировщик поверх нашего.
|
|
75
|
-
*
|
|
76
|
-
* ЭТОТ ПОТОЛОК ЖИВЁТ ПОД ОБЩИМ ЛИМИТОМ ТАРИФА Trigger.dev, а не вместо него.
|
|
77
|
-
* Числа тарифа и следствие для волны N=50 — в `docs/02-architecture.md`.
|
|
78
|
-
*/
|
|
18
|
+
/** Concurrent renders per account: 3. Excess runs are queued (202), not refused, so agents */
|
|
19
|
+
/** need no scheduler of their own. It sits under the Trigger.dev plan limit, not instead of it. */
|
|
79
20
|
export declare const MAX_CONCURRENT_RENDERS_PER_ACCOUNT = 3;
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
*
|
|
83
|
-
* Тип живёт здесь, а не в `service-core`, ровно потому, что ведро НАЗВАНО в
|
|
84
|
-
* ответе клиенту (сообщение ниже отличает платный лимит от бесплатного).
|
|
85
|
-
* Разъедься строка в счётчике со строкой в сообщении — клиент получал бы
|
|
86
|
-
* совет ждать не того окна.
|
|
87
|
-
*/
|
|
21
|
+
/** The bucket: also the counter axis in the DB and the `bucket` column value. It lives here */
|
|
22
|
+
/** because the client-facing message names it. */
|
|
88
23
|
export type RateLimitScope = "paid" | "free";
|
|
89
|
-
/**
|
|
90
|
-
|
|
91
|
-
* денежных отказов в `errors.ts`: у ответа об ошибке один конверт, и всё, что
|
|
92
|
-
* объясняет отказ, лежит в нём.
|
|
93
|
-
*/
|
|
24
|
+
/** 429 body. The numbers sit INSIDE `error`, like the money refusals in `errors.ts`: an */
|
|
25
|
+
/** error response has one envelope. */
|
|
94
26
|
export declare const rateLimitedError: z.ZodObject<{
|
|
95
27
|
error: z.ZodObject<{
|
|
96
28
|
code: z.ZodLiteral<"rate_limited">;
|
|
@@ -101,65 +33,26 @@ export declare const rateLimitedError: z.ZodObject<{
|
|
|
101
33
|
}, z.core.$strip>;
|
|
102
34
|
}, z.core.$strip>;
|
|
103
35
|
export type RateLimitedError = z.infer<typeof rateLimitedError>;
|
|
104
|
-
/**
|
|
105
|
-
|
|
106
|
-
*
|
|
107
|
-
* Формулировка живёт ЗДЕСЬ, а не в мидлваре, по той же причине, что и форма:
|
|
108
|
-
* вёдер два, и объяснять отказ они обязаны одинаково. Сообщение НАЗЫВАЕТ
|
|
109
|
-
* ведро — иначе агент, упершийся в платный лимит, не отличит его от
|
|
110
|
-
* бесплатного и остановит поллинг уже принятых ранов.
|
|
111
|
-
*/
|
|
36
|
+
/** Builds the "too many requests" body. The message NAMES the bucket, so an agent hitting */
|
|
37
|
+
/** the paid limit does not stop polling runs it already started. */
|
|
112
38
|
export declare function rateLimitedBody(args: {
|
|
113
39
|
limit: number;
|
|
114
40
|
windowSeconds: number;
|
|
115
41
|
retryAfterSeconds: number;
|
|
116
42
|
scope: RateLimitScope;
|
|
117
|
-
/**
|
|
118
|
-
|
|
119
|
-
* ведро само по себе не различает платный маршрут и любой неизвестный путь,
|
|
120
|
-
* который попадает туда же по безопасному дефолту.
|
|
121
|
-
*
|
|
122
|
-
* Нужен ради правдивости совета (внешнее ревью, круг 5): предупреждение
|
|
123
|
-
* «новый ключ может запустить ВТОРОЙ платный рендер» осмысленно только там,
|
|
124
|
-
* где рендер вообще бывает; на опечатке в пути или неподдержанном методе оно
|
|
125
|
-
* говорит о невозможном. По умолчанию `false` — молчим, пока не сказано
|
|
126
|
-
* обратное.
|
|
127
|
-
*
|
|
128
|
-
* ИМЯ ГОВОРИТ «АДРЕСОВАН», А НЕ «ЗАПУСТИТ», И ЭТО ТОЧНОЕ СЛОВО (круг 6).
|
|
129
|
-
* Знать, дошёл бы запрос до создания рана, мидлвара не может: битое тело,
|
|
130
|
-
* отклонённое поле, конфликт формата, опущенный килсвитч и нехватка кредитов
|
|
131
|
-
* отбиваются УЖЕ В ОБРАБОТЧИКЕ, то есть после лимита. Чтобы это выяснить,
|
|
132
|
-
* пришлось бы выполнить работу обработчика до решения о лимите — ровно ту
|
|
133
|
-
* работу, ради недопущения которой лимит и стоит впереди. Поэтому доступный
|
|
134
|
-
* факт один: «запрос шёл на платный маршрут», и обещание сформулировано в
|
|
135
|
-
* сослагательном («может»), а не в изъявительном наклонении.
|
|
136
|
-
*/
|
|
43
|
+
/** Whether the refused request was ADDRESSED to run creation; only the caller knows. The */
|
|
44
|
+
/** "second paid render" advice appears only then. "Addressed", since later checks may still refuse. */
|
|
137
45
|
targetsRunCreation?: boolean;
|
|
138
46
|
}): RateLimitedError;
|
|
139
|
-
/**
|
|
140
|
-
|
|
141
|
-
* подтверждения).
|
|
142
|
-
*
|
|
143
|
-
* ЖИВЁТ ЗДЕСЬ, А НЕ В МИДЛВАРЕ, ПО ПРАВИЛУ ПРОЕКТА №2 — и это не формальность:
|
|
144
|
-
* литерал `rate_limited`, собранный на месте, поймал сторож
|
|
145
|
-
* `rate-limit.single-source.test.ts` в тот же прогон. Форма 429 у продукта одна,
|
|
146
|
-
* потому что разбирают её клиентские пакеты одной схемой (`rateLimitedError`):
|
|
147
|
-
* тело без любого из трёх чисел не пройдёт разбор вовсе, и агент получит
|
|
148
|
-
* «неизвестный отказ» вместо «подожди столько секунд».
|
|
149
|
-
*
|
|
150
|
-
* ОТЛИЧИЕ ОТ `rateLimitedBody` — ТОЛЬКО СООБЩЕНИЕ, и различать их обязательно.
|
|
151
|
-
* Тот отказ адресован ДЕЙСТВУЮЩЕМУ клиенту и говорит про ведро аккаунта,
|
|
152
|
-
* идемпотентность и второй платный рендер. Этот приходит тому, кто предъявил
|
|
153
|
-
* НЕработающий ключ: ни аккаунта, ни рана у него нет, и совет про
|
|
154
|
-
* `Idempotency-Key` был бы разговором о невозможном.
|
|
155
|
-
*/
|
|
47
|
+
/** "Too many failed authentication attempts" in the same 429 shape, so clients parse it with */
|
|
48
|
+
/** one schema. Only the message differs: the caller has no account, so no idempotency advice. */
|
|
156
49
|
export declare function authThrottledBody(args: {
|
|
157
50
|
limit: number;
|
|
158
51
|
windowSeconds: number;
|
|
159
52
|
retryAfterSeconds: number;
|
|
160
53
|
}): RateLimitedError;
|
|
161
|
-
/**
|
|
162
|
-
/**
|
|
54
|
+
/** Per-account `create_actor` limits over a sliding day. Creations count runs of any */
|
|
55
|
+
/** outcome; refusals and unusable portraits count worker events. */
|
|
163
56
|
export declare const ACTOR_LIMIT_WINDOW_SECONDS = 86400;
|
|
164
57
|
export declare const ACTOR_LIMIT_KINDS: readonly ["creations", "prompt_refusals", "unusable_portraits"];
|
|
165
58
|
export type ActorLimitKind = (typeof ACTOR_LIMIT_KINDS)[number];
|
package/dist/rate-limit.js
CHANGED
|
@@ -1,138 +1,48 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* `spec.md` и `docs/03-api.md` объявляли «60 rpm, заголовки
|
|
6
|
-
* `X-RateLimit-Remaining`/`X-RateLimit-Reset`, код `rate_limited` 429» — и в
|
|
7
|
-
* коде не было ничего. Строить это тремя литералами в трёх пакетах значило бы
|
|
8
|
-
* воспроизвести ровно тот разрыв между объявлением и реализацией, ради
|
|
9
|
-
* закрытия которого стори и заведена: имя заголовка, разъехавшееся между
|
|
10
|
-
* сервером и клиентом, не ловится ни компилятором, ни тестом одной стороны.
|
|
11
|
-
*
|
|
12
|
-
* Поэтому здесь лежат И схема тела, И имена заголовков, И числа лимитов.
|
|
13
|
-
* REST, SDK и MCP берут их отсюда; тест `rate-limit.contract.test.ts` в
|
|
14
|
-
* `apps/api` проверяет, что литерала `rate_limited` нет ни в одной из трёх
|
|
15
|
-
* поверхностей (правило проекта №2, блокер 9 внешнего ревью плана).
|
|
16
|
-
*/
|
|
17
|
-
/** Имя заголовка с потолком ведра — сколько запросов в окне разрешено всего. */
|
|
2
|
+
// Rate-limit body shape, header names and limits in one home: REST, SDK and MCP take them
|
|
3
|
+
// from here, since a header name drifting between server and client is caught by neither side.
|
|
4
|
+
/** Header with the bucket size: how many requests the window allows in total. */
|
|
18
5
|
export const RATE_LIMIT_LIMIT_HEADER = "X-RateLimit-Limit";
|
|
19
|
-
/**
|
|
6
|
+
/** How many requests remain in the current window. Zero is a legal value. */
|
|
20
7
|
export const RATE_LIMIT_REMAINING_HEADER = "X-RateLimit-Remaining";
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
*
|
|
24
|
-
* ЕДИНИЦА — ДЕЛЬТА, А НЕ UNIX-ВРЕМЯ, и это осознанное расхождение с GitHub.
|
|
25
|
-
* Дельта не зависит от часов клиента: агент на машине с уехавшим временем,
|
|
26
|
-
* вычитая epoch из своего `Date.now()`, ждал бы неверно и упирался бы в лимит
|
|
27
|
-
* повторно. Направление то же, что у черновика IETF (`RateLimit-Reset`), и то
|
|
28
|
-
* же, что у `Retry-After` ниже — две единицы в одном ответе путали бы сильнее,
|
|
29
|
-
* чем расхождение с чужой реализацией.
|
|
30
|
-
*
|
|
31
|
-
* СМЫСЛ ИМЕННО «ВЫРАСТЕТ НА ЕДИНИЦУ», а не «обнулится счётчик»: окно
|
|
32
|
-
* скользящее, и полного обнуления в нём не происходит — запросы выпадают из
|
|
33
|
-
* окна по одному. Для отказа это ровно момент, когда можно повторить.
|
|
34
|
-
*/
|
|
8
|
+
/** SECONDS until the remainder grows by at least one: a delta, not Unix time, so client */
|
|
9
|
+
/** clock skew does not matter, matching `Retry-After`. The window slides; it never resets. */
|
|
35
10
|
export const RATE_LIMIT_RESET_HEADER = "X-RateLimit-Reset";
|
|
36
|
-
/**
|
|
11
|
+
/** Standard `Retry-After` (RFC 9110), in seconds. Only on 429. */
|
|
37
12
|
export const RETRY_AFTER_HEADER = "Retry-After";
|
|
38
|
-
/**
|
|
13
|
+
/** Window length, shared by both buckets: "per minute" is what is published. */
|
|
39
14
|
export const RATE_LIMIT_WINDOW_SECONDS = 60;
|
|
40
|
-
/**
|
|
41
|
-
* ПЛАТНОЕ ВЕДРО — 60 запросов в минуту. Число не выбрано здесь, а взято из
|
|
42
|
-
* объявления (`spec.md`, `docs/03-api.md`): стори закрывает разрыв «объявлено,
|
|
43
|
-
* но не построено», и менять заодно само объявление значило бы закрыть его
|
|
44
|
-
* подгонкой.
|
|
45
|
-
*/
|
|
15
|
+
/** PAID bucket: 60 requests per minute, the published figure. */
|
|
46
16
|
export const RATE_LIMIT_PAID_PER_MINUTE = 60;
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
*
|
|
50
|
-
* ПОЧЕМУ ОТДЕЛЬНО. Общее ведро с платным путём отравило бы ШТАТНЫЙ агентный
|
|
51
|
-
* цикл: по ADR-009 клиент поллит `GET /v1/runs/:id` каждые ~5 с, то есть 12
|
|
52
|
-
* запросов в минуту НА РАН. При потолке в три параллельных рана (та же стори)
|
|
53
|
-
* один только поллинг съедает 36 из 60, и агент упирался бы в лимит, ничего не
|
|
54
|
-
* заказывая — отказ там, где нет ни траты, ни нагрузки на вендора.
|
|
55
|
-
*
|
|
56
|
-
* ОТКУДА 300. Пол — те самые 36 плюс `quote` перед каждым запуском и редкий
|
|
57
|
-
* `voices`: около 40 в минуту на аккаунт, работающий на полном потолке
|
|
58
|
-
* параллельности. 300 даёт запас в 7.5 раза (место для ретраев, нескольких
|
|
59
|
-
* агентов на одном аккаунте и более частого поллинга), но остаётся ПОТОЛКОМ:
|
|
60
|
-
* зациклившийся клиент упирается в него на пятой секунде, а не выкачивает
|
|
61
|
-
* базу минутами. Число живёт здесь, а не в переменной окружения, потому что
|
|
62
|
-
* оно часть публичного контракта и объявлено в `docs/03-api.md`.
|
|
63
|
-
*/
|
|
17
|
+
/** FREE bucket: 300 per minute, counted separately so run polling (~12/min per run, three */
|
|
18
|
+
/** runs at once) never starves paid calls. A ceiling: a looping client hits it in seconds. */
|
|
64
19
|
export const RATE_LIMIT_FREE_PER_MINUTE = 300;
|
|
65
|
-
/**
|
|
66
|
-
|
|
67
|
-
*
|
|
68
|
-
* Число живёт рядом с лимитом частоты, потому что они считают одно и то же
|
|
69
|
-
* сверху: сколько работы аккаунт может держать у нас в моменте. Из него же
|
|
70
|
-
* выведен пол бесплатного ведра (три рана × 12 опросов в минуту).
|
|
71
|
-
*
|
|
72
|
-
* ПРЕВЫШЕНИЕ СТАВИТ В ОЧЕРЕДЬ, А НЕ ОТВЕРГАЕТ. Четвёртый ран получает 202 и
|
|
73
|
-
* ждёт своей очереди; отказ здесь был бы хуже для агента, чем ожидание, —
|
|
74
|
-
* ему пришлось бы городить собственный планировщик поверх нашего.
|
|
75
|
-
*
|
|
76
|
-
* ЭТОТ ПОТОЛОК ЖИВЁТ ПОД ОБЩИМ ЛИМИТОМ ТАРИФА Trigger.dev, а не вместо него.
|
|
77
|
-
* Числа тарифа и следствие для волны N=50 — в `docs/02-architecture.md`.
|
|
78
|
-
*/
|
|
20
|
+
/** Concurrent renders per account: 3. Excess runs are queued (202), not refused, so agents */
|
|
21
|
+
/** need no scheduler of their own. It sits under the Trigger.dev plan limit, not instead of it. */
|
|
79
22
|
export const MAX_CONCURRENT_RENDERS_PER_ACCOUNT = 3;
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
* денежных отказов в `errors.ts`: у ответа об ошибке один конверт, и всё, что
|
|
83
|
-
* объясняет отказ, лежит в нём.
|
|
84
|
-
*/
|
|
23
|
+
/** 429 body. The numbers sit INSIDE `error`, like the money refusals in `errors.ts`: an */
|
|
24
|
+
/** error response has one envelope. */
|
|
85
25
|
export const rateLimitedError = z.object({
|
|
86
26
|
error: z.object({
|
|
87
27
|
code: z.literal("rate_limited"),
|
|
88
28
|
message: z.string().min(1),
|
|
89
|
-
/**
|
|
29
|
+
/** Size of the bucket the request fell into. */
|
|
90
30
|
limit: z.number().int().positive(),
|
|
91
|
-
/**
|
|
31
|
+
/** Window length in seconds; `limit` means nothing without it. */
|
|
92
32
|
window_seconds: z.number().int().positive(),
|
|
93
|
-
/**
|
|
33
|
+
/** Seconds until a retry. Matches `Retry-After`. */
|
|
94
34
|
retry_after_seconds: z.number().int().positive(),
|
|
95
35
|
}),
|
|
96
36
|
});
|
|
97
|
-
/**
|
|
98
|
-
|
|
99
|
-
*
|
|
100
|
-
* Формулировка живёт ЗДЕСЬ, а не в мидлваре, по той же причине, что и форма:
|
|
101
|
-
* вёдер два, и объяснять отказ они обязаны одинаково. Сообщение НАЗЫВАЕТ
|
|
102
|
-
* ведро — иначе агент, упершийся в платный лимит, не отличит его от
|
|
103
|
-
* бесплатного и остановит поллинг уже принятых ранов.
|
|
104
|
-
*/
|
|
37
|
+
/** Builds the "too many requests" body. The message NAMES the bucket, so an agent hitting */
|
|
38
|
+
/** the paid limit does not stop polling runs it already started. */
|
|
105
39
|
export function rateLimitedBody(args) {
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
// Первая редакция дописывала «no run was created» к ОБОИМ отказам, и это была
|
|
109
|
-
// ложь дважды.
|
|
110
|
-
//
|
|
111
|
-
// НА БЕСПЛАТНОМ ВЕДРЕ: агент, опрашивающий статус уже ЗАПУЩЕННОГО рана,
|
|
112
|
-
// получал бы 429 с уверением, что рана нет, — и мог бы бросить работу, за
|
|
113
|
-
// которую уже заплачено. Ту же работу защищает и решение пропускать
|
|
114
|
-
// бесплатные пути при отказе счётчика.
|
|
115
|
-
//
|
|
116
|
-
// НА ПЛАТНОМ: лимит стоит ПЕРЕД обработчиком, поэтому 429 получает и ПОВТОР
|
|
117
|
-
// с уже занятым `Idempotency-Key` — запрос, за которым ран существует. «No
|
|
118
|
-
// run was created» толкает агента взять новый ключ, а новый ключ есть второй
|
|
119
|
-
// платный рендер. Поэтому платный хвост больше ничего не утверждает о
|
|
120
|
-
// существовании рана и прямо велит повторить С ТЕМ ЖЕ ключом: это верно и
|
|
121
|
-
// для первого запроса (там повтор просто создаст ран), и для повтора.
|
|
122
|
-
// ОПИСАНИЕ ВЕДРА ТОЖЕ ОБЯЗАНО БЫТЬ ВЕРНЫМ (внешнее ревью, круг 4). В платное
|
|
123
|
-
// ведро по построению попадает не только создание рана, но и любой
|
|
124
|
-
// неизвестный путь под авторизованными префиксами — так выбран безопасный
|
|
125
|
-
// дефолт. Формулировка «starting runs» описывала бы клиенту не тот отказ.
|
|
40
|
+
// The paid bucket also catches any unknown authenticated path, and the text says so.
|
|
126
41
|
const surface = args.scope === "paid"
|
|
127
42
|
? "paid requests (starting a run, and any unrecognised authenticated path)"
|
|
128
43
|
: "free requests (quotes, voices, run status, account)";
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
// Круг 4 снял безусловность: 429 получает и запрос, который ключа не
|
|
132
|
-
// присылал. Круг 5 снял вторую неточность — предупреждение о «втором платном
|
|
133
|
-
// рендере» уходило и на опечатку в пути, и на неподдержанный метод, где
|
|
134
|
-
// никакой ключ ничего не отрендерит. Теперь его печатает только запуск рана,
|
|
135
|
-
// и `targetsRunCreation` приходит от мидлвары — она единственная знает маршрут.
|
|
44
|
+
// No claim that no run exists: the paid limit precedes the handler, so a retry may own
|
|
45
|
+
// a run. Key advice only for run creation, which only the middleware can tell.
|
|
136
46
|
const tail = args.scope === "free"
|
|
137
47
|
? "nothing was charged; runs already started keep going and stay retrievable."
|
|
138
48
|
: args.targetsRunCreation === true
|
|
@@ -149,23 +59,8 @@ export function rateLimitedBody(args) {
|
|
|
149
59
|
},
|
|
150
60
|
});
|
|
151
61
|
}
|
|
152
|
-
/**
|
|
153
|
-
|
|
154
|
-
* подтверждения).
|
|
155
|
-
*
|
|
156
|
-
* ЖИВЁТ ЗДЕСЬ, А НЕ В МИДЛВАРЕ, ПО ПРАВИЛУ ПРОЕКТА №2 — и это не формальность:
|
|
157
|
-
* литерал `rate_limited`, собранный на месте, поймал сторож
|
|
158
|
-
* `rate-limit.single-source.test.ts` в тот же прогон. Форма 429 у продукта одна,
|
|
159
|
-
* потому что разбирают её клиентские пакеты одной схемой (`rateLimitedError`):
|
|
160
|
-
* тело без любого из трёх чисел не пройдёт разбор вовсе, и агент получит
|
|
161
|
-
* «неизвестный отказ» вместо «подожди столько секунд».
|
|
162
|
-
*
|
|
163
|
-
* ОТЛИЧИЕ ОТ `rateLimitedBody` — ТОЛЬКО СООБЩЕНИЕ, и различать их обязательно.
|
|
164
|
-
* Тот отказ адресован ДЕЙСТВУЮЩЕМУ клиенту и говорит про ведро аккаунта,
|
|
165
|
-
* идемпотентность и второй платный рендер. Этот приходит тому, кто предъявил
|
|
166
|
-
* НЕработающий ключ: ни аккаунта, ни рана у него нет, и совет про
|
|
167
|
-
* `Idempotency-Key` был бы разговором о невозможном.
|
|
168
|
-
*/
|
|
62
|
+
/** "Too many failed authentication attempts" in the same 429 shape, so clients parse it with */
|
|
63
|
+
/** one schema. Only the message differs: the caller has no account, so no idempotency advice. */
|
|
169
64
|
export function authThrottledBody(args) {
|
|
170
65
|
return rateLimitedError.parse({
|
|
171
66
|
error: {
|
|
@@ -179,8 +74,8 @@ export function authThrottledBody(args) {
|
|
|
179
74
|
},
|
|
180
75
|
});
|
|
181
76
|
}
|
|
182
|
-
/**
|
|
183
|
-
/**
|
|
77
|
+
/** Per-account `create_actor` limits over a sliding day. Creations count runs of any */
|
|
78
|
+
/** outcome; refusals and unusable portraits count worker events. */
|
|
184
79
|
export const ACTOR_LIMIT_WINDOW_SECONDS = 86_400;
|
|
185
80
|
export const ACTOR_LIMIT_KINDS = ["creations", "prompt_refusals", "unusable_portraits"];
|
|
186
81
|
export const ACTOR_LIMITS = {
|
package/dist/rate-limit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"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"}
|