kanbo-cli 0.1.3 → 0.2.1

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.
@@ -1,257 +1,3 @@
1
- import { $ as commentAuthorReference, A as maskDatabaseUrls, B as readEntryRules, C as cardDisplayTitle, D as readProjectBinding, E as readBinding, F as ENTRY_RULES, G as normalizeStatusName, H as readChangeSeq, I as ENTRY_RULE_DESCRIPTIONS, J as BOARD_ACTOR, K as TRACKED_FIELDS, L as UNMET_ENTRY_RULE_REASONS, M as formatExternalSessionRef, N as parseExternalSessionRef, O as writeBinding, P as pullRequestFactKeys, Q as activityToken, R as evaluateEntryRules, S as renderCapabilitiesMarkdown, T as ignoreBoardFile, U as runBoardWrite, V as serializeEntryRules, W as DEFAULT_STATUSES, X as activityKindOrder, Y as currentUnixSeconds, Z as activityText, a as BOARD_ERROR_RESPONSES, at as isOutsideWriter, ct as formatIssueId, dt as nextIssueOrder, et as formatActivityIssueReference, ft as readIssuePrefix, i as KANBO_TOOL_NAMES, it as readSystemCommentKind, j as createBoardOps, k as maskDatabaseUrl, lt as nextIssueIdentity, n as buildCapabilitiesManifest, nt as isEmptyActivityValue, ot as normalizeCommentAuthorKind, q as diffFieldChanges, r as KANBO_TOOL_CLI_EQUIVALENTS, rt as parseActivityStringArray, st as toIssueView, t as CAPABILITIES_MANIFEST_VERSION, tt as formatPlainActivityValue, ut as nextIssueNumber, w as BINDING_FILE_PATH, x as DEFAULT_BOARD_FILE_PATH, z as readChecklist } from "./manifest-mkDJmxt2.mjs";
1
+ import { $ as commentAuthorReference, A as maskDatabaseUrls, B as readEntryRules, C as cardDisplayTitle, D as readProjectBinding, E as readBinding, F as ENTRY_RULES, G as normalizeStatusName, H as readChangeSeq, I as ENTRY_RULE_DESCRIPTIONS, J as BOARD_ACTOR, K as TRACKED_FIELDS, L as UNMET_ENTRY_RULE_REASONS, M as formatExternalSessionRef, N as parseExternalSessionRef, O as writeBinding, P as pullRequestFactKeys, Q as activityToken, R as evaluateEntryRules, S as renderCapabilitiesMarkdown, T as ignoreBoardFile, U as runBoardWrite, V as serializeEntryRules, W as DEFAULT_STATUSES, X as activityKindOrder, Y as currentUnixSeconds, Z as activityText, a as BOARD_ERROR_RESPONSES, at as isOutsideWriter, ct as formatIssueId, dt as nextIssueOrder, et as formatActivityIssueReference, ft as readIssuePrefix, i as KANBO_TOOL_NAMES, it as readSystemCommentKind, j as createBoardOps, k as maskDatabaseUrl, lt as nextIssueIdentity, n as buildCapabilitiesManifest, nt as isEmptyActivityValue, ot as normalizeCommentAuthorKind, q as diffFieldChanges, r as KANBO_TOOL_CLI_EQUIVALENTS, rt as parseActivityStringArray, st as toIssueView, t as CAPABILITIES_MANIFEST_VERSION, tt as formatPlainActivityValue, ut as nextIssueNumber, w as BINDING_FILE_PATH, x as DEFAULT_BOARD_FILE_PATH, z as readChecklist } from "./manifest-DHV2fRdO.mjs";
2
2
  import { a as BoardError } from "./migrations-path-Ciwan537.mjs";
3
- //#region src/ops/board-copy.ts
4
- /** Nothing copied — what a move that had nothing to move reports. */
5
- function emptyCopyCounts() {
6
- return {
7
- statuses: 0,
8
- milestones: 0,
9
- issues: 0,
10
- comments: 0,
11
- runs: 0,
12
- relations: 0,
13
- fieldChanges: 0,
14
- contextRefs: 0,
15
- pullRequests: 0
16
- };
17
- }
18
- /**
19
- * Everything the workspace has on this board, read in one pass before a single
20
- * row is written anywhere.
21
- *
22
- * Links are collected by id because an edge is listed by both of the cards it
23
- * touches, and one reaching a card outside this workspace is left behind rather
24
- * than copied: the target holds this workspace's board and nothing else, so the
25
- * far end of that edge is not there to point at.
26
- */
27
- async function readBoardSlice(from, workspaceId) {
28
- const warnings = [];
29
- const statuses = await from.statuses.listByWorkspace(workspaceId);
30
- const milestones = await from.milestones.listByWorkspace(workspaceId);
31
- const issues = orderParentsFirst(await from.issues.listByWorkspace(workspaceId));
32
- const issueIds = new Set(issues.map((issue) => issue.id));
33
- const comments = [];
34
- const runs = [];
35
- const relations = /* @__PURE__ */ new Map();
36
- const fieldChanges = [];
37
- const pullRequests = [];
38
- const skippedRelations = /* @__PURE__ */ new Set();
39
- for (const issue of issues) {
40
- comments.push(...await from.comments.listByIssue(issue.id));
41
- runs.push(...await from.runs.listByIssue(issue.id));
42
- for (const relation of await from.relations.listByIssue(issue.id)) {
43
- if (issueIds.has(relation.sourceIssueId) && issueIds.has(relation.targetIssueId)) {
44
- relations.set(relation.id, relation);
45
- continue;
46
- }
47
- skippedRelations.add(relation.id);
48
- }
49
- fieldChanges.push(...await from.fieldChanges.listByIssue(issue.id));
50
- pullRequests.push(...await from.pullRequests.listByIssue(issue.id));
51
- }
52
- if (skippedRelations.size > 0) warnings.push(`${skippedRelations.size} links to cards in other workspaces were not moved`);
53
- return {
54
- statuses,
55
- milestones,
56
- issues,
57
- comments,
58
- runs,
59
- relations: [...relations.values()],
60
- fieldChanges,
61
- pullRequests,
62
- warnings
63
- };
64
- }
65
- /**
66
- * Write a slice into the target board, in one transaction, and say what was
67
- * written and what a person should know about it — the slice's own warnings
68
- * first.
69
- *
70
- * It is idempotent by id. A row the target already has is left exactly as it
71
- * is and counted as already present, so a copy interrupted half-way is finished
72
- * by running it again, and a second run of a finished one copies nothing. A
73
- * clash that is not the same row — a column name or a card number the target
74
- * holds under another id — refuses the whole copy before its first insert
75
- * (`board_copy_conflict`, ruling 3-55).
76
- */
77
- async function writeBoardSlice(to, slice, workspaceId) {
78
- const warnings = [...slice.warnings];
79
- const copied = emptyCopyCounts();
80
- let alreadyPresent = 0;
81
- await to.transaction(async (tx) => {
82
- await assertTheCopyFits(tx, slice, workspaceId);
83
- for (const status of slice.statuses) {
84
- if (await tx.statuses.findById(status.id)) {
85
- alreadyPresent += 1;
86
- continue;
87
- }
88
- await tx.statuses.create(status);
89
- copied.statuses += 1;
90
- }
91
- for (const milestone of slice.milestones) {
92
- if (await tx.milestones.findById(milestone.id)) {
93
- alreadyPresent += 1;
94
- continue;
95
- }
96
- await tx.milestones.create(milestone);
97
- copied.milestones += 1;
98
- }
99
- const movingIssueIds = new Set(slice.issues.map((issue) => issue.id));
100
- for (const issue of slice.issues) {
101
- if (await tx.issues.findById(issue.id)) {
102
- alreadyPresent += 1;
103
- continue;
104
- }
105
- const parentIsReachable = issue.parentIssueId === null || movingIssueIds.has(issue.parentIssueId) || await tx.issues.findById(issue.parentIssueId) !== null;
106
- if (!parentIsReachable) warnings.push(`${issue.id} lost its parent card, which is not on this board`);
107
- const { contextRefs, ...row } = issue;
108
- await tx.issues.create({
109
- ...row,
110
- parentIssueId: parentIsReachable ? issue.parentIssueId : null
111
- });
112
- copied.issues += 1;
113
- if (contextRefs !== "[]") {
114
- await tx.contextRefs.replace(issue.id, contextRefs, issue.updatedAt);
115
- copied.contextRefs += 1;
116
- }
117
- }
118
- for (const comment of slice.comments) {
119
- if (await tx.comments.findById(comment.id)) {
120
- alreadyPresent += 1;
121
- continue;
122
- }
123
- await tx.comments.create(comment);
124
- copied.comments += 1;
125
- }
126
- for (const run of slice.runs) {
127
- if (await tx.runs.findById(run.id)) {
128
- alreadyPresent += 1;
129
- continue;
130
- }
131
- await tx.runs.create(run);
132
- copied.runs += 1;
133
- }
134
- for (const relation of slice.relations) {
135
- if (await tx.relations.findById(relation.id)) {
136
- alreadyPresent += 1;
137
- continue;
138
- }
139
- await tx.relations.create(relation);
140
- copied.relations += 1;
141
- }
142
- const changesByIssue = /* @__PURE__ */ new Map();
143
- for (const change of slice.fieldChanges) changesByIssue.set(change.issueId, [...changesByIssue.get(change.issueId) ?? [], change]);
144
- for (const [issueId, changes] of changesByIssue) {
145
- const present = new Set((await tx.fieldChanges.listByIssue(issueId)).map((change) => change.id));
146
- for (const change of changes) {
147
- if (present.has(change.id)) {
148
- alreadyPresent += 1;
149
- continue;
150
- }
151
- await tx.fieldChanges.create(change);
152
- copied.fieldChanges += 1;
153
- }
154
- }
155
- const linksByIssue = /* @__PURE__ */ new Map();
156
- for (const link of slice.pullRequests) linksByIssue.set(link.issueId, [...linksByIssue.get(link.issueId) ?? [], link]);
157
- for (const [issueId, links] of linksByIssue) {
158
- const present = new Set((await tx.pullRequests.listByIssue(issueId)).map((link) => link.id));
159
- for (const link of links) {
160
- if (present.has(link.id) || (await tx.pullRequests.link(link)).id !== link.id) {
161
- alreadyPresent += 1;
162
- continue;
163
- }
164
- copied.pullRequests += 1;
165
- }
166
- }
167
- await tx.meta.bumpRevision("board", currentUnixSeconds());
168
- });
169
- if (alreadyPresent > 0) warnings.push(`${alreadyPresent} rows were already present on the target board and were left as they are`);
170
- return {
171
- copied,
172
- warnings
173
- };
174
- }
175
- /**
176
- * Empty the slice off the board it was read from, in a transaction of its own.
177
- *
178
- * Only the cards, the columns and the milestones are named: comments, runs,
179
- * links, pull request links and the field-change history hang off a card by a
180
- * foreign key that cascades on both engines, so deleting the card takes them
181
- * with it.
182
- */
183
- async function deleteBoardSlice(from, slice) {
184
- await from.transaction(async (tx) => {
185
- for (const issue of slice.issues) await tx.issues.delete(issue.id);
186
- for (const milestone of slice.milestones) await tx.milestones.delete(milestone.id);
187
- for (const status of slice.statuses) await tx.statuses.delete(status.id);
188
- await tx.meta.bumpRevision("board", currentUnixSeconds());
189
- });
190
- }
191
- /**
192
- * What a copy would collide with on the target, said before a row is written.
193
- *
194
- * The board carries two uniqueness rules that a *second* board of the same
195
- * workspace can break: a column's name within its workspace, and a card's
196
- * number within it. In practice it is the columns that collide: a standard set
197
- * created a second time carries the same names under new ids, while a card's id
198
- * is its key (`BST-001`), so two generations of card *number* 1 are two rows
199
- * with one id — which the copy treats as already present rather than as a
200
- * clash. The number check covers the case where they are not: a workspace whose
201
- * identifier changed between the two generations numbers from 1 again under
202
- * different ids.
203
- *
204
- * A row the target already has *by id* is not a collision — it is the
205
- * idempotent half of the copy, which is why the holder's id is compared rather
206
- * than merely counted. Milestones need no check: neither engine makes their
207
- * titles unique.
208
- */
209
- async function assertTheCopyFits(tx, slice, workspaceId) {
210
- const conflicts = [];
211
- const numbers = new Map((await tx.issues.listByWorkspace(workspaceId)).map((issue) => [issue.number, issue.id]));
212
- for (const issue of slice.issues) {
213
- const holder = numbers.get(issue.number);
214
- if (holder !== void 0 && holder !== issue.id) conflicts.push({
215
- kind: "card",
216
- value: issue.number,
217
- heldBy: holder
218
- });
219
- }
220
- const names = new Map((await tx.statuses.listByWorkspace(workspaceId)).map((status) => [status.name, status.id]));
221
- for (const status of slice.statuses) {
222
- const holder = names.get(status.name);
223
- if (holder !== void 0 && holder !== status.id) conflicts.push({
224
- kind: "column",
225
- value: status.name,
226
- heldBy: holder
227
- });
228
- }
229
- if (conflicts.length > 0) throw new BoardError("board_copy_conflict", {
230
- workspaceId,
231
- conflicts
232
- });
233
- }
234
- /**
235
- * The same cards, ordered so that a parent is always written before its
236
- * children. The column is a foreign key onto the same table, so any other order
237
- * writes a card pointing at one that is not there yet.
238
- */
239
- function orderParentsFirst(issues) {
240
- const byId = new Map(issues.map((issue) => [issue.id, issue]));
241
- const ordered = [];
242
- const placed = /* @__PURE__ */ new Set();
243
- function place(issue, ancestors) {
244
- if (placed.has(issue.id) || ancestors.has(issue.id)) return;
245
- ancestors.add(issue.id);
246
- const parent = issue.parentIssueId === null ? void 0 : byId.get(issue.parentIssueId);
247
- if (parent) place(parent, ancestors);
248
- placed.add(issue.id);
249
- ordered.push(issue);
250
- }
251
- for (const issue of issues) place(issue, /* @__PURE__ */ new Set());
252
- return ordered;
253
- }
254
- //#endregion
255
- export { BINDING_FILE_PATH, BOARD_ACTOR, BOARD_ERROR_RESPONSES, BoardError, CAPABILITIES_MANIFEST_VERSION, DEFAULT_BOARD_FILE_PATH, DEFAULT_STATUSES, ENTRY_RULES, ENTRY_RULE_DESCRIPTIONS, KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, TRACKED_FIELDS, UNMET_ENTRY_RULE_REASONS, activityKindOrder, activityText, activityToken, buildCapabilitiesManifest, cardDisplayTitle, commentAuthorReference, createBoardOps, currentUnixSeconds, deleteBoardSlice, diffFieldChanges, emptyCopyCounts, evaluateEntryRules, formatActivityIssueReference, formatExternalSessionRef, formatIssueId, formatPlainActivityValue, ignoreBoardFile, isEmptyActivityValue, isOutsideWriter, maskDatabaseUrl, maskDatabaseUrls, nextIssueIdentity, nextIssueNumber, nextIssueOrder, normalizeCommentAuthorKind, normalizeStatusName, parseActivityStringArray, parseExternalSessionRef, pullRequestFactKeys, readBinding, readBoardSlice, readChangeSeq, readChecklist, readEntryRules, readIssuePrefix, readProjectBinding, readSystemCommentKind, renderCapabilitiesMarkdown, runBoardWrite, serializeEntryRules, toIssueView, writeBinding, writeBoardSlice };
256
-
257
- //# sourceMappingURL=index.mjs.map
3
+ export { BINDING_FILE_PATH, BOARD_ACTOR, BOARD_ERROR_RESPONSES, BoardError, CAPABILITIES_MANIFEST_VERSION, DEFAULT_BOARD_FILE_PATH, DEFAULT_STATUSES, ENTRY_RULES, ENTRY_RULE_DESCRIPTIONS, KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, TRACKED_FIELDS, UNMET_ENTRY_RULE_REASONS, activityKindOrder, activityText, activityToken, buildCapabilitiesManifest, cardDisplayTitle, commentAuthorReference, createBoardOps, currentUnixSeconds, diffFieldChanges, evaluateEntryRules, formatActivityIssueReference, formatExternalSessionRef, formatIssueId, formatPlainActivityValue, ignoreBoardFile, isEmptyActivityValue, isOutsideWriter, maskDatabaseUrl, maskDatabaseUrls, nextIssueIdentity, nextIssueNumber, nextIssueOrder, normalizeCommentAuthorKind, normalizeStatusName, parseActivityStringArray, parseExternalSessionRef, pullRequestFactKeys, readBinding, readChangeSeq, readChecklist, readEntryRules, readIssuePrefix, readProjectBinding, readSystemCommentKind, renderCapabilitiesMarkdown, runBoardWrite, serializeEntryRules, toIssueView, writeBinding };
@@ -1926,15 +1926,12 @@ async function approve(store, issueId, input, actor, scope) {
1926
1926
  * leaves even says "returned by you".
1927
1927
  */
1928
1928
  async function returnCard(store, issueId, input, actor, scope) {
1929
- if (actor.kind !== "user") throw new require_migrations_path.BoardError("board_return_requires_user", {
1930
- issueId,
1931
- actorKind: actor.kind
1932
- });
1933
1929
  return await runBoardWrite(store, async ({ tx }) => {
1930
+ await ensureDefaultColumns(tx, (await requireCard$1(tx, issueId)).workspaceId, { tx });
1931
+ const target = await assertReturnable(tx, issueId, input, actor);
1934
1932
  const card = await requireCard$1(tx, issueId);
1935
- const columns = await ensureDefaultColumns(tx, card.workspaceId, { tx });
1936
1933
  const updates = {
1937
- statusId: (input.toStatusName ? await requireColumn(tx, card.workspaceId, input.toStatusName) : previousColumn(columns, card)).id,
1934
+ statusId: target.id,
1938
1935
  waitingFor: null,
1939
1936
  updatedAt: currentUnixSeconds()
1940
1937
  };
@@ -1955,6 +1952,27 @@ async function returnCard(store, issueId, input, actor, scope) {
1955
1952
  };
1956
1953
  }, scope);
1957
1954
  }
1955
+ /**
1956
+ * Every reason `returnCard` would refuse, asked on reads alone, and the column
1957
+ * the card would go back to when none applies.
1958
+ *
1959
+ * `returnCard` asks exactly this inside its write. A caller that has to undo
1960
+ * something of its own before the return — stop listening for the approval the
1961
+ * card is waiting on, say — asks it first, so a return the board refuses leaves
1962
+ * that untouched. The refusals are the same `BoardError` codes: an actor who is
1963
+ * not a person (`board_return_requires_user`), a card that is not there
1964
+ * (`issue_not_found`), a named column the workspace does not hold
1965
+ * (`issue_status_not_found`), and a card already in the first column with no
1966
+ * column named (`board_return_no_previous_column`).
1967
+ */
1968
+ async function assertReturnable(store, issueId, input, actor) {
1969
+ if (actor.kind !== "user") throw new require_migrations_path.BoardError("board_return_requires_user", {
1970
+ issueId,
1971
+ actorKind: actor.kind
1972
+ });
1973
+ const card = await requireCard$1(store, issueId);
1974
+ return input.toStatusName ? await requireColumn(store, card.workspaceId, input.toStatusName) : previousColumn(await listColumns(store, card.workspaceId), card);
1975
+ }
1958
1976
  /** Write a comment on the card, as the actor unless the caller names another author. */
1959
1977
  async function addComment(store, input, actor, scope) {
1960
1978
  return await runBoardWrite(store, async ({ tx }) => {
@@ -2832,6 +2850,7 @@ function createBoardOps(store) {
2832
2850
  waitApproval: async (issueId, input, actor, scope) => await waitApproval(store, issueId, input, actor, scope),
2833
2851
  approve: async (issueId, input, actor, scope) => await approve(store, issueId, input, actor, scope),
2834
2852
  returnCard: async (issueId, input, actor, scope) => await returnCard(store, issueId, input, actor, scope),
2853
+ assertReturnable: async (issueId, input, actor) => await assertReturnable(store, issueId, input, actor),
2835
2854
  readApproval: async (issueId) => await readApproval(store, issueId),
2836
2855
  linkPullRequest: async (issueId, urlOrRef, actor, scope) => await linkPullRequest(store, issueId, urlOrRef, actor, scope),
2837
2856
  unlinkPullRequest: async (issueId, linkId, actor, scope) => await unlinkPullRequest(store, issueId, linkId, actor, scope),
@@ -4334,7 +4353,7 @@ function readRequestedRules(options) {
4334
4353
  * `package.version`. A build carries it as a literal; running from source
4335
4354
  * (tests, `tsx`) reads the package's own `package.json` instead.
4336
4355
  */
4337
- const KANBO_PACKAGE_VERSION = "0.1.3";
4356
+ const KANBO_PACKAGE_VERSION = "0.2.1";
4338
4357
  //#endregion
4339
4358
  //#region src/cli/failure.ts
4340
4359
  /**
@@ -7020,21 +7039,6 @@ function sendBoardPage(response, pathname, assets) {
7020
7039
  * reason turned around: the answer will be yes once the card meets them, and
7021
7040
  * `details.unmet` says what is missing.
7022
7041
  *
7023
- * The five failures about where a board is kept read the same rule. A database
7024
- * that holds no board this build can speak for is 409 — the setting is there,
7025
- * the board behind it is not yet, and `board-storage prepare` is what settles
7026
- * that — and one nobody could reach at all is 503, because nothing about the
7027
- * request was wrong. A workspace naming no board at all is 404: the caller
7028
- * asked about a setting that is not there. A board still holding cards when
7029
- * somebody asks to point the workspace elsewhere is 409, because the answer
7030
- * would have been yes on an empty board and `board-storage migrate` is what
7031
- * makes it one. An operation naming cards from two different boards is 400: no
7032
- * transaction reaches both, so the caller asked for something that cannot be
7033
- * done. A copy that would land on a card number or a column name the target
7034
- * already holds under a different id is 409 for the same reason the others
7035
- * are: the answer would have been yes on a target that did not hold that
7036
- * board, and `details.conflicts` names every value that clashed.
7037
- *
7038
7042
  * A failure may also be renamed here: the package names its codes after the
7039
7043
  * board, while every error the `/issues` routes answer with is named after the
7040
7044
  * issue, and a client matching on `issue_*` should not have to learn a second
@@ -7056,10 +7060,6 @@ const BOARD_ERROR_RESPONSES = {
7056
7060
  message: "The card does not meet what that column asks for yet",
7057
7061
  code: "issue_column_rules_unmet"
7058
7062
  },
7059
- board_copy_conflict: {
7060
- status: 409,
7061
- message: "That board already holds cards or columns of this workspace under the same numbers or names; nothing was copied"
7062
- },
7063
7063
  board_entry_rule_invalid: {
7064
7064
  status: 400,
7065
7065
  message: "Unknown column entry rule"
@@ -7068,10 +7068,6 @@ const BOARD_ERROR_RESPONSES = {
7068
7068
  status: 400,
7069
7069
  message: "Execution mode cannot change once the card has been launched"
7070
7070
  },
7071
- board_mixed_workspaces: {
7072
- status: 400,
7073
- message: "Those cards are not all on the same board"
7074
- },
7075
7071
  board_pull_request_invalid: {
7076
7072
  status: 400,
7077
7073
  message: "Not a GitHub pull request: give its URL or owner/repo#number"
@@ -7131,22 +7127,6 @@ const BOARD_ERROR_RESPONSES = {
7131
7127
  status: 400,
7132
7128
  message: "A sprint cannot start after it is due"
7133
7129
  },
7134
- board_storage_not_configured: {
7135
- status: 404,
7136
- message: "This workspace names no board storage"
7137
- },
7138
- board_storage_not_empty: {
7139
- status: 409,
7140
- message: "That board still holds cards of this workspace; move them with migrate before changing where the board is kept"
7141
- },
7142
- board_storage_not_prepared: {
7143
- status: 409,
7144
- message: "That board has not been prepared yet"
7145
- },
7146
- board_storage_unavailable: {
7147
- status: 503,
7148
- message: "That board could not be reached"
7149
- },
7150
7130
  issue_comment_delete_requires_user: {
7151
7131
  status: 403,
7152
7132
  message: "Only a person can delete a comment the board wrote"
@@ -9368,4 +9348,4 @@ Object.defineProperty(exports, "writeBinding", {
9368
9348
  }
9369
9349
  });
9370
9350
 
9371
- //# sourceMappingURL=manifest-BBJIrMw7.cjs.map
9351
+ //# sourceMappingURL=manifest-D9nCRtXM.cjs.map