@eyeauras/youtrack-cli 0.1.0 → 0.3.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/LICENSE +21 -21
- package/README.md +113 -30
- package/dist/src/article-extras-commands.d.ts.map +1 -1
- package/dist/src/article-extras-commands.js +3 -1
- package/dist/src/article-extras-commands.js.map +1 -1
- package/dist/src/articles-commands.d.ts.map +1 -1
- package/dist/src/articles-commands.js +8 -6
- package/dist/src/articles-commands.js.map +1 -1
- package/dist/src/articles.d.ts +9 -0
- package/dist/src/articles.d.ts.map +1 -1
- package/dist/src/articles.js +19 -0
- package/dist/src/articles.js.map +1 -1
- package/dist/src/attachment-download-commands.d.ts +1 -0
- package/dist/src/attachment-download-commands.d.ts.map +1 -1
- package/dist/src/attachment-download-commands.js +12 -8
- package/dist/src/attachment-download-commands.js.map +1 -1
- package/dist/src/attachment-download.d.ts +1 -0
- package/dist/src/attachment-download.d.ts.map +1 -1
- package/dist/src/attachment-download.js +19 -11
- package/dist/src/attachment-download.js.map +1 -1
- package/dist/src/cli-support.d.ts +5 -2
- package/dist/src/cli-support.d.ts.map +1 -1
- package/dist/src/cli-support.js +53 -10
- package/dist/src/cli-support.js.map +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +51 -8
- package/dist/src/cli.js.map +1 -1
- package/dist/src/client.d.ts +19 -4
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +66 -33
- package/dist/src/client.js.map +1 -1
- package/dist/src/index.d.ts +5 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/issue-batch.d.ts +28 -0
- package/dist/src/issue-batch.d.ts.map +1 -0
- package/dist/src/issue-batch.js +138 -0
- package/dist/src/issue-batch.js.map +1 -0
- package/dist/src/issue-context-commands.d.ts.map +1 -1
- package/dist/src/issue-context-commands.js +1 -1
- package/dist/src/issue-context-commands.js.map +1 -1
- package/dist/src/issue-fields.d.ts +16 -0
- package/dist/src/issue-fields.d.ts.map +1 -1
- package/dist/src/issue-fields.js +96 -1
- package/dist/src/issue-fields.js.map +1 -1
- package/dist/src/issue-query-commands.js +2 -2
- package/dist/src/issue-query-commands.js.map +1 -1
- package/dist/src/issue-query.js +2 -2
- package/dist/src/issue-query.js.map +1 -1
- package/package.json +3 -2
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 AI CLI Factory contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AI CLI Factory contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -16,9 +16,10 @@ Licensed under MIT. See the [release guide](https://github.com/iXab3r/EyeAuras.C
|
|
|
16
16
|
|
|
17
17
|
YouTrack uses the same `@eyeauras/cli-factory` workspace as TeamCity. The CLI
|
|
18
18
|
provides standard profiles/auth/permissions and 118 REST operations: 98 ReadOnly and 20 Update.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
Five workflow leaves reuse those operations instead of adding REST operations: issue and article
|
|
20
|
+
attachment download, article export, and `issues batch validate/apply`. There are 121 service
|
|
21
|
+
leaves: 116 for REST operations plus these five. Two `--direct` selectors each select a second
|
|
22
|
+
REST endpoint without adding another leaf.
|
|
22
23
|
The foundational read projections are:
|
|
23
24
|
|
|
24
25
|
| Command | Default fields |
|
|
@@ -31,16 +32,24 @@ The foundational read projections are:
|
|
|
31
32
|
|
|
32
33
|
REST reads support explicit `--fields <projection>`. Projection results retain the server's
|
|
33
34
|
field names, `$type` and nullable values; authentication always validates fixed `id,login`.
|
|
34
|
-
Offset collections use `--top 50 --skip 0` by default; top is
|
|
35
|
+
Offset collections use `--top 50 --skip 0` by default; top is a positive safe integer and skip a nonnegative safe integer.
|
|
35
36
|
Paging accepts unsigned decimal digits, including leading zeros; signs (including `-0`), whitespace,
|
|
36
37
|
fractions, exponents and unsafe integers reject. Invalid syntax, range and overflow now fail before
|
|
37
38
|
onboarding or credential access on CLI, execute and RPC. The static errors are
|
|
38
|
-
`YouTrack top must be a decimal integer
|
|
39
|
+
`YouTrack top must be a positive safe decimal integer.` and
|
|
39
40
|
`YouTrack skip must be a nonnegative safe decimal integer.`; they never include the supplied input.
|
|
40
41
|
Directly callable service methods retain their own range validation.
|
|
41
|
-
Each collection command makes one request, and rejects an oversized server page.
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
Each collection command makes one request, and rejects an oversized server page. Multi-page reads
|
|
43
|
+
happen only for the explicit `issues list --all` described below and for field `name` selectors in
|
|
44
|
+
issue writes (their field list is read completely; cancellable); no other nested follow-up requests
|
|
45
|
+
are made. Issue IDs are encoded as opaque path segments, including readable IDs such as `DEMO-1`.
|
|
46
|
+
|
|
47
|
+
`issues list --all --max-results <n>` reads every page (`--top` is the page size, `--skip` the start)
|
|
48
|
+
with the same query and projection. Success means the selection is complete: the result is the
|
|
49
|
+
same JSON array in server order, with repeated `id`s removed. More than `n` issues, responses over
|
|
50
|
+
the optional `--max-bytes <n>` (total decoded bytes; also valid without `--all`) or any failed page
|
|
51
|
+
fail the whole command without partial output or retries. `--all` and `--max-results` require each
|
|
52
|
+
other. Offset paging is not a snapshot: concurrent changes can still omit issues.
|
|
44
53
|
|
|
45
54
|
```powershell
|
|
46
55
|
npm run youtrack -- project list --top 3 --profile youtrack-dev
|
|
@@ -54,16 +63,14 @@ Empty collections are `[]`. Signed/credential-bearing URLs and the active bearer
|
|
|
54
63
|
scrubbed recursively, including explicitly projected nested fields. Unsigned URLs remain
|
|
55
64
|
unchanged. Failures expose HTTP status and safe Retry-After information, never raw server
|
|
56
65
|
errors or authentication material. Remote mutations require the Update gate, described below.
|
|
57
|
-
The ReadOnly download
|
|
66
|
+
The ReadOnly download and export commands write only their explicitly requested local file beneath
|
|
67
|
+
profile AppData.
|
|
58
68
|
|
|
59
|
-
JSON responses
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
Compressed wire length is syntax-checked but not compared with decoded size. Existing HTTP status,
|
|
65
|
-
Retry-After, empty/null mutation and UTF-8 BOM behavior are unchanged. Attachment-download limits
|
|
66
|
-
remain separate; no request is retried automatically.
|
|
69
|
+
JSON responses have no CLI byte ceiling. Invalid/truncated identity transfer lengths, stream failure
|
|
70
|
+
or cancellation fail with `YouTrack response stream failed or was cancelled.` without response content.
|
|
71
|
+
Compressed wire length is syntax-checked but not compared with decoded size. HTTP status,
|
|
72
|
+
Retry-After, empty/null mutation and UTF-8 BOM behavior are unchanged. No request is retried
|
|
73
|
+
automatically. Runtime memory and service limits still apply.
|
|
67
74
|
|
|
68
75
|
## Sign in locally
|
|
69
76
|
|
|
@@ -130,17 +137,37 @@ This documentation does not enable it automatically. The local proof remains Rea
|
|
|
130
137
|
|
|
131
138
|
| Command | Required `--body` JSON object |
|
|
132
139
|
|---|---|
|
|
133
|
-
| `issues create` |
|
|
134
|
-
| `issues update <issueID>` | Nonempty subset of `summary` and `
|
|
140
|
+
| `issues create` | `project` as exactly one of `{id}`/`{shortName}`, nonempty `summary`; optional string or null `description`, optional `customFields` |
|
|
141
|
+
| `issues update <issueID>` | Nonempty subset of `summary`, `description` and `customFields`; summary must be nonempty |
|
|
135
142
|
| `issues comments add <issueID>` | Nonempty `text` only |
|
|
136
143
|
|
|
137
144
|
Missing `--body` and malformed JSON fail before profile onboarding or credential access.
|
|
138
145
|
Description and comment text preserve multiline Markdown. Omitted fields remain unchanged;
|
|
139
146
|
`description: null` clears the description. Unknown fields (including nested project properties)
|
|
140
|
-
are rejected locally.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
are rejected locally. Visibility, notification controls and state-machine events are not accepted.
|
|
148
|
+
|
|
149
|
+
`customFields` is a nonempty array sent in the same single POST, so a project's required fields
|
|
150
|
+
can be set at creation. Each entry has an explicit `$type`, exactly one of `id` or `name`, and a
|
|
151
|
+
`value` validated like `issues fields set` below (`null`/`[]` clear on update). A field may appear
|
|
152
|
+
once. `StateMachineIssueCustomField` is rejected: a new issue starts in its workflow's initial
|
|
153
|
+
state, and transitions stay on `issues fields set` events or `commands apply`. Selectors resolve
|
|
154
|
+
exactly before the write: `project.shortName` by one project read (case-insensitive match
|
|
155
|
+
required), field `name` (case-sensitive) against all fields of the project (create) or issue
|
|
156
|
+
(update). Zero or several matches fail before the POST; `id` entries need no lookup. Value
|
|
157
|
+
selectors (`id`, `name`, `login` for users) are resolved by YouTrack inside the request; `$type`
|
|
158
|
+
is never inferred and nothing is cached.
|
|
159
|
+
|
|
160
|
+
```powershell
|
|
161
|
+
npm run youtrack -- issues create --profile youtrack-dev --body '{"project":{"shortName":"DEMO"},"summary":"Example","customFields":[{"$type":"SingleEnumIssueCustomField","name":"Priority","value":{"name":"Major"}}]}'
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Every narrative write also accepts a UTF-8 file for its text field: `--description-file` (issue
|
|
165
|
+
create/update), `--content-file` (article create/update) and `--text-file` (issue/article comment
|
|
166
|
+
add/update). `--body` stays required (use `{}` when the file supplies the only field) and must not
|
|
167
|
+
also contain that field. Files are read only after Update admission, as strict UTF-8 with an
|
|
168
|
+
initial BOM removed and otherwise unchanged (line endings included); invalid encoding, directories
|
|
169
|
+
and unreadable paths fail before any request. Clearing still uses `--body` with `null`. There is no
|
|
170
|
+
local size ceiling, and stdin is not used because JSON-RPC owns it.
|
|
144
171
|
|
|
145
172
|
For Windows **CMD**, replace the example project ID before deliberately running a write:
|
|
146
173
|
|
|
@@ -182,7 +209,7 @@ for exact arguments and permission categories; no endpoint, header or arbitrary
|
|
|
182
209
|
`commands assist`, `search assist` and `issues count` use POST on the wire but remain ReadOnly:
|
|
183
210
|
they compute suggestions or counts without applying changes. Assist is not a dry run or a guarantee
|
|
184
211
|
that a later command will succeed. Required `--query` is preserved exactly; optional `--caret` is
|
|
185
|
-
between zero and its length. `commands apply` requires
|
|
212
|
+
between zero and its length. `commands apply` requires comma-separated distinct explicit issue IDs via
|
|
186
213
|
`--issues`, never an implicit search expansion. It has no run-as or silent mode. Count returns the
|
|
187
214
|
server's `count`, including `-1` (pending) or `null`; the CLI never polls automatically.
|
|
188
215
|
|
|
@@ -195,7 +222,7 @@ Project fields expose field types and settings without following bundle referenc
|
|
|
195
222
|
preserve polymorphic values, including scalar, null and array values. `issues fields set` accepts
|
|
196
223
|
an explicit `$type` and `value`: single/multi Enum, Build, Version, Owned, Group and User types;
|
|
197
224
|
State, Simple, Date, Period and Text types. References use explicit identity selectors (`id`,
|
|
198
|
-
`name`, and `login` for users);
|
|
225
|
+
`name`, and `login` for users); `fields set` performs no lookup of its own. Single values can use `null`,
|
|
199
226
|
multi values use `[]` to clear. Period values accept nonnegative 32-bit integer `minutes`
|
|
200
227
|
and/or `presentation`; dates use
|
|
201
228
|
integer Unix milliseconds. Text values use `{ "text": "..." }`. StateMachine fields instead
|
|
@@ -289,15 +316,16 @@ add six operations. The hierarchy commands read only the selected relationship a
|
|
|
289
316
|
recursively traverse descendants. A literal JSON null parent remains null; an empty body,
|
|
290
317
|
404 or malformed response is still an error. Article attachment upload requires one explicit
|
|
291
318
|
`--file`, the Update gate, and uses native multipart after checking that the file is regular.
|
|
292
|
-
It supports `--fields` for the response. No implicit file discovery
|
|
293
|
-
|
|
319
|
+
It supports `--fields` for the response. No implicit file discovery is provided, and upload never
|
|
320
|
+
grants permissions.
|
|
294
321
|
|
|
295
322
|
```powershell
|
|
296
323
|
npm run youtrack -- issues attachments download DEMO-1 1-1 --profile youtrack-dev
|
|
297
324
|
npm run youtrack -- issues attachments download DEMO-1 1-1 --name report.txt --max-bytes 1048576 --profile youtrack-dev
|
|
325
|
+
npm run youtrack -- article attachment download KB-A-1 7-1 --profile youtrack-dev
|
|
298
326
|
```
|
|
299
327
|
|
|
300
|
-
Issue attachment
|
|
328
|
+
Issue and article attachment downloads first read the exact attachment's fixed metadata, then request only
|
|
301
329
|
its returned URL. The file request sends neither Authorization nor cookies, follows no redirects,
|
|
302
330
|
and accepts only the configured origin and documented attachment path beneath its context.
|
|
303
331
|
External/CDN URLs fail rather than relaxing this policy. Signatures stay in memory and never
|
|
@@ -305,8 +333,9 @@ appear in metadata output, errors or the download result.
|
|
|
305
333
|
|
|
306
334
|
Files go beneath the selected profile's `AppDataDirectory/downloads`. `--name` must be a safe
|
|
307
335
|
single basename; the default prefixes the sanitized attachment name with its ID. Existing
|
|
308
|
-
filenames are never overwritten.
|
|
309
|
-
|
|
336
|
+
filenames are never overwritten. Downloads have no default byte ceiling. Optional `--max-bytes`
|
|
337
|
+
accepts a positive safe integer and enforces the caller-selected bound while streaming and against
|
|
338
|
+
Content-Length. Filename lengths are left to the filesystem. Core stages bytes in a fresh
|
|
310
339
|
private directory under this profile's `temp`, then hard-links only the complete identity-checked
|
|
311
340
|
file into `downloads`. Partial files are removed when their identities remain trusted. Output
|
|
312
341
|
contains only sanitized ID/name, local path, byte count and content type.
|
|
@@ -317,6 +346,60 @@ current-user-owned AppData; it cannot prevent every malicious same-account repla
|
|
|
317
346
|
last identity check. Errors report whether publication occurred and whether private staging cleanup
|
|
318
347
|
failed, without raw filesystem/service details. The local proof never invokes download or upload.
|
|
319
348
|
|
|
349
|
+
`article export <article> [--name <basename>]` (ReadOnly) saves the article content, with signed
|
|
350
|
+
URLs scrubbed like console output, as `downloads/<idReadable>.md` through the same no-overwrite
|
|
351
|
+
publication. Edit it and send it back with `article update <article> --body '{}' --content-file <path>`.
|
|
352
|
+
The result's `redacted: true` means the file contains `[redacted]` placeholders where console-output
|
|
353
|
+
scrubbing removed text (signed or credential-bearing URLs, undecodable URL-like text or the token);
|
|
354
|
+
sending it back unchanged would replace that text in YouTrack, so restore it first or edit that
|
|
355
|
+
article elsewhere.
|
|
356
|
+
The local `downloads list`, `downloads delete <name>` and `downloads clean` built-ins (ungated, no
|
|
357
|
+
network) show or remove saved files: only regular files directly in the selected profile's
|
|
358
|
+
`downloads` directory, never links, subdirectories, staging or other profiles.
|
|
359
|
+
|
|
360
|
+
## Issue batches
|
|
361
|
+
|
|
362
|
+
`issues batch validate --file <manifest>` (ReadOnly; sends no requests and never uses the token,
|
|
363
|
+
but like every service command runs against a configured profile) and `issues batch apply --file
|
|
364
|
+
<manifest>` (Update, checked before the file is read) accept a `.json` array of rows or a UTF-8 `.csv`
|
|
365
|
+
with a header row. A row is `action` (`create`/`update`), `issue` (update only, an exact ID, never a
|
|
366
|
+
search) and the same body fields as `issues create/update`. CSV columns are `action`, `issue`,
|
|
367
|
+
`project.id`, `project.shortName`, `summary`, `description` and `customFields` (a JSON array cell);
|
|
368
|
+
an empty cell omits the field, so clearing needs JSON. CSV syntax errors and unknown or repeated
|
|
369
|
+
columns fail as a whole; unknown keys and invalid rows fail with the row number. Either way nothing
|
|
370
|
+
is written. Name selectors are resolved per row during apply.
|
|
371
|
+
|
|
372
|
+
Apply runs rows in order, one request per write plus exact selector reads, without retries,
|
|
373
|
+
rollback or compensation; a batch is not atomic. It stops at the first unsuccessful row unless
|
|
374
|
+
`--continue-on-error` is given. Each row reports `completed` (with the write result), `failed`
|
|
375
|
+
(rejected before the write or with HTTP 4xx: not applied), `uncertain` (connectivity, 5xx or an
|
|
376
|
+
invalid response: it may have been applied) or `unattempted`; the overall `status` is `completed`
|
|
377
|
+
or `incomplete`, with counts. The command itself succeeds (exit code 0) once rows ran, so callers
|
|
378
|
+
must check `status`. `--failed-rows <name>.json` saves the `failed` and `unattempted` rows
|
|
379
|
+
as a manifest under `downloads` for deliberate resubmission; `uncertain` rows are left out and must
|
|
380
|
+
be checked in YouTrack first. A save failure is reported in `failedRows.error` without hiding row results.
|
|
381
|
+
|
|
382
|
+
## Compared with `yt` 0.22.2
|
|
383
|
+
|
|
384
|
+
The everyday issue and article workflows have explicit, typed commands:
|
|
385
|
+
- issue creation and updates with custom fields in one request;
|
|
386
|
+
- exact human-readable selectors;
|
|
387
|
+
- budgeted `issues list --all`;
|
|
388
|
+
- JSON/CSV batches;
|
|
389
|
+
- attachment downloads, article export and text-file inputs.
|
|
390
|
+
|
|
391
|
+
Deliberate differences:
|
|
392
|
+
- field types are never guessed and selectors never take the first match;
|
|
393
|
+
- field-value names are validated by YouTrack rather than pre-resolved;
|
|
394
|
+
- a failed batch never deletes created issues to compensate.
|
|
395
|
+
|
|
396
|
+
Not provided:
|
|
397
|
+
- project, user, group and role administration;
|
|
398
|
+
- deletion wrappers;
|
|
399
|
+
- burndown and velocity reports;
|
|
400
|
+
- interactive tables, themes, tutorials and aliases;
|
|
401
|
+
- stdin input (JSON-RPC owns stdin).
|
|
402
|
+
|
|
320
403
|
## Local proof and offline tests
|
|
321
404
|
|
|
322
405
|
After configuring a profile, explicitly run:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"article-extras-commands.d.ts","sourceRoot":"","sources":["../../src/article-extras-commands.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"article-extras-commands.d.ts","sourceRoot":"","sources":["../../src/article-extras-commands.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,qBAAqB,qDAiDjC,CAAC"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { command } from "@eyeauras/cli-factory";
|
|
2
2
|
import { requiredText } from "./client.js";
|
|
3
|
+
import { articleAttachmentDownloadCommand } from "./attachment-download-commands.js";
|
|
3
4
|
import { pagedRead, projectedRead, updateCommand, projectionOptions, readOptions } from "./cli-support.js";
|
|
4
5
|
import { getArticleAttachment, getChildArticle, getParentArticle, listArticleAttachments, listChildArticles, uploadArticleAttachment, } from "./article-extras.js";
|
|
5
6
|
export const articlesExtraChildren = [
|
|
6
|
-
command("attachment", "Inspect
|
|
7
|
+
command("attachment", "Inspect, upload or download one selected article attachment", [
|
|
8
|
+
articleAttachmentDownloadCommand,
|
|
7
9
|
pagedRead("list <article>", "List one page of attachment metadata without downloading files", listArticleAttachments),
|
|
8
10
|
projectedRead("get <article> <attachment>", "Read attachment metadata without downloading its contents", getArticleAttachment),
|
|
9
11
|
updateCommand("upload <article>", "Upload one selected regular file to an existing article", async (connection, { args, options }, context) => uploadArticleAttachment(connection, args.article, String(options.file), readOptions(options)), [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"article-extras-commands.js","sourceRoot":"","sources":["../../src/article-extras-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3G,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,OAAO,CAAC,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"article-extras-commands.js","sourceRoot":"","sources":["../../src/article-extras-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gCAAgC,EAAE,MAAM,mCAAmC,CAAC;AACrF,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3G,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,OAAO,CAAC,YAAY,EAAE,6DAA6D,EAAE;QACnF,gCAAgC;QAChC,SAAS,CACP,gBAAgB,EAChB,gEAAgE,EAChE,sBAAsB,CACvB;QACD,aAAa,CACX,4BAA4B,EAC5B,2DAA2D,EAC3D,oBAAoB,CACrB;QACD,aAAa,CACX,kBAAkB,EAClB,yDAAyD,EACzD,KAAK,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,CAC/C,uBAAuB,CACrB,UAAU,EACV,IAAI,CAAC,OAAO,EACZ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EACpB,WAAW,CAAC,OAAO,CAAC,CACrB,EACH;YACI,GAAG,iBAAiB;YACpB;gBACE,KAAK,EAAE,eAAe;gBACtB,WAAW,EAAE,4DAA4D;gBACzE,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC;aACnD;SACF,CACJ;KACF,CAAC;IACF,OAAO,CAAC,OAAO,EAAE,8DAA8D,EAAE;QAC/E,SAAS,CAAC,gBAAgB,EAAE,2CAA2C,EAAE,iBAAiB,CAAC;QAC3F,aAAa,CACX,uBAAuB,EACvB,gDAAgD,EAChD,eAAe,CAChB;KACF,CAAC;IACF,OAAO,CAAC,QAAQ,EAAE,6BAA6B,EAAE;QAC/C,aAAa,CACX,eAAe,EACf,gEAAgE,EAChE,gBAAgB,CACjB;KACF,CAAC;CACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"articles-commands.d.ts","sourceRoot":"","sources":["../../src/articles-commands.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"articles-commands.d.ts","sourceRoot":"","sources":["../../src/articles-commands.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,oBAAoB,qDA6ChC,CAAC;AAEF,eAAO,MAAM,uBAAuB,qDAInC,CAAC"}
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { command } from "@eyeauras/cli-factory";
|
|
2
2
|
import { articlesExtraChildren } from "./article-extras-commands.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { downloadName } from "./attachment-download.js";
|
|
4
|
+
import { pagedRead, projectedBodyUpdate, projectedRead, readCommand } from "./cli-support.js";
|
|
5
|
+
import { addArticleComment, createArticle, exportArticle, getArticle, getArticleComment, listArticleComments, listArticles, listProjectArticles, updateArticle, updateArticleComment, } from "./articles.js";
|
|
5
6
|
export const articlesRootCommands = [
|
|
6
7
|
command("article", "Read and write knowledge-base articles", [
|
|
7
8
|
...articlesExtraChildren,
|
|
8
9
|
pagedRead("list", "List one page of accessible articles", listArticles),
|
|
9
10
|
projectedRead("get <article>", "Read article content and parent identity", getArticle),
|
|
10
|
-
|
|
11
|
-
projectedBodyUpdate("
|
|
11
|
+
readCommand("export <article>", "Save article content under this profile's downloads directory without overwriting files", async (connection, { args, options }, context) => exportArticle(connection, args.article, context.appArguments.AppDataDirectory, typeof options.name === "string" ? options.name : undefined), [{ flags: "--name <basename>", description: "Optional safe filename (default: <idReadable>.md)", parse: downloadName }]),
|
|
12
|
+
projectedBodyUpdate("create", "Create an article with project.id, summary and optional content", createArticle, "content"),
|
|
13
|
+
projectedBodyUpdate("update <article>", "Update summary/content; null content clears it and omitted fields stay unchanged", updateArticle, "content"),
|
|
12
14
|
command("comment", "Read and write article comments", [
|
|
13
15
|
pagedRead("list <article>", "List one page of comments", listArticleComments),
|
|
14
16
|
projectedRead("get <article> <comment>", "Read an article comment", getArticleComment),
|
|
15
|
-
projectedBodyUpdate("add <article>", "Add an article comment with nonempty text", addArticleComment),
|
|
16
|
-
projectedBodyUpdate("update <article> <comment>", "Replace an article comment's text", updateArticleComment),
|
|
17
|
+
projectedBodyUpdate("add <article>", "Add an article comment with nonempty text", addArticleComment, "text"),
|
|
18
|
+
projectedBodyUpdate("update <article> <comment>", "Replace an article comment's text", updateArticleComment, "text"),
|
|
17
19
|
]),
|
|
18
20
|
]),
|
|
19
21
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"articles-commands.js","sourceRoot":"","sources":["../../src/articles-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"articles-commands.js","sourceRoot":"","sources":["../../src/articles-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,OAAO,CAAC,SAAS,EAAE,wCAAwC,EAAE;QAC3D,GAAG,qBAAqB;QACxB,SAAS,CAAC,MAAM,EAAE,sCAAsC,EAAE,YAAY,CAAC;QACvE,aAAa,CAAC,eAAe,EAAE,0CAA0C,EAAE,UAAU,CAAC;QACtF,WAAW,CACT,kBAAkB,EAClB,yFAAyF,EACzF,KAAK,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,aAAa,CAC7D,UAAU,EACV,IAAI,CAAC,OAAO,EACZ,OAAO,CAAC,YAAY,CAAC,gBAAgB,EACrC,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAC5D,EACD,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,mDAAmD,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CACxH;QACD,mBAAmB,CACjB,QAAQ,EACR,iEAAiE,EACjE,aAAa,EACb,SAAS,CACV;QACD,mBAAmB,CACjB,kBAAkB,EAClB,kFAAkF,EAClF,aAAa,EACb,SAAS,CACV;QACD,OAAO,CAAC,SAAS,EAAE,iCAAiC,EAAE;YACpD,SAAS,CAAC,gBAAgB,EAAE,2BAA2B,EAAE,mBAAmB,CAAC;YAC7E,aAAa,CAAC,yBAAyB,EAAE,yBAAyB,EAAE,iBAAiB,CAAC;YACtF,mBAAmB,CACjB,eAAe,EACf,2CAA2C,EAC3C,iBAAiB,EACjB,MAAM,CACP;YACD,mBAAmB,CACjB,4BAA4B,EAC5B,mCAAmC,EACnC,oBAAoB,EACpB,MAAM,CACP;SACF,CAAC;KACH,CAAC;CACH,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,OAAO,CAAC,SAAS,EAAE,yCAAyC,EAAE;QAC5D,SAAS,CAAC,gBAAgB,EAAE,wCAAwC,EAAE,mBAAmB,CAAC;KAC3F,CAAC;CACH,CAAC"}
|
package/dist/src/articles.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
import { type PublishedProfileFile } from "@eyeauras/cli-factory";
|
|
1
2
|
import { type Connection, type ProjectionOptions, type YouTrackObject } from "./client.js";
|
|
2
3
|
export declare const listArticles: (connection: Connection, options?: import("./client.js").PageOptions | undefined) => Promise<YouTrackObject[]>;
|
|
3
4
|
export declare const getArticle: (connection: Connection, articleID: string, options?: ProjectionOptions | undefined) => Promise<YouTrackObject>;
|
|
5
|
+
/**
|
|
6
|
+
* Save the scrubbed article content as a profile-owned file for a fetch/edit/update workflow.
|
|
7
|
+
* `redacted` warns that URL placeholders would replace the originals if the file were sent back.
|
|
8
|
+
*/
|
|
9
|
+
export declare function exportArticle(connection: Connection, articleID: string, appDataDirectory: string, name?: string): Promise<{
|
|
10
|
+
id: string;
|
|
11
|
+
redacted: boolean;
|
|
12
|
+
} & PublishedProfileFile>;
|
|
4
13
|
export declare function createArticle(connection: Connection, input: unknown, options?: ProjectionOptions): Promise<YouTrackObject | null>;
|
|
5
14
|
export declare function updateArticle(connection: Connection, articleID: string, input: unknown, options?: ProjectionOptions): Promise<YouTrackObject | null>;
|
|
6
15
|
export declare const listArticleComments: (connection: Connection, articleID: string, options?: import("./client.js").PageOptions | undefined) => Promise<YouTrackObject[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../../src/articles.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AAWrB,eAAO,MAAM,YAAY,gHAAsD,CAAC;AAChF,eAAO,MAAM,UAAU,iHAAiD,CAAC;AAEzE,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAahC;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAchC;AAED,eAAO,MAAM,mBAAmB,mIAG/B,CAAC;AACF,eAAO,MAAM,iBAAiB,oIAI7B,CAAC;AAEF,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAQhC;AAED,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAQhC;AAED,eAAO,MAAM,mBAAmB,mIAG/B,CAAC"}
|
|
1
|
+
{"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../../src/articles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EASL,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AAWrB,eAAO,MAAM,YAAY,gHAAsD,CAAC;AAChF,eAAO,MAAM,UAAU,iHAAiD,CAAC;AAEzE;;;GAGG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAAG,oBAAoB,CAAC,CAanE;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAahC;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAchC;AAED,eAAO,MAAM,mBAAmB,mIAG/B,CAAC;AACF,eAAO,MAAM,iBAAiB,oIAI7B,CAAC;AAEF,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAQhC;AAED,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAQhC;AAED,eAAO,MAAM,mBAAmB,mIAG/B,CAAC"}
|
package/dist/src/articles.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { saveProfileFile } from "@eyeauras/cli-factory";
|
|
1
2
|
import { encodedID, fields, mutate, mutationBody, narrative, nullableText, readCollectionAt, readObjectAt, } from "./client.js";
|
|
2
3
|
const articleListFields = "id,idReadable,summary,project(id,shortName),updated";
|
|
3
4
|
const articleDetailFields = `${articleListFields},content,parentArticle(id,idReadable),created`;
|
|
@@ -8,6 +9,24 @@ function articlePath(articleID) {
|
|
|
8
9
|
}
|
|
9
10
|
export const listArticles = readCollectionAt("api/articles", articleListFields);
|
|
10
11
|
export const getArticle = readObjectAt(articlePath, articleDetailFields);
|
|
12
|
+
/**
|
|
13
|
+
* Save the scrubbed article content as a profile-owned file for a fetch/edit/update workflow.
|
|
14
|
+
* `redacted` warns that URL placeholders would replace the originals if the file were sent back.
|
|
15
|
+
*/
|
|
16
|
+
export async function exportArticle(connection, articleID, appDataDirectory, name) {
|
|
17
|
+
const article = await getArticle(connection, articleID, { fields: "id,idReadable,content" });
|
|
18
|
+
const id = typeof article.idReadable === "string" ? article.idReadable : article.id;
|
|
19
|
+
if (typeof id !== "string" || !id || (article.content !== null && typeof article.content !== "string")) {
|
|
20
|
+
throw new Error("YouTrack returned an invalid article for export.");
|
|
21
|
+
}
|
|
22
|
+
const saved = await saveProfileFile({
|
|
23
|
+
appDataDirectory,
|
|
24
|
+
name: name ?? `${id.replace(/[^a-zA-Z0-9._-]/g, "_")}.md`,
|
|
25
|
+
content: article.content ?? "",
|
|
26
|
+
signal: connection.signal,
|
|
27
|
+
});
|
|
28
|
+
return { id, ...saved, redacted: article.content?.includes("[redacted]") ?? false };
|
|
29
|
+
}
|
|
11
30
|
export async function createArticle(connection, input, options = {}) {
|
|
12
31
|
const body = mutationBody(input, ["project", "summary", "content"]);
|
|
13
32
|
const project = mutationBody(body.project, ["id"]);
|
package/dist/src/articles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"articles.js","sourceRoot":"","sources":["../../src/articles.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"articles.js","sourceRoot":"","sources":["../../src/articles.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-download-commands.d.ts","sourceRoot":"","sources":["../../src/attachment-download-commands.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"attachment-download-commands.d.ts","sourceRoot":"","sources":["../../src/attachment-download-commands.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,yBAAyB,mDAWrC,CAAC;AAEF,eAAO,MAAM,gCAAgC,mDAW5C,CAAC"}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { readCommand } from "./cli-support.js";
|
|
2
|
-
import { downloadIssueAttachment, downloadLimit, downloadName } from "./attachment-download.js";
|
|
3
|
-
|
|
4
|
-
...(typeof options.name === "string" ? { name: options.name } : {}),
|
|
5
|
-
...(typeof options.maxBytes === "number" ? { maxBytes: options.maxBytes } : {}),
|
|
6
|
-
}), [
|
|
2
|
+
import { downloadArticleAttachment, downloadIssueAttachment, downloadLimit, downloadName, } from "./attachment-download.js";
|
|
3
|
+
const downloadOptions = [
|
|
7
4
|
{
|
|
8
5
|
flags: "--name <basename>",
|
|
9
6
|
description: "Optional safe filename; an existing name is never overwritten",
|
|
@@ -11,9 +8,16 @@ export const attachmentDownloadCommand = readCommand("download <issueID> <attach
|
|
|
11
8
|
},
|
|
12
9
|
{
|
|
13
10
|
flags: "--max-bytes <n>",
|
|
14
|
-
description: "
|
|
15
|
-
defaultValue: 25 * 1024 * 1024,
|
|
11
|
+
description: "Optional maximum transfer size in bytes (positive safe integer)",
|
|
16
12
|
parse: downloadLimit,
|
|
17
13
|
},
|
|
18
|
-
]
|
|
14
|
+
];
|
|
15
|
+
function downloadInput(options) {
|
|
16
|
+
return {
|
|
17
|
+
...(typeof options.name === "string" ? { name: options.name } : {}),
|
|
18
|
+
...(typeof options.maxBytes === "number" ? { maxBytes: options.maxBytes } : {}),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export const attachmentDownloadCommand = readCommand("download <issueID> <attachmentID>", "Download one attachment into this profile's downloads directory without overwriting files", async (connection, { args, options }, context) => downloadIssueAttachment(connection, args.issueID, args.attachmentID, context.appArguments.AppDataDirectory, downloadInput(options)), downloadOptions);
|
|
22
|
+
export const articleAttachmentDownloadCommand = readCommand("download <article> <attachment>", "Download one article attachment into this profile's downloads directory without overwriting files", async (connection, { args, options }, context) => downloadArticleAttachment(connection, args.article, args.attachment, context.appArguments.AppDataDirectory, downloadInput(options)), downloadOptions);
|
|
19
23
|
//# sourceMappingURL=attachment-download-commands.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-download-commands.js","sourceRoot":"","sources":["../../src/attachment-download-commands.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,
|
|
1
|
+
{"version":3,"file":"attachment-download-commands.js","sourceRoot":"","sources":["../../src/attachment-download-commands.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,aAAa,EACb,YAAY,GAEb,MAAM,0BAA0B,CAAC;AAElC,MAAM,eAAe,GAAG;IACtB;QACE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,+DAA+D;QAC5E,KAAK,EAAE,YAAY;KACpB;IACD;QACE,KAAK,EAAE,iBAAiB;QACxB,WAAW,EAAE,iEAAiE;QAC9E,KAAK,EAAE,aAAa;KACrB;CACF,CAAC;AAEF,SAAS,aAAa,CAAC,OAAgC;IACrD,OAAO;QACL,GAAG,CAAC,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,GAAG,CAAC,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAG,WAAW,CAClD,mCAAmC,EACnC,2FAA2F,EAC3F,KAAK,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,uBAAuB,CACvE,UAAU,EACV,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,YAAY,EACjB,OAAO,CAAC,YAAY,CAAC,gBAAgB,EACrC,aAAa,CAAC,OAAO,CAAC,CACvB,EACD,eAAe,CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,gCAAgC,GAAG,WAAW,CACzD,iCAAiC,EACjC,mGAAmG,EACnG,KAAK,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,yBAAyB,CACzE,UAAU,EACV,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,UAAU,EACf,OAAO,CAAC,YAAY,CAAC,gBAAgB,EACrC,aAAa,CAAC,OAAO,CAAC,CACvB,EACD,eAAe,CAChB,CAAC"}
|
|
@@ -13,4 +13,5 @@ export interface AttachmentDownloadResult {
|
|
|
13
13
|
export declare function downloadName(value: string): string;
|
|
14
14
|
export declare function downloadLimit(value: number | string): number;
|
|
15
15
|
export declare function downloadIssueAttachment(connection: Connection, issueID: string, attachmentID: string, appDataDirectory: string, options?: DownloadOptions): Promise<AttachmentDownloadResult>;
|
|
16
|
+
export declare function downloadArticleAttachment(connection: Connection, articleID: string, attachmentID: string, appDataDirectory: string, options?: DownloadOptions): Promise<AttachmentDownloadResult>;
|
|
16
17
|
//# sourceMappingURL=attachment-download.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-download.d.ts","sourceRoot":"","sources":["../../src/attachment-download.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"attachment-download.d.ts","sourceRoot":"","sources":["../../src/attachment-download.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,UAAU,EAEhB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAM5D;AAiED,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,wBAAwB,CAAC,CAGnC;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,wBAAwB,CAAC,CAGnC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ProfileFileError, publishProfileFile } from "@eyeauras/cli-factory";
|
|
2
|
-
import {
|
|
2
|
+
import { encodedID, getAttachmentDownloadMetadata, issuePath, youTrackUrl, } from "./client.js";
|
|
3
3
|
class DownloadError extends ProfileFileError {
|
|
4
4
|
}
|
|
5
5
|
export function downloadName(value) {
|
|
6
|
-
if (!value ||
|
|
6
|
+
if (!value || value === "." || value === ".." ||
|
|
7
7
|
/[<>:"/\\|?*\u0000-\u001f\u007f-\u009f\p{Cf}]/u.test(value) || /[. ]$/.test(value) ||
|
|
8
8
|
/^(?:con|prn|aux|nul|conin\$|conout\$|clock\$|com[1-9¹²³]|lpt[1-9¹²³])(?:[ .]|$)/i.test(value)) {
|
|
9
9
|
throw new Error("YouTrack download name must be one safe basename, without reserved paths or characters.");
|
|
@@ -12,8 +12,8 @@ export function downloadName(value) {
|
|
|
12
12
|
}
|
|
13
13
|
export function downloadLimit(value) {
|
|
14
14
|
const number = typeof value === "string" && /^\d+$/.test(value) ? Number(value) : value;
|
|
15
|
-
if (typeof number !== "number" || !Number.isSafeInteger(number) || number < 1
|
|
16
|
-
throw new Error("YouTrack max-bytes must be
|
|
15
|
+
if (typeof number !== "number" || !Number.isSafeInteger(number) || number < 1) {
|
|
16
|
+
throw new Error("YouTrack max-bytes must be a positive safe integer.");
|
|
17
17
|
}
|
|
18
18
|
return number;
|
|
19
19
|
}
|
|
@@ -67,8 +67,8 @@ function redact(value, secrets) {
|
|
|
67
67
|
}
|
|
68
68
|
return value;
|
|
69
69
|
}
|
|
70
|
-
function filenamePart(value, fallback
|
|
71
|
-
return value.replace(/[^a-zA-Z0-9._-]/g, "_").
|
|
70
|
+
function filenamePart(value, fallback) {
|
|
71
|
+
return value.replace(/[^a-zA-Z0-9._-]/g, "_").replace(/^\.+|[. ]+$/g, "") || fallback;
|
|
72
72
|
}
|
|
73
73
|
function contentType(value, secrets) {
|
|
74
74
|
const type = value?.split(";", 1)[0]?.trim() ?? "";
|
|
@@ -76,17 +76,25 @@ function contentType(value, secrets) {
|
|
|
76
76
|
? type : "application/octet-stream";
|
|
77
77
|
}
|
|
78
78
|
export async function downloadIssueAttachment(connection, issueID, attachmentID, appDataDirectory, options = {}) {
|
|
79
|
+
const path = `${issuePath(issueID)}/attachments/${encodedID(attachmentID, "attachment ID")}`;
|
|
80
|
+
return downloadAttachment(connection, path, attachmentID, appDataDirectory, options);
|
|
81
|
+
}
|
|
82
|
+
export async function downloadArticleAttachment(connection, articleID, attachmentID, appDataDirectory, options = {}) {
|
|
83
|
+
const path = `api/articles/${encodedID(articleID, "article ID")}/attachments/${encodedID(attachmentID, "attachment ID")}`;
|
|
84
|
+
return downloadAttachment(connection, path, attachmentID, appDataDirectory, options);
|
|
85
|
+
}
|
|
86
|
+
async function downloadAttachment(connection, attachmentPath, attachmentID, appDataDirectory, options) {
|
|
79
87
|
const requestedName = options.name === undefined ? undefined : downloadName(options.name);
|
|
80
|
-
const maxBytes =
|
|
88
|
+
const maxBytes = options.maxBytes === undefined ? undefined : downloadLimit(options.maxBytes);
|
|
81
89
|
try {
|
|
82
|
-
const metadata = await
|
|
90
|
+
const metadata = await getAttachmentDownloadMetadata(connection, attachmentPath);
|
|
83
91
|
if (metadata.id !== attachmentID) {
|
|
84
92
|
throw new DownloadError("YouTrack returned a different attachment identity for the download.");
|
|
85
93
|
}
|
|
86
94
|
const { url, secrets } = attachmentUrl(connection, metadata.url);
|
|
87
|
-
const id = filenamePart(redact(metadata.id, secrets), "attachment"
|
|
95
|
+
const id = filenamePart(redact(metadata.id, secrets), "attachment");
|
|
88
96
|
const name = requestedName ??
|
|
89
|
-
downloadName(`${id}-${filenamePart(redact(metadata.name, secrets), "attachment"
|
|
97
|
+
downloadName(`${id}-${filenamePart(redact(metadata.name, secrets), "attachment")}`);
|
|
90
98
|
if (redact(name, secrets) !== name || redact(appDataDirectory, secrets) !== appDataDirectory) {
|
|
91
99
|
throw new DownloadError("YouTrack download destination must not contain reflected credentials or signatures.");
|
|
92
100
|
}
|
|
@@ -112,7 +120,7 @@ export async function downloadIssueAttachment(connection, issueID, attachmentID,
|
|
|
112
120
|
if (length !== null && (!/^\d+$/.test(length) || !Number.isSafeInteger(declared))) {
|
|
113
121
|
throw new DownloadError("YouTrack attachment has an invalid Content-Length.");
|
|
114
122
|
}
|
|
115
|
-
if (declared !== undefined && declared > maxBytes) {
|
|
123
|
+
if (maxBytes !== undefined && declared !== undefined && declared > maxBytes) {
|
|
116
124
|
throw new DownloadError("YouTrack attachment exceeds the configured byte limit.");
|
|
117
125
|
}
|
|
118
126
|
type = contentType(response.headers.get("content-type") ?? metadata.mimeType, secrets);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-download.js","sourceRoot":"","sources":["../../src/attachment-download.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"attachment-download.js","sourceRoot":"","sources":["../../src/attachment-download.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EACL,SAAS,EACT,6BAA6B,EAC7B,SAAS,EAET,WAAW,GACZ,MAAM,aAAa,CAAC;AAerB,MAAM,aAAc,SAAQ,gBAAgB;CAAG;AAE/C,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,IAAI;QACzC,+CAA+C,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAClF,kFAAkF,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACnG,MAAM,IAAI,KAAK,CAAC,yFAAyF,CAAC,CAAC;IAC7G,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAsB;IAClD,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACxF,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9E,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,UAAsB,EAAE,KAAa;IAC1D,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,sFAAsF;QACtF,yCAAyC,CAC1C,CAAC;IACF,IAAI,CAAC;QACH,IAAI,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACjE,MAAM,OAAO,CAAC;QAChB,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;QACxC,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;QACxF,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,MAAM,OAAO,CAAC;QAChB,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5D,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,IAAI,IAAI,6BAA6B,CAAC,IAAI,CAAC,MAAM,CAAC;YAC1F,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC,EAAE,CAAC;YACtF,MAAM,OAAO,CAAC;QAChB,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACjC,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,IAAI;YACxG,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,QAAQ,YAAY,CAAC,EAAE,CAAC;YAC3D,MAAM,OAAO,CAAC;QAChB,CAAC;QACD,MAAM,aAAa,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,eAAe,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;aACnD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;aAC7D,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,UAAU,GAAG;YACjB,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC;YAC1F,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;SAC3F,CAAC;QACF,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC5C,CAAC,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YAC7F,MAAM,OAAO,CAAC;QAChB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,OAAO,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,KAAa,EAAE,OAAiB;IAC9C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,KAAa,EAAE,QAAgB;IACnD,OAAO,KAAK,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAC;AACxF,CAAC;AAED,SAAS,WAAW,CAAC,KAAoB,EAAE,OAAiB;IAC1D,MAAM,IAAI,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACnD,OAAO,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI,gDAAgD,CAAC,IAAI,CAAC,IAAI,CAAC;QAC1G,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,0BAA0B,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,UAAsB,EACtB,OAAe,EACf,YAAoB,EACpB,gBAAwB,EACxB,OAAO,GAAoB,EAAE;IAE7B,MAAM,IAAI,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,gBAAgB,SAAS,CAAC,YAAY,EAAE,eAAe,CAAC,EAAE,CAAC;IAC7F,OAAO,kBAAkB,CAAC,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,UAAsB,EACtB,SAAiB,EACjB,YAAoB,EACpB,gBAAwB,EACxB,OAAO,GAAoB,EAAE;IAE7B,MAAM,IAAI,GAAG,gBAAgB,SAAS,CAAC,SAAS,EAAE,YAAY,CAAC,gBAAgB,SAAS,CAAC,YAAY,EAAE,eAAe,CAAC,EAAE,CAAC;IAC1H,OAAO,kBAAkB,CAAC,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;AACvF,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,UAAsB,EACtB,cAAsB,EACtB,YAAoB,EACpB,gBAAwB,EACxB,OAAwB;IAExB,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1F,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9F,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,6BAA6B,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QACjF,IAAI,QAAQ,CAAC,EAAE,KAAK,YAAY,EAAE,CAAC;YACjC,MAAM,IAAI,aAAa,CAAC,qEAAqE,CAAC,CAAC;QACjG,CAAC;QACD,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,aAAa;YACxB,YAAY,CAAC,GAAG,EAAE,IAAI,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;QACtF,IAAI,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,gBAAgB,EAAE,OAAO,CAAC,KAAK,gBAAgB,EAAE,CAAC;YAC7F,MAAM,IAAI,aAAa,CACrB,qFAAqF,CACtF,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,GAAG,0BAA0B,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC;YACrC,gBAAgB;YAChB,IAAI;YACJ,QAAQ;YACR,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE;gBAC9D,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,EAAE,MAAM,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,UAAU,EAAE;gBAC9E,WAAW,EAAE,MAAM;gBACnB,QAAQ,EAAE,OAAO;gBACjB,GAAG,CAAC,UAAU,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;aAC1E,CAAC;YACF,eAAe,CAAC,QAAQ;gBACtB,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBAC5C,MAAM,IAAI,aAAa,CAAC,6CAA6C,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;gBAC5F,CAAC;gBACD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;gBACtD,MAAM,QAAQ,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC9D,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;oBAClF,MAAM,IAAI,aAAa,CAAC,oDAAoD,CAAC,CAAC;gBAChF,CAAC;gBACD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,GAAG,QAAQ,EAAE,CAAC;oBAC5E,MAAM,IAAI,aAAa,CAAC,wDAAwD,CAAC,CAAC;gBACpF,CAAC;gBACD,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACzF,CAAC;SACF,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC/E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,KAAK,YAAY,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,aAAa,CACjE,sGAAsG,CACvG,CAAC;IACJ,CAAC;AACH,CAAC"}
|