@ganju/utils 0.0.3 → 0.0.4

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.
@@ -519,6 +519,10 @@ export declare const constants: {
519
519
  CUSTOM_CODE_MAX_FILE_PATH: number;
520
520
  CUSTOM_CODE_VERSION_STATUSES: ("draft" | "published" | "archived")[];
521
521
  CUSTOM_CODE_SCRIPT_NAME_PREFIX: string;
522
+ CUSTOM_CODE_SCRIPT_NAME_MAX: number;
523
+ CUSTOM_CODE_UPLOAD_SUFFIX_CHARS: number;
524
+ CUSTOM_CODE_SWEEP_GRACE_MS: number;
525
+ CUSTOM_CODE_SWEEP_MAX_DELETES: number;
522
526
  CUSTOM_CODE_PREVIEW_SCRIPT_SUFFIX: string;
523
527
  CUSTOM_CODE_PREVIEW_TOKEN_TTL_MS: number;
524
528
  CUSTOM_CODE_TEST_TIMEOUT_MS: number;
@@ -560,8 +564,8 @@ export declare const constants: {
560
564
  CUSTOM_CODE_BROKER_SERVICE_ENV: string;
561
565
  CUSTOM_CODE_COMPATIBILITY_DATE: string;
562
566
  CUSTOM_CODE_SCRIPT_CPU_MS: number;
563
- CUSTOM_CODE_SMOKE_TIMEOUT_MS: number;
564
- CUSTOM_CODE_SMOKE_INTERVAL_MS: number;
567
+ CUSTOM_CODE_REGISTER_TIMEOUT_MS: number;
568
+ CUSTOM_CODE_REGISTER_INTERVAL_MS: number;
565
569
  CUSTOM_CODE_MAX_LOGS: number;
566
570
  CUSTOM_CODE_MAX_LOG_LENGTH: number;
567
571
  CUSTOM_CODE_SEND_FILE_TARGET_GMAIL: "gmail";
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AA6JA,QAAA,MAAM,yBAAyB,EAAiB,UAAU,CAAC;AAC3D,QAAA,MAAM,+BAA+B,EAAuB,gBAAgB,CAAC;AAC7E,QAAA,MAAM,8BAA8B,EAAsB,eAAe,CAAC;AAC1E,QAAA,MAAM,wBAAwB,EAAgB,SAAS,CAAC;AAuCxD,QAAA,MAAM,sBAAsB,EAAiB,UAAU,CAAC;AACxD,QAAA,MAAM,4BAA4B,EAAuB,gBAAgB,CAAC;AAC1E,QAAA,MAAM,oBAAoB,EAAe,QAAQ,CAAC;AAClD,QAAA,MAAM,oBAAoB,EAAe,QAAQ,CAAC;AAmYlD,QAAA,MAAM,sBAAsB,EAAkB,WAAW,CAAC;AAC1D,QAAA,MAAM,mBAAmB,EAAe,QAAQ,CAAC;AAGjD,QAAA,MAAM,mBAAmB,EAAe,QAAQ,CAAC;AAkTjD,MAAM,MAAM,mBAAmB,GAC3B;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACD;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACD;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAg6BpE,UAAU,UAAU;IAElB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAMjC,sBAAsB,EAAE,MAAM,CAAC;IAM/B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;IAKnB,eAAe,EAAE,OAAO,CAAC;IAOzB,gBAAgB,EAAE,OAAO,CAAC;IAK1B,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;IAG3C,gBAAgB,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAqKD,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eA51DhB,OAAO,yBAAyB,GAChC,OAAO,+BAA+B,GACtC,OAAO,8BAA8B,GACrC,OAAO,wBAAwB;eAC5B,MAAM;;;;;;;;;;;;;;;;;;eAsCT,OAAO,sBAAsB,GAC7B,OAAO,4BAA4B,GACnC,OAAO,oBAAoB,GAC3B,OAAO,oBAAoB;eACxB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6YT,OAAO,mBAAmB,GAC1B,OAAO,mBAAmB,GAC1B,OAAO,sBAAsB;eAC1B,MAAM;eACN,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eA6NwB,MAAM,GAAG,MAAM;cAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuuDnE,CAAC"}
package/dist/constants.js CHANGED
@@ -1041,9 +1041,36 @@ const CUSTOM_CODE_MAIN_MODULE = 'index.js';
1041
1041
  // object read on every deploy.
1042
1042
  const CUSTOM_CODE_MAX_FILES = 25;
1043
1043
  const CUSTOM_CODE_MAX_FILE_PATH = 100;
1044
- // WfP script name: `artifact_<artifactId>`. The id, never the slug — slugs are
1045
- // user-editable and a rename would orphan the deployed script.
1044
+ // WfP script name: `artifact_<artifactId>_<upload>`. The id, never the slug —
1045
+ // slugs are user-editable and a rename would orphan the deployed script.
1046
+ //
1047
+ // The trailing segment is minted per upload rather than derived from anything,
1048
+ // which is the whole point: uploading over a name that already exists is not
1049
+ // read-your-writes, so a deploy that replaces a script can serve the previous
1050
+ // edition for up to half a minute. A name nothing has ever used cannot, and
1051
+ // costs nothing to mint. Everything a publish used to do to survive that race —
1052
+ // waiting on an edition marker, refusing with a 503, putting the previous bundle
1053
+ // back when validation failed — went with the reuse that caused it.
1046
1054
  const CUSTOM_CODE_SCRIPT_NAME_PREFIX = 'artifact_';
1055
+ // Worker names cap at 63 characters, and `artifact_<uuid>` already spends 45.
1056
+ // That leaves 17 for a separator and a suffix, so a second uuid does not fit and
1057
+ // neither does a hex-32 digest. Twelve hex characters is 48 bits against a
1058
+ // namespace holding at most a few hundred names for any one artifact — not a
1059
+ // collision worth checking for, and an upload to a name in use would fail loudly
1060
+ // rather than quietly serve the wrong code.
1061
+ const CUSTOM_CODE_SCRIPT_NAME_MAX = 63;
1062
+ const CUSTOM_CODE_UPLOAD_SUFFIX_CHARS = 12;
1063
+ // How long a superseded script stays in the namespace before the hourly sweep
1064
+ // may collect it.
1065
+ //
1066
+ // Deleting at publish time would race the thing it deletes: a tool call that
1067
+ // resolved the old pointer a moment earlier is still in flight, and the pointer
1068
+ // moving does not recall it. An hour is far longer than any call can take, and
1069
+ // the wait costs $0.02 per script per month against an allowance of 1,000.
1070
+ const CUSTOM_CODE_SWEEP_GRACE_MS = 60 * 60 * 1_000;
1071
+ // Deletes per sweep. A backlog drains over several hourly runs rather than
1072
+ // making one run unbounded — the same shape the retention purge uses.
1073
+ const CUSTOM_CODE_SWEEP_MAX_DELETES = 200;
1047
1074
  // A second script per artifact, `artifact_<id>_preview`, that the Test panel
1048
1075
  // deploys a draft into and calls.
1049
1076
  //
@@ -1228,15 +1255,17 @@ const CUSTOM_CODE_COMPATIBILITY_DATE = '2025-11-17';
1228
1255
  // tighter than our own workers' 30s — this is the technical cap that bounds
1229
1256
  // what one adversarial call can cost us, so an infinite loop in a customer's
1230
1257
  // tool is billed as five seconds rather than as whatever it wanted.
1231
- // How long publish waits for the edition it just uploaded to be the one the
1232
- // dispatcher answers with, and how often it asks.
1258
+ // How long a deploy waits for a freshly minted script name to become
1259
+ // dispatchable, and how often it asks.
1233
1260
  //
1234
- // Bounded rather than open-ended because this runs inside the publish request:
1235
- // past this, publishing would be a request nobody waits out. Exceeding it is
1236
- // reported as "try again" rather than published, which is the safe direction
1237
- // the alternative is advertising tools backed by a script that is not there yet.
1238
- const CUSTOM_CODE_SMOKE_TIMEOUT_MS = 20_000;
1239
- const CUSTOM_CODE_SMOKE_INTERVAL_MS = 1_000;
1261
+ // Every upload goes to a name that has never been used, which is
1262
+ // read-your-writes: ~2s end to end against the deployed namespace, against the
1263
+ // 20-41s a replacement could take. So this bounds how long a brand-new name
1264
+ // takes to register, never how long an old edition takes to stop answering
1265
+ // there is no old edition. It is short for that reason, and a script that
1266
+ // answers with the wrong edition now fails outright instead of being waited on.
1267
+ const CUSTOM_CODE_REGISTER_TIMEOUT_MS = 8_000;
1268
+ const CUSTOM_CODE_REGISTER_INTERVAL_MS = 500;
1240
1269
  const CUSTOM_CODE_SCRIPT_CPU_MS = 5_000;
1241
1270
  // The ctx.log() caps also live in ./sdkConstants — the buffer that enforces them
1242
1271
  // runs inside the isolate.
@@ -2139,6 +2168,10 @@ exports.constants = {
2139
2168
  CUSTOM_CODE_MAX_FILE_PATH,
2140
2169
  CUSTOM_CODE_VERSION_STATUSES,
2141
2170
  CUSTOM_CODE_SCRIPT_NAME_PREFIX,
2171
+ CUSTOM_CODE_SCRIPT_NAME_MAX,
2172
+ CUSTOM_CODE_UPLOAD_SUFFIX_CHARS,
2173
+ CUSTOM_CODE_SWEEP_GRACE_MS,
2174
+ CUSTOM_CODE_SWEEP_MAX_DELETES,
2142
2175
  CUSTOM_CODE_PREVIEW_SCRIPT_SUFFIX,
2143
2176
  CUSTOM_CODE_PREVIEW_TOKEN_TTL_MS,
2144
2177
  CUSTOM_CODE_TEST_TIMEOUT_MS,
@@ -2180,8 +2213,8 @@ exports.constants = {
2180
2213
  CUSTOM_CODE_BROKER_SERVICE_ENV,
2181
2214
  CUSTOM_CODE_COMPATIBILITY_DATE,
2182
2215
  CUSTOM_CODE_SCRIPT_CPU_MS,
2183
- CUSTOM_CODE_SMOKE_TIMEOUT_MS,
2184
- CUSTOM_CODE_SMOKE_INTERVAL_MS,
2216
+ CUSTOM_CODE_REGISTER_TIMEOUT_MS,
2217
+ CUSTOM_CODE_REGISTER_INTERVAL_MS,
2185
2218
  CUSTOM_CODE_MAX_LOGS: sdkConstants_1.CUSTOM_CODE_MAX_LOGS,
2186
2219
  CUSTOM_CODE_MAX_LOG_LENGTH: sdkConstants_1.CUSTOM_CODE_MAX_LOG_LENGTH,
2187
2220
  CUSTOM_CODE_SEND_FILE_TARGET_GMAIL,
@@ -24,18 +24,53 @@ export declare const mintCustomCodeToken: (payload: Omit<CustomCodeTokenPayload,
24
24
  */
25
25
  export declare const verifyCustomCodeToken: (token: string, secret: string, now?: number) => Promise<CustomCodeTokenPayload | null>;
26
26
  /**
27
- * The dispatch-namespace script name for an artifact: `artifact_<id>`.
27
+ * The legacy dispatch-namespace script name for an artifact: `artifact_<id>`.
28
28
  *
29
29
  * The id, never the slug — slugs are user-editable and a rename would orphan the
30
30
  * deployed script while the database still pointed at a live version.
31
+ *
32
+ * Nothing uploads to this name any more; every deploy mints its own. It survives
33
+ * as the fallback for a version published before `script_name` existed, whose
34
+ * bundle really is sitting under this name. Tightening a rule must never stop an
35
+ * already-published version from serving, because that failure is invisible to
36
+ * whoever owns it — the same reason the boot loop still accepts a stored tool key
37
+ * the current catalog no longer offers.
31
38
  */
32
39
  export declare const customCodeScriptName: (artifactId: string) => string;
33
40
  /**
34
- * The script name a test run deploys into: `artifact_<id>_preview`.
41
+ * The legacy preview script name: `artifact_<id>_preview`.
35
42
  *
36
- * A second script rather than a second version of the live one, because a test
37
- * must not be able to disturb what MCP clients are being served and the only
38
- * way to be certain of that is for it to run under a name nothing dispatches to.
43
+ * Kept for the same reason as the one above, and for one more: it is the prefix
44
+ * the sweep matches to recognise a preview script left behind by a test run that
45
+ * did not clean up after itself.
39
46
  */
40
47
  export declare const customCodePreviewScriptName: (artifactId: string) => string;
48
+ /**
49
+ * A dispatch-namespace name no upload has ever used:
50
+ * `artifact_<id>_<12 hex chars>`.
51
+ *
52
+ * Minted rather than derived, and that is the entire design. Uploading over an
53
+ * existing name is not read-your-writes — a replacement can serve the previous
54
+ * edition for tens of seconds — so a deploy that always writes to a new name is
55
+ * correct by construction rather than by waiting to see whether it worked.
56
+ *
57
+ * The suffix deliberately carries no meaning. The two candidates that did are
58
+ * both wrong: the bundle digest collides whenever a deploy reverts to bytes that
59
+ * shipped before, which is exactly what a rollback is, and the version id is one
60
+ * string across every re-upload of a single draft, which is every test run of it.
61
+ *
62
+ * Twelve hex characters is what fits. Worker names cap at 63 and
63
+ * `artifact_<uuid>` spends 45 of them.
64
+ */
65
+ export declare const customCodeUploadName: (artifactId: string) => string;
66
+ /**
67
+ * A preview name no test run has ever used:
68
+ * `artifact_<id>_preview_<12 hex chars>`.
69
+ *
70
+ * The sharper version of the same race. Every test used to deploy over one
71
+ * preview name, so a test could report the run before it — which reads as "my
72
+ * edit did nothing" from the one tool whose whole job is to say what an edit
73
+ * does. Nothing stores this: it is minted, used, and deleted inside one request.
74
+ */
75
+ export declare const customCodePreviewUploadName: (artifactId: string) => string;
41
76
  //# sourceMappingURL=customCodeToken.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"customCodeToken.d.ts","sourceRoot":"","sources":["../src/customCodeToken.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,sBAAsB;IAGrC,CAAC,EAAE,MAAM,CAAC;IACV,UAAU,EAAE,MAAM,CAAC;IAGnB,SAAS,EAAE,MAAM,CAAC;IAIlB,GAAG,EAAE,MAAM,CAAC;IAOZ,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA0BD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,IAAI,CAAC,sBAAsB,EAAE,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,GAAG;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,EACD,QAAQ,MAAM,EACd,WAAU,MAAmB,KAC5B,OAAO,CAAC,MAAM,CAmBhB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,OAAO,CAAC,sBAAsB,GAAG,IAAI,CA+DvC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,YAAY,MAAM,KAAG,MACE,CAAC;AAE7D;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GAAI,YAAY,MAAM,KAAG,MACoB,CAAC"}
1
+ {"version":3,"file":"customCodeToken.d.ts","sourceRoot":"","sources":["../src/customCodeToken.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,sBAAsB;IAGrC,CAAC,EAAE,MAAM,CAAC;IACV,UAAU,EAAE,MAAM,CAAC;IAGnB,SAAS,EAAE,MAAM,CAAC;IAIlB,GAAG,EAAE,MAAM,CAAC;IAOZ,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA0BD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,IAAI,CAAC,sBAAsB,EAAE,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,GAAG;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,EACD,QAAQ,MAAM,EACd,WAAU,MAAmB,KAC5B,OAAO,CAAC,MAAM,CAmBhB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,OAAO,CAAC,sBAAsB,GAAG,IAAI,CA+DvC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,GAAI,YAAY,MAAM,KAAG,MACE,CAAC;AAE7D;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GAAI,YAAY,MAAM,KAAG,MACoB,CAAC;AAEtF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,oBAAoB,GAAI,YAAY,MAAM,KAAG,MACR,CAAC;AAEnD;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,GAAI,YAAY,MAAM,KAAG,MACR,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.customCodePreviewScriptName = exports.customCodeScriptName = exports.verifyCustomCodeToken = exports.mintCustomCodeToken = void 0;
3
+ exports.customCodePreviewUploadName = exports.customCodeUploadName = exports.customCodePreviewScriptName = exports.customCodeScriptName = exports.verifyCustomCodeToken = exports.mintCustomCodeToken = void 0;
4
4
  const base64_1 = require("./base64");
5
5
  const constants_1 = require("./constants");
6
6
  const encoder = new TextEncoder();
@@ -97,19 +97,90 @@ const verifyCustomCodeToken = async (token, secret, now) => {
97
97
  };
98
98
  exports.verifyCustomCodeToken = verifyCustomCodeToken;
99
99
  /**
100
- * The dispatch-namespace script name for an artifact: `artifact_<id>`.
100
+ * The legacy dispatch-namespace script name for an artifact: `artifact_<id>`.
101
101
  *
102
102
  * The id, never the slug — slugs are user-editable and a rename would orphan the
103
103
  * deployed script while the database still pointed at a live version.
104
+ *
105
+ * Nothing uploads to this name any more; every deploy mints its own. It survives
106
+ * as the fallback for a version published before `script_name` existed, whose
107
+ * bundle really is sitting under this name. Tightening a rule must never stop an
108
+ * already-published version from serving, because that failure is invisible to
109
+ * whoever owns it — the same reason the boot loop still accepts a stored tool key
110
+ * the current catalog no longer offers.
104
111
  */
105
112
  const customCodeScriptName = (artifactId) => `${constants_1.constants.CUSTOM_CODE_SCRIPT_NAME_PREFIX}${artifactId}`;
106
113
  exports.customCodeScriptName = customCodeScriptName;
107
114
  /**
108
- * The script name a test run deploys into: `artifact_<id>_preview`.
115
+ * The legacy preview script name: `artifact_<id>_preview`.
109
116
  *
110
- * A second script rather than a second version of the live one, because a test
111
- * must not be able to disturb what MCP clients are being served and the only
112
- * way to be certain of that is for it to run under a name nothing dispatches to.
117
+ * Kept for the same reason as the one above, and for one more: it is the prefix
118
+ * the sweep matches to recognise a preview script left behind by a test run that
119
+ * did not clean up after itself.
113
120
  */
114
121
  const customCodePreviewScriptName = (artifactId) => `${(0, exports.customCodeScriptName)(artifactId)}${constants_1.constants.CUSTOM_CODE_PREVIEW_SCRIPT_SUFFIX}`;
115
122
  exports.customCodePreviewScriptName = customCodePreviewScriptName;
123
+ /**
124
+ * A dispatch-namespace name no upload has ever used:
125
+ * `artifact_<id>_<12 hex chars>`.
126
+ *
127
+ * Minted rather than derived, and that is the entire design. Uploading over an
128
+ * existing name is not read-your-writes — a replacement can serve the previous
129
+ * edition for tens of seconds — so a deploy that always writes to a new name is
130
+ * correct by construction rather than by waiting to see whether it worked.
131
+ *
132
+ * The suffix deliberately carries no meaning. The two candidates that did are
133
+ * both wrong: the bundle digest collides whenever a deploy reverts to bytes that
134
+ * shipped before, which is exactly what a rollback is, and the version id is one
135
+ * string across every re-upload of a single draft, which is every test run of it.
136
+ *
137
+ * Twelve hex characters is what fits. Worker names cap at 63 and
138
+ * `artifact_<uuid>` spends 45 of them.
139
+ */
140
+ const customCodeUploadName = (artifactId) => mintUploadName((0, exports.customCodeScriptName)(artifactId));
141
+ exports.customCodeUploadName = customCodeUploadName;
142
+ /**
143
+ * A preview name no test run has ever used:
144
+ * `artifact_<id>_preview_<12 hex chars>`.
145
+ *
146
+ * The sharper version of the same race. Every test used to deploy over one
147
+ * preview name, so a test could report the run before it — which reads as "my
148
+ * edit did nothing" from the one tool whose whole job is to say what an edit
149
+ * does. Nothing stores this: it is minted, used, and deleted inside one request.
150
+ */
151
+ const customCodePreviewUploadName = (artifactId) => mintUploadName((0, exports.customCodePreviewScriptName)(artifactId));
152
+ exports.customCodePreviewUploadName = customCodePreviewUploadName;
153
+ /**
154
+ * Append `_<hex>` to a base name, spending whatever the 63-character ceiling
155
+ * leaves and no more.
156
+ *
157
+ * The budget is genuinely tight, and the two names spend it differently:
158
+ *
159
+ * | name | base | separator | suffix | total |
160
+ * |---|---|---|---|---|
161
+ * | live | `artifact_<uuid>` = 45 | 1 | 12 | 58 |
162
+ * | preview | + `_preview` = 53 | 1 | 8 | 62 |
163
+ *
164
+ * Twelve hex characters is 48 bits and eight is 32, against a namespace holding
165
+ * a few hundred names for any one artifact — and a preview name lives for the
166
+ * seconds one test run takes. Neither is a collision worth checking for, and an
167
+ * upload to a name already in use fails loudly rather than quietly serving the
168
+ * wrong code, which is the failure that matters.
169
+ *
170
+ * The ceiling is asserted rather than assumed: it is one number away from being
171
+ * silently exceeded by a longer prefix, and a name Cloudflare refuses would
172
+ * surface as a failed publish with nothing explaining why.
173
+ */
174
+ const mintUploadName = (base) => {
175
+ const available = constants_1.constants.CUSTOM_CODE_SCRIPT_NAME_MAX - base.length - 1;
176
+ // Even, because each byte renders as two hex characters.
177
+ const chars = Math.min(constants_1.constants.CUSTOM_CODE_UPLOAD_SUFFIX_CHARS, available) & ~1;
178
+ if (chars < 4) {
179
+ throw new Error(`A dispatch script name based on "${base}" leaves no room for a unique suffix.`);
180
+ }
181
+ const bytes = new Uint8Array(chars / 2);
182
+ crypto.getRandomValues(bytes);
183
+ return `${base}_${Array.from(bytes)
184
+ .map(byte => byte.toString(16).padStart(2, '0'))
185
+ .join('')}`;
186
+ };
package/dist/index.d.ts CHANGED
@@ -2206,6 +2206,10 @@ export declare const utils: {
2206
2206
  CUSTOM_CODE_MAX_FILE_PATH: number;
2207
2207
  CUSTOM_CODE_VERSION_STATUSES: ("draft" | "published" | "archived")[];
2208
2208
  CUSTOM_CODE_SCRIPT_NAME_PREFIX: string;
2209
+ CUSTOM_CODE_SCRIPT_NAME_MAX: number;
2210
+ CUSTOM_CODE_UPLOAD_SUFFIX_CHARS: number;
2211
+ CUSTOM_CODE_SWEEP_GRACE_MS: number;
2212
+ CUSTOM_CODE_SWEEP_MAX_DELETES: number;
2209
2213
  CUSTOM_CODE_PREVIEW_SCRIPT_SUFFIX: string;
2210
2214
  CUSTOM_CODE_PREVIEW_TOKEN_TTL_MS: number;
2211
2215
  CUSTOM_CODE_TEST_TIMEOUT_MS: number;
@@ -2247,8 +2251,8 @@ export declare const utils: {
2247
2251
  CUSTOM_CODE_BROKER_SERVICE_ENV: string;
2248
2252
  CUSTOM_CODE_COMPATIBILITY_DATE: string;
2249
2253
  CUSTOM_CODE_SCRIPT_CPU_MS: number;
2250
- CUSTOM_CODE_SMOKE_TIMEOUT_MS: number;
2251
- CUSTOM_CODE_SMOKE_INTERVAL_MS: number;
2254
+ CUSTOM_CODE_REGISTER_TIMEOUT_MS: number;
2255
+ CUSTOM_CODE_REGISTER_INTERVAL_MS: number;
2252
2256
  CUSTOM_CODE_MAX_LOGS: number;
2253
2257
  CUSTOM_CODE_MAX_LOG_LENGTH: number;
2254
2258
  CUSTOM_CODE_SEND_FILE_TARGET_GMAIL: "gmail";
@@ -2353,6 +2357,8 @@ export declare const utils: {
2353
2357
  verifyCustomCodeToken: (token: string, secret: string, now?: number) => Promise<CustomCodeTokenPayload | null>;
2354
2358
  customCodeScriptName: (artifactId: string) => string;
2355
2359
  customCodePreviewScriptName: (artifactId: string) => string;
2360
+ customCodeUploadName: (artifactId: string) => string;
2361
+ customCodePreviewUploadName: (artifactId: string) => string;
2356
2362
  oauthProviders: Record<string, OAuthProviderConfig>;
2357
2363
  resolveAttachment: (resource: AttachmentResource, readObject: (key: string) => Promise<ArrayBuffer | null>, verb?: "attach" | "upload") => Promise<ResolveAttachmentResult>;
2358
2364
  isExposedResource: (resource: ExposableResource) => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAlGhB,CAAC;;;;;;;;;;;;;;;;;;;;;;;kBAjHkB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA0DF,CAAC;oBAEd,CAAC;;;;aA0BkB,CAAC;mBAA8B,CAAC;WACvC,CAAC;gBACf,CAAC;gBAA4B,CAAA;;;mBAmBK,CAAC;oBACtC,CAAC;;;;;;;;;;;;;;;kBA1DmB,CAAC;;;;;;;sBAqCR,CAAC;;;;;;;;;CAuOf,CAAC;AAEF,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,YAAY,EACZ,OAAO,EACP,mBAAmB,EACnB,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,8BAA8B,EAC9B,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EACjC,kBAAkB,EAClB,mBAAmB,EACnB,gCAAgC,EAChC,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EACjC,SAAS,EACT,SAAS,EACT,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,yBAAyB,EACzB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,MAAM,EACN,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACX,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aArGf,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;kBAhHiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA0DF,CAAC;oBAEd,CAAC;;;;aA0BkB,CAAC;mBAA8B,CAAC;WACvC,CAAC;gBACf,CAAC;gBAA4B,CAAA;;;mBAoBK,CAAC;oBACjC,CAAC;;;;;;;;;;;;;;;kBA3Dc,CAAC;;;;;;;sBAqCR,CAAC;;;;;;;;;CA2Of,CAAC;AAEF,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,YAAY,EACZ,OAAO,EACP,mBAAmB,EACnB,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,8BAA8B,EAC9B,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EACjC,kBAAkB,EAClB,mBAAmB,EACnB,gCAAgC,EAChC,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EACjC,SAAS,EACT,SAAS,EACT,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,yBAAyB,EACzB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,MAAM,EACN,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACX,CAAC"}
package/dist/index.js CHANGED
@@ -89,6 +89,8 @@ exports.utils = {
89
89
  verifyCustomCodeToken: customCodeToken_1.verifyCustomCodeToken,
90
90
  customCodeScriptName: customCodeToken_1.customCodeScriptName,
91
91
  customCodePreviewScriptName: customCodeToken_1.customCodePreviewScriptName,
92
+ customCodeUploadName: customCodeToken_1.customCodeUploadName,
93
+ customCodePreviewUploadName: customCodeToken_1.customCodePreviewUploadName,
92
94
  oauthProviders: oauthProviders_1.oauthProviders,
93
95
  resolveAttachment: attachment_1.resolveAttachment,
94
96
  isExposedResource: exposedResource_1.isExposedResource,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ganju/utils",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Shared constants, schemas and helpers for Ganju",
5
5
  "license": "Apache-2.0",
6
6
  "author": "MontoyaAndres <andresmontoyafcb@gmail.com>",
package/src/constants.ts CHANGED
@@ -1239,10 +1239,40 @@ const CUSTOM_CODE_MAIN_MODULE = 'index.js';
1239
1239
  const CUSTOM_CODE_MAX_FILES = 25;
1240
1240
  const CUSTOM_CODE_MAX_FILE_PATH = 100;
1241
1241
 
1242
- // WfP script name: `artifact_<artifactId>`. The id, never the slug — slugs are
1243
- // user-editable and a rename would orphan the deployed script.
1242
+ // WfP script name: `artifact_<artifactId>_<upload>`. The id, never the slug —
1243
+ // slugs are user-editable and a rename would orphan the deployed script.
1244
+ //
1245
+ // The trailing segment is minted per upload rather than derived from anything,
1246
+ // which is the whole point: uploading over a name that already exists is not
1247
+ // read-your-writes, so a deploy that replaces a script can serve the previous
1248
+ // edition for up to half a minute. A name nothing has ever used cannot, and
1249
+ // costs nothing to mint. Everything a publish used to do to survive that race —
1250
+ // waiting on an edition marker, refusing with a 503, putting the previous bundle
1251
+ // back when validation failed — went with the reuse that caused it.
1244
1252
  const CUSTOM_CODE_SCRIPT_NAME_PREFIX = 'artifact_';
1245
1253
 
1254
+ // Worker names cap at 63 characters, and `artifact_<uuid>` already spends 45.
1255
+ // That leaves 17 for a separator and a suffix, so a second uuid does not fit and
1256
+ // neither does a hex-32 digest. Twelve hex characters is 48 bits against a
1257
+ // namespace holding at most a few hundred names for any one artifact — not a
1258
+ // collision worth checking for, and an upload to a name in use would fail loudly
1259
+ // rather than quietly serve the wrong code.
1260
+ const CUSTOM_CODE_SCRIPT_NAME_MAX = 63;
1261
+ const CUSTOM_CODE_UPLOAD_SUFFIX_CHARS = 12;
1262
+
1263
+ // How long a superseded script stays in the namespace before the hourly sweep
1264
+ // may collect it.
1265
+ //
1266
+ // Deleting at publish time would race the thing it deletes: a tool call that
1267
+ // resolved the old pointer a moment earlier is still in flight, and the pointer
1268
+ // moving does not recall it. An hour is far longer than any call can take, and
1269
+ // the wait costs $0.02 per script per month against an allowance of 1,000.
1270
+ const CUSTOM_CODE_SWEEP_GRACE_MS = 60 * 60 * 1_000;
1271
+
1272
+ // Deletes per sweep. A backlog drains over several hourly runs rather than
1273
+ // making one run unbounded — the same shape the retention purge uses.
1274
+ const CUSTOM_CODE_SWEEP_MAX_DELETES = 200;
1275
+
1246
1276
  // A second script per artifact, `artifact_<id>_preview`, that the Test panel
1247
1277
  // deploys a draft into and calls.
1248
1278
  //
@@ -1453,15 +1483,17 @@ const CUSTOM_CODE_COMPATIBILITY_DATE = '2025-11-17';
1453
1483
  // tighter than our own workers' 30s — this is the technical cap that bounds
1454
1484
  // what one adversarial call can cost us, so an infinite loop in a customer's
1455
1485
  // tool is billed as five seconds rather than as whatever it wanted.
1456
- // How long publish waits for the edition it just uploaded to be the one the
1457
- // dispatcher answers with, and how often it asks.
1486
+ // How long a deploy waits for a freshly minted script name to become
1487
+ // dispatchable, and how often it asks.
1458
1488
  //
1459
- // Bounded rather than open-ended because this runs inside the publish request:
1460
- // past this, publishing would be a request nobody waits out. Exceeding it is
1461
- // reported as "try again" rather than published, which is the safe direction
1462
- // the alternative is advertising tools backed by a script that is not there yet.
1463
- const CUSTOM_CODE_SMOKE_TIMEOUT_MS = 20_000;
1464
- const CUSTOM_CODE_SMOKE_INTERVAL_MS = 1_000;
1489
+ // Every upload goes to a name that has never been used, which is
1490
+ // read-your-writes: ~2s end to end against the deployed namespace, against the
1491
+ // 20-41s a replacement could take. So this bounds how long a brand-new name
1492
+ // takes to register, never how long an old edition takes to stop answering
1493
+ // there is no old edition. It is short for that reason, and a script that
1494
+ // answers with the wrong edition now fails outright instead of being waited on.
1495
+ const CUSTOM_CODE_REGISTER_TIMEOUT_MS = 8_000;
1496
+ const CUSTOM_CODE_REGISTER_INTERVAL_MS = 500;
1465
1497
 
1466
1498
  const CUSTOM_CODE_SCRIPT_CPU_MS = 5_000;
1467
1499
 
@@ -2465,6 +2497,10 @@ export const constants = {
2465
2497
  CUSTOM_CODE_MAX_FILE_PATH,
2466
2498
  CUSTOM_CODE_VERSION_STATUSES,
2467
2499
  CUSTOM_CODE_SCRIPT_NAME_PREFIX,
2500
+ CUSTOM_CODE_SCRIPT_NAME_MAX,
2501
+ CUSTOM_CODE_UPLOAD_SUFFIX_CHARS,
2502
+ CUSTOM_CODE_SWEEP_GRACE_MS,
2503
+ CUSTOM_CODE_SWEEP_MAX_DELETES,
2468
2504
  CUSTOM_CODE_PREVIEW_SCRIPT_SUFFIX,
2469
2505
  CUSTOM_CODE_PREVIEW_TOKEN_TTL_MS,
2470
2506
  CUSTOM_CODE_TEST_TIMEOUT_MS,
@@ -2506,8 +2542,8 @@ export const constants = {
2506
2542
  CUSTOM_CODE_BROKER_SERVICE_ENV,
2507
2543
  CUSTOM_CODE_COMPATIBILITY_DATE,
2508
2544
  CUSTOM_CODE_SCRIPT_CPU_MS,
2509
- CUSTOM_CODE_SMOKE_TIMEOUT_MS,
2510
- CUSTOM_CODE_SMOKE_INTERVAL_MS,
2545
+ CUSTOM_CODE_REGISTER_TIMEOUT_MS,
2546
+ CUSTOM_CODE_REGISTER_INTERVAL_MS,
2511
2547
  CUSTOM_CODE_MAX_LOGS,
2512
2548
  CUSTOM_CODE_MAX_LOG_LENGTH,
2513
2549
  CUSTOM_CODE_SEND_FILE_TARGET_GMAIL,
@@ -179,20 +179,100 @@ export const verifyCustomCodeToken = async (
179
179
  };
180
180
 
181
181
  /**
182
- * The dispatch-namespace script name for an artifact: `artifact_<id>`.
182
+ * The legacy dispatch-namespace script name for an artifact: `artifact_<id>`.
183
183
  *
184
184
  * The id, never the slug — slugs are user-editable and a rename would orphan the
185
185
  * deployed script while the database still pointed at a live version.
186
+ *
187
+ * Nothing uploads to this name any more; every deploy mints its own. It survives
188
+ * as the fallback for a version published before `script_name` existed, whose
189
+ * bundle really is sitting under this name. Tightening a rule must never stop an
190
+ * already-published version from serving, because that failure is invisible to
191
+ * whoever owns it — the same reason the boot loop still accepts a stored tool key
192
+ * the current catalog no longer offers.
186
193
  */
187
194
  export const customCodeScriptName = (artifactId: string): string =>
188
195
  `${constants.CUSTOM_CODE_SCRIPT_NAME_PREFIX}${artifactId}`;
189
196
 
190
197
  /**
191
- * The script name a test run deploys into: `artifact_<id>_preview`.
198
+ * The legacy preview script name: `artifact_<id>_preview`.
192
199
  *
193
- * A second script rather than a second version of the live one, because a test
194
- * must not be able to disturb what MCP clients are being served and the only
195
- * way to be certain of that is for it to run under a name nothing dispatches to.
200
+ * Kept for the same reason as the one above, and for one more: it is the prefix
201
+ * the sweep matches to recognise a preview script left behind by a test run that
202
+ * did not clean up after itself.
196
203
  */
197
204
  export const customCodePreviewScriptName = (artifactId: string): string =>
198
205
  `${customCodeScriptName(artifactId)}${constants.CUSTOM_CODE_PREVIEW_SCRIPT_SUFFIX}`;
206
+
207
+ /**
208
+ * A dispatch-namespace name no upload has ever used:
209
+ * `artifact_<id>_<12 hex chars>`.
210
+ *
211
+ * Minted rather than derived, and that is the entire design. Uploading over an
212
+ * existing name is not read-your-writes — a replacement can serve the previous
213
+ * edition for tens of seconds — so a deploy that always writes to a new name is
214
+ * correct by construction rather than by waiting to see whether it worked.
215
+ *
216
+ * The suffix deliberately carries no meaning. The two candidates that did are
217
+ * both wrong: the bundle digest collides whenever a deploy reverts to bytes that
218
+ * shipped before, which is exactly what a rollback is, and the version id is one
219
+ * string across every re-upload of a single draft, which is every test run of it.
220
+ *
221
+ * Twelve hex characters is what fits. Worker names cap at 63 and
222
+ * `artifact_<uuid>` spends 45 of them.
223
+ */
224
+ export const customCodeUploadName = (artifactId: string): string =>
225
+ mintUploadName(customCodeScriptName(artifactId));
226
+
227
+ /**
228
+ * A preview name no test run has ever used:
229
+ * `artifact_<id>_preview_<12 hex chars>`.
230
+ *
231
+ * The sharper version of the same race. Every test used to deploy over one
232
+ * preview name, so a test could report the run before it — which reads as "my
233
+ * edit did nothing" from the one tool whose whole job is to say what an edit
234
+ * does. Nothing stores this: it is minted, used, and deleted inside one request.
235
+ */
236
+ export const customCodePreviewUploadName = (artifactId: string): string =>
237
+ mintUploadName(customCodePreviewScriptName(artifactId));
238
+
239
+ /**
240
+ * Append `_<hex>` to a base name, spending whatever the 63-character ceiling
241
+ * leaves and no more.
242
+ *
243
+ * The budget is genuinely tight, and the two names spend it differently:
244
+ *
245
+ * | name | base | separator | suffix | total |
246
+ * |---|---|---|---|---|
247
+ * | live | `artifact_<uuid>` = 45 | 1 | 12 | 58 |
248
+ * | preview | + `_preview` = 53 | 1 | 8 | 62 |
249
+ *
250
+ * Twelve hex characters is 48 bits and eight is 32, against a namespace holding
251
+ * a few hundred names for any one artifact — and a preview name lives for the
252
+ * seconds one test run takes. Neither is a collision worth checking for, and an
253
+ * upload to a name already in use fails loudly rather than quietly serving the
254
+ * wrong code, which is the failure that matters.
255
+ *
256
+ * The ceiling is asserted rather than assumed: it is one number away from being
257
+ * silently exceeded by a longer prefix, and a name Cloudflare refuses would
258
+ * surface as a failed publish with nothing explaining why.
259
+ */
260
+ const mintUploadName = (base: string): string => {
261
+ const available = constants.CUSTOM_CODE_SCRIPT_NAME_MAX - base.length - 1;
262
+ // Even, because each byte renders as two hex characters.
263
+ const chars =
264
+ Math.min(constants.CUSTOM_CODE_UPLOAD_SUFFIX_CHARS, available) & ~1;
265
+
266
+ if (chars < 4) {
267
+ throw new Error(
268
+ `A dispatch script name based on "${base}" leaves no room for a unique suffix.`
269
+ );
270
+ }
271
+
272
+ const bytes = new Uint8Array(chars / 2);
273
+ crypto.getRandomValues(bytes);
274
+
275
+ return `${base}_${Array.from(bytes)
276
+ .map(byte => byte.toString(16).padStart(2, '0'))
277
+ .join('')}`;
278
+ };
package/src/index.ts CHANGED
@@ -102,7 +102,9 @@ import {
102
102
  mintCustomCodeToken,
103
103
  verifyCustomCodeToken,
104
104
  customCodeScriptName,
105
- customCodePreviewScriptName
105
+ customCodePreviewScriptName,
106
+ customCodeUploadName,
107
+ customCodePreviewUploadName
106
108
  } from './customCodeToken';
107
109
  import type { CustomCodeTokenPayload } from './customCodeToken';
108
110
  import { oauthProviders } from './oauthProviders';
@@ -257,6 +259,8 @@ export const utils = {
257
259
  verifyCustomCodeToken,
258
260
  customCodeScriptName,
259
261
  customCodePreviewScriptName,
262
+ customCodeUploadName,
263
+ customCodePreviewUploadName,
260
264
  oauthProviders,
261
265
  resolveAttachment,
262
266
  isExposedResource,