@meltemi/diagrams-cli 0.0.0-stage → 1.9.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.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -2
  3. package/dist/assets-command.d.ts +16 -0
  4. package/dist/assets-command.d.ts.map +1 -0
  5. package/dist/assets-command.js +145 -0
  6. package/dist/assets-command.js.map +1 -0
  7. package/dist/assist-command.d.ts +19 -0
  8. package/dist/assist-command.d.ts.map +1 -0
  9. package/dist/assist-command.js +268 -0
  10. package/dist/assist-command.js.map +1 -0
  11. package/dist/auth-command.d.ts +14 -0
  12. package/dist/auth-command.d.ts.map +1 -0
  13. package/dist/auth-command.js +233 -0
  14. package/dist/auth-command.js.map +1 -0
  15. package/dist/bin.d.ts +3 -0
  16. package/dist/bin.d.ts.map +1 -0
  17. package/dist/bin.js +60 -0
  18. package/dist/bin.js.map +1 -0
  19. package/dist/build-command.d.ts +23 -0
  20. package/dist/build-command.d.ts.map +1 -0
  21. package/dist/build-command.js +123 -0
  22. package/dist/build-command.js.map +1 -0
  23. package/dist/cli.d.ts +46 -0
  24. package/dist/cli.d.ts.map +1 -0
  25. package/dist/cli.js +823 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/cloud-client.d.ts +246 -0
  28. package/dist/cloud-client.d.ts.map +1 -0
  29. package/dist/cloud-client.js +591 -0
  30. package/dist/cloud-client.js.map +1 -0
  31. package/dist/cloud-command.d.ts +56 -0
  32. package/dist/cloud-command.d.ts.map +1 -0
  33. package/dist/cloud-command.js +81 -0
  34. package/dist/cloud-command.js.map +1 -0
  35. package/dist/cloud-context.d.ts +106 -0
  36. package/dist/cloud-context.d.ts.map +1 -0
  37. package/dist/cloud-context.js +185 -0
  38. package/dist/cloud-context.js.map +1 -0
  39. package/dist/cloud-errors.d.ts +37 -0
  40. package/dist/cloud-errors.d.ts.map +1 -0
  41. package/dist/cloud-errors.js +46 -0
  42. package/dist/cloud-errors.js.map +1 -0
  43. package/dist/cloud-host.d.ts +72 -0
  44. package/dist/cloud-host.d.ts.map +1 -0
  45. package/dist/cloud-host.js +129 -0
  46. package/dist/cloud-host.js.map +1 -0
  47. package/dist/cloud-manifest.d.ts +12 -0
  48. package/dist/cloud-manifest.d.ts.map +1 -0
  49. package/dist/cloud-manifest.js +21 -0
  50. package/dist/cloud-manifest.js.map +1 -0
  51. package/dist/cloud-paths.d.ts +48 -0
  52. package/dist/cloud-paths.d.ts.map +1 -0
  53. package/dist/cloud-paths.js +104 -0
  54. package/dist/cloud-paths.js.map +1 -0
  55. package/dist/credentials.d.ts +107 -0
  56. package/dist/credentials.d.ts.map +1 -0
  57. package/dist/credentials.js +243 -0
  58. package/dist/credentials.js.map +1 -0
  59. package/dist/export-command.d.ts +35 -0
  60. package/dist/export-command.d.ts.map +1 -0
  61. package/dist/export-command.js +524 -0
  62. package/dist/export-command.js.map +1 -0
  63. package/dist/import-command.d.ts +20 -0
  64. package/dist/import-command.d.ts.map +1 -0
  65. package/dist/import-command.js +254 -0
  66. package/dist/import-command.js.map +1 -0
  67. package/dist/index.d.ts +4 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +4 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/init-command.d.ts +28 -0
  72. package/dist/init-command.d.ts.map +1 -0
  73. package/dist/init-command.js +199 -0
  74. package/dist/init-command.js.map +1 -0
  75. package/dist/login-listener.d.ts +58 -0
  76. package/dist/login-listener.d.ts.map +1 -0
  77. package/dist/login-listener.js +173 -0
  78. package/dist/login-listener.js.map +1 -0
  79. package/dist/messages/en.d.ts +533 -0
  80. package/dist/messages/en.d.ts.map +1 -0
  81. package/dist/messages/en.js +803 -0
  82. package/dist/messages/en.js.map +1 -0
  83. package/dist/messages/es.d.ts +3 -0
  84. package/dist/messages/es.d.ts.map +1 -0
  85. package/dist/messages/es.js +764 -0
  86. package/dist/messages/es.js.map +1 -0
  87. package/dist/messages/index.d.ts +442 -0
  88. package/dist/messages/index.d.ts.map +1 -0
  89. package/dist/messages/index.js +42 -0
  90. package/dist/messages/index.js.map +1 -0
  91. package/dist/messages/push-pull-en.d.ts +84 -0
  92. package/dist/messages/push-pull-en.d.ts.map +1 -0
  93. package/dist/messages/push-pull-en.js +146 -0
  94. package/dist/messages/push-pull-en.js.map +1 -0
  95. package/dist/messages/push-pull-es.d.ts +7 -0
  96. package/dist/messages/push-pull-es.d.ts.map +1 -0
  97. package/dist/messages/push-pull-es.js +144 -0
  98. package/dist/messages/push-pull-es.js.map +1 -0
  99. package/dist/open-url.d.ts +11 -0
  100. package/dist/open-url.d.ts.map +1 -0
  101. package/dist/open-url.js +36 -0
  102. package/dist/open-url.js.map +1 -0
  103. package/dist/plugins-command.d.ts +15 -0
  104. package/dist/plugins-command.d.ts.map +1 -0
  105. package/dist/plugins-command.js +106 -0
  106. package/dist/plugins-command.js.map +1 -0
  107. package/dist/preview.d.ts +54 -0
  108. package/dist/preview.d.ts.map +1 -0
  109. package/dist/preview.js +249 -0
  110. package/dist/preview.js.map +1 -0
  111. package/dist/project-errors.d.ts +17 -0
  112. package/dist/project-errors.d.ts.map +1 -0
  113. package/dist/project-errors.js +85 -0
  114. package/dist/project-errors.js.map +1 -0
  115. package/dist/projects-command.d.ts +13 -0
  116. package/dist/projects-command.d.ts.map +1 -0
  117. package/dist/projects-command.js +85 -0
  118. package/dist/projects-command.js.map +1 -0
  119. package/dist/publish-command.d.ts +41 -0
  120. package/dist/publish-command.d.ts.map +1 -0
  121. package/dist/publish-command.js +311 -0
  122. package/dist/publish-command.js.map +1 -0
  123. package/dist/pull-command.d.ts +21 -0
  124. package/dist/pull-command.d.ts.map +1 -0
  125. package/dist/pull-command.js +300 -0
  126. package/dist/pull-command.js.map +1 -0
  127. package/dist/push-command.d.ts +31 -0
  128. package/dist/push-command.d.ts.map +1 -0
  129. package/dist/push-command.js +391 -0
  130. package/dist/push-command.js.map +1 -0
  131. package/dist/push-review.d.ts +16 -0
  132. package/dist/push-review.d.ts.map +1 -0
  133. package/dist/push-review.js +72 -0
  134. package/dist/push-review.js.map +1 -0
  135. package/dist/push-set.d.ts +126 -0
  136. package/dist/push-set.d.ts.map +1 -0
  137. package/dist/push-set.js +289 -0
  138. package/dist/push-set.js.map +1 -0
  139. package/dist/push-validation.d.ts +20 -0
  140. package/dist/push-validation.d.ts.map +1 -0
  141. package/dist/push-validation.js +70 -0
  142. package/dist/push-validation.js.map +1 -0
  143. package/dist/redact.d.ts +9 -0
  144. package/dist/redact.d.ts.map +1 -0
  145. package/dist/redact.js +22 -0
  146. package/dist/redact.js.map +1 -0
  147. package/dist/review-command.d.ts +44 -0
  148. package/dist/review-command.d.ts.map +1 -0
  149. package/dist/review-command.js +348 -0
  150. package/dist/review-command.js.map +1 -0
  151. package/package.json +56 -3
  152. package/templates/c4/diagrams/views.meltemi +16 -0
  153. package/templates/c4/models/system.meltemi +23 -0
  154. package/templates/ci/github.yml +96 -0
  155. package/templates/ci/gitlab.yml +53 -0
  156. package/templates/flow/diagrams/overview.meltemi +15 -0
  157. package/templates/free/diagrams/slide.meltemi +39 -0
  158. package/templates/purchase/diagrams/architecture.meltemi +36 -0
  159. package/templates/purchase/diagrams/executive.meltemi +52 -0
  160. package/templates/purchase/diagrams/payment.meltemi +42 -0
  161. package/templates/purchase/models/commerce.meltemi +30 -0
  162. package/templates/purchase/stories/purchase.meltemi +38 -0
  163. package/templates/sequence/diagrams/sign-in.meltemi +36 -0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * A cloud project as a `ProjectHost` (`cli-cloud`, "Projects and review against the cloud"): what
3
+ * `review --base cloud[:<n>]` compares the folder with, as `gitRevisionHost` is what `review
4
+ * --base <revision>` compares it with.
5
+ *
6
+ * A `ProjectHost` is synchronous, so the cloud is read once, up front: the project's files (or a
7
+ * version's) and the images and fonts they reference, each blob once. Every path the service
8
+ * answers then goes through the path rule of the cloud (`isCleanPath`) and must resolve inside the
9
+ * project's root; one that does not is `pull.unsafe-path` and nothing is compared. The only paths
10
+ * left out without a word are the losers of a name collision (`<path>~<id>`, listed in the
11
+ * answer's `collisions`): the service keeps them out of copies and restores for the same reason.
12
+ *
13
+ * The host is rooted at the local project root, like the git host is rooted at the repository:
14
+ * `<root>/<path>` answers the fetched text or bytes and `readDirectory` is made from the path set.
15
+ */
16
+ import { createMemoryHost, joinPath } from "@meltemi/diagrams-project";
17
+ import { collisionLosers, insideFolder, pathProblem, printablePath, setProblems, } from "./cloud-paths.js";
18
+ import { CloudError, isCloudError } from "./cloud-errors.js";
19
+ /** The most blobs fetched at once. */
20
+ const BLOB_CONCURRENCY = 4;
21
+ /**
22
+ * Whether a path the cloud answered is NOT safe to put under `root` by itself, with the checks
23
+ * `pull` makes (`cloud-paths.ts`): it breaks the cloud's path rule, a name of it could not be kept
24
+ * on Windows (a device name such as `con` or `com1.txt`, a name that ends with a dot or a space), or
25
+ * joined to the root it leaves it (or is the root itself). What only a set of paths can show
26
+ * (`setProblems`) is checked by `checkCloudPaths`.
27
+ */
28
+ export function unsafeCloudPath(root, path) {
29
+ return pathProblem(path) !== undefined || insideFolder(root, path) === undefined;
30
+ }
31
+ /**
32
+ * Fails with `pull.unsafe-path` naming the first of `paths` that is not safe under `root`: one that
33
+ * `unsafeCloudPath` refuses, or that cannot be written beside the others, because it differs from
34
+ * another only in letter case (one overwrites the other on Windows and macOS) or is a file where
35
+ * another path needs a folder. The path is named as `pull` names it, escaped (`printablePath`), as it
36
+ * is the cloud's to choose and the terminal is the person's.
37
+ */
38
+ export function checkCloudPaths(root, paths) {
39
+ const all = [...paths];
40
+ const together = setProblems(all.filter((path) => pathProblem(path) === undefined));
41
+ for (const path of all) {
42
+ if (!unsafeCloudPath(root, path) && !together.has(path))
43
+ continue;
44
+ const shown = printablePath(path);
45
+ throw new CloudError("pull.unsafe-path", `The cloud project holds ${JSON.stringify(shown)}, which is not a safe path inside the folder.`, { details: { path: shown } });
46
+ }
47
+ }
48
+ /** Runs `task` over `items`, at most `limit` at a time; the first failure is the one thrown. */
49
+ async function pooled(items, limit, task) {
50
+ const results = new Array(items.length);
51
+ let next = 0;
52
+ let failure;
53
+ let failed = false;
54
+ const worker = async () => {
55
+ while (!failed && next < items.length) {
56
+ const index = next++;
57
+ try {
58
+ results[index] = await task(items[index]);
59
+ }
60
+ catch (error) {
61
+ if (!failed) {
62
+ failed = true;
63
+ failure = error;
64
+ }
65
+ }
66
+ }
67
+ };
68
+ await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
69
+ if (failed)
70
+ throw failure;
71
+ return results;
72
+ }
73
+ /**
74
+ * Reads a cloud project once: its current files, or version `version`'s, and the blobs they
75
+ * reference. `root` is the folder the paths are checked against (`pull.unsafe-path`, before any
76
+ * blob is fetched). An unknown version is `version.not-found` naming it; an unknown project,
77
+ * `project.not-found`.
78
+ */
79
+ export async function fetchCloudSnapshot(client, options) {
80
+ const { project, root, version } = options;
81
+ let answer;
82
+ try {
83
+ answer =
84
+ version === undefined
85
+ ? await client.files(project)
86
+ : await client.readVersion(project, version);
87
+ }
88
+ catch (error) {
89
+ if (isCloudError(error, "version.not-found")) {
90
+ throw new CloudError(error.code, error.message, {
91
+ status: error.status,
92
+ details: { ...error.details, project, version },
93
+ });
94
+ }
95
+ throw error;
96
+ }
97
+ // The losers of a name collision (`<path>~<id>`) are display names: left out, as pull and push do.
98
+ const losers = collisionLosers([...Object.keys(answer.files), ...Object.keys(answer.binaries)], "collisions" in answer ? answer.collisions : []);
99
+ const files = new Map(Object.entries(answer.files).filter(([path]) => !losers.has(path)));
100
+ const hashes = new Map(Object.entries(answer.binaries).filter(([path]) => !losers.has(path)));
101
+ checkCloudPaths(root, [...files.keys(), ...hashes.keys()]);
102
+ const wanted = [...new Set(hashes.values())];
103
+ const fetched = await pooled(wanted, BLOB_CONCURRENCY, (hash) => client.blob(project, hash));
104
+ const bytesOf = new Map(wanted.map((hash, index) => [hash, fetched[index]]));
105
+ return {
106
+ revision: "revision" in answer ? answer.revision : undefined,
107
+ version,
108
+ files,
109
+ binaries: new Map([...hashes].map(([path, hash]) => [path, { hash, bytes: bytesOf.get(hash) }])),
110
+ skipped: [...new Set([...Object.keys(answer.files), ...Object.keys(answer.binaries)])].filter((path) => losers.has(path)),
111
+ };
112
+ }
113
+ /** The host of a snapshot, rooted at `root`: `<root>/<path>` is the file the cloud holds there. */
114
+ export function cloudSnapshotHost(root, snapshot) {
115
+ const contents = {};
116
+ for (const [path, text] of snapshot.files)
117
+ contents[joinPath(root, path)] = text;
118
+ for (const [path, binary] of snapshot.binaries)
119
+ contents[joinPath(root, path)] = binary.bytes;
120
+ return createMemoryHost(contents);
121
+ }
122
+ /**
123
+ * The host of a cloud project (`project`, its current files or those of `version`) rooted at the
124
+ * local project root `root`, filled by one prefetch (`fetchCloudSnapshot`).
125
+ */
126
+ export async function cloudHost(client, options) {
127
+ return cloudSnapshotHost(options.root, await fetchCloudSnapshot(client, options));
128
+ }
129
+ //# sourceMappingURL=cloud-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-host.js","sourceRoot":"","sources":["../src/cloud-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The `cloud` field of `project.json` (`cli-cloud`, "Push" and "Pull"): `{ "host": …, "project": … }`,
3
+ * written by `push --create` and `pull` through `setJsonObjectField`, which keeps the file's
4
+ * indentation, line endings and everything else byte for byte.
5
+ */
6
+ /**
7
+ * The text of a manifest with its `cloud` field set to the service and the cloud project: replaced
8
+ * when it is there (and unchanged when it is already these values), else added after the last field.
9
+ * A byte order mark stays. Throws when the text is not a JSON object.
10
+ */
11
+ export declare function withCloudField(text: string, host: string, project: string): string;
12
+ //# sourceMappingURL=cloud-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-manifest.d.ts","sourceRoot":"","sources":["../src/cloud-manifest.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKlF"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The `cloud` field of `project.json` (`cli-cloud`, "Push" and "Pull"): `{ "host": …, "project": … }`,
3
+ * written by `push --create` and `pull` through `setJsonObjectField`, which keeps the file's
4
+ * indentation, line endings and everything else byte for byte.
5
+ */
6
+ import { setJsonObjectField } from "@meltemi/diagrams-editor";
7
+ import { applyTextEdits } from "@meltemi/diagrams-language";
8
+ /** The byte order mark, which a Windows editor may put in front of a JSON file. */
9
+ const BYTE_ORDER_MARK = 0xfeff;
10
+ /**
11
+ * The text of a manifest with its `cloud` field set to the service and the cloud project: replaced
12
+ * when it is there (and unchanged when it is already these values), else added after the last field.
13
+ * A byte order mark stays. Throws when the text is not a JSON object.
14
+ */
15
+ export function withCloudField(text, host, project) {
16
+ const bom = text.charCodeAt(0) === BYTE_ORDER_MARK;
17
+ const body = bom ? text.slice(1) : text;
18
+ const edited = applyTextEdits(body, setJsonObjectField(body, "cloud", { host, project }));
19
+ return bom ? String.fromCharCode(BYTE_ORDER_MARK) + edited : edited;
20
+ }
21
+ //# sourceMappingURL=cloud-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-manifest.js","sourceRoot":"","sources":["../src/cloud-manifest.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,mFAAmF;AACnF,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,IAAY,EAAE,OAAe;IACxE,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,eAAe,CAAC;IACnD,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxC,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAC1F,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AACtE,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * What a path of a cloud project must be before it may be written under a folder (`cli-cloud`,
3
+ * "Pull"): one rule for `pull` and for every command that reads a cloud project into a folder's
4
+ * place (`review --base cloud`).
5
+ *
6
+ * The cloud already refuses every path that breaks its path rule, so what arrives is what the
7
+ * service kept; the command line does not take that on trust, because the folder is the person's
8
+ * and a project can be written by anybody who edits it. A path is refused when
9
+ *
10
+ * - it is not already in canonical form (`isCleanPath`: relative, `/`-separated, no `..`, nothing
11
+ * hidden, no `:`, at most 12 names of at most 100 plain ASCII characters);
12
+ * - a name could not be written safely on Windows: it ends with a dot or a space (Windows drops
13
+ * both, so `a.` would be `a`) or is a device name (`con`, `nul`, `com1`, `lpt1`, ... with or
14
+ * without an extension);
15
+ * - it resolves outside the folder (`insideFolder`), which the rule above already rules out and
16
+ * which is checked again on the real, resolved path anyway;
17
+ * - in a set of paths, it differs from another only in letter case (one overwrites the other on
18
+ * Windows and macOS), or is a file where another path needs a folder.
19
+ */
20
+ /** Why a path is not safe: the cloud's rule, or a name Windows cannot keep. */
21
+ export type PathProblem = "rule" | "windows-name" | "windows-dot";
22
+ /** Why a path is not safe in a set of paths. */
23
+ export type SetProblem = "letter-case" | "file-and-folder";
24
+ /** Why one path cannot be written safely anywhere, or undefined when it can. */
25
+ export declare function pathProblem(path: string): PathProblem | undefined;
26
+ /**
27
+ * The paths of a set that cannot be written beside the others, each with why: the later of two
28
+ * paths that differ only in letter case, and a path that is also the folder of another one.
29
+ */
30
+ export declare function setProblems(paths: Iterable<string>): Map<string, SetProblem>;
31
+ /**
32
+ * A path the cloud answered, safe to print: control characters and line separators (an escape
33
+ * sequence in a name would reach the person's terminal) are written as `\uXXXX`. A path that
34
+ * passes the path rule has none.
35
+ */
36
+ export declare function printablePath(path: string): string;
37
+ /**
38
+ * The paths among `paths` that are the losers of a name collision: those the service lists as
39
+ * `shown` in `collisions`, and any `<path>~<id>` whose `<path>` is a valid path. The service shows
40
+ * such a path in its answers but never keeps one; it is never written and never sent.
41
+ */
42
+ export declare function collisionLosers(paths: Iterable<string>, collisions: readonly unknown[]): Set<string>;
43
+ /**
44
+ * Where a project path lands under a folder, as a native path, or undefined when the resolved
45
+ * result is not inside the folder (or is the folder itself). `folder` is absolute.
46
+ */
47
+ export declare function insideFolder(folder: string, path: string): string | undefined;
48
+ //# sourceMappingURL=cloud-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-paths.d.ts","sourceRoot":"","sources":["../src/cloud-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,+EAA+E;AAC/E,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,cAAc,GAAG,aAAa,CAAC;AAClE,gDAAgD;AAChD,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,iBAAiB,CAAC;AAK3D,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAOjE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAkB5E;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKlD;AAKD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EACvB,UAAU,EAAE,SAAS,OAAO,EAAE,GAC7B,GAAG,CAAC,MAAM,CAAC,CAcb;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO7E"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * What a path of a cloud project must be before it may be written under a folder (`cli-cloud`,
3
+ * "Pull"): one rule for `pull` and for every command that reads a cloud project into a folder's
4
+ * place (`review --base cloud`).
5
+ *
6
+ * The cloud already refuses every path that breaks its path rule, so what arrives is what the
7
+ * service kept; the command line does not take that on trust, because the folder is the person's
8
+ * and a project can be written by anybody who edits it. A path is refused when
9
+ *
10
+ * - it is not already in canonical form (`isCleanPath`: relative, `/`-separated, no `..`, nothing
11
+ * hidden, no `:`, at most 12 names of at most 100 plain ASCII characters);
12
+ * - a name could not be written safely on Windows: it ends with a dot or a space (Windows drops
13
+ * both, so `a.` would be `a`) or is a device name (`con`, `nul`, `com1`, `lpt1`, ... with or
14
+ * without an extension);
15
+ * - it resolves outside the folder (`insideFolder`), which the rule above already rules out and
16
+ * which is checked again on the real, resolved path anyway;
17
+ * - in a set of paths, it differs from another only in letter case (one overwrites the other on
18
+ * Windows and macOS), or is a file where another path needs a folder.
19
+ */
20
+ import { isAbsolute, relative, resolve, sep } from "node:path";
21
+ import { isCleanPath } from "@meltemi/diagrams-project";
22
+ /** The device names Windows reserves, with or without an extension. */
23
+ const DEVICE_NAME = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
24
+ /** Why one path cannot be written safely anywhere, or undefined when it can. */
25
+ export function pathProblem(path) {
26
+ if (!isCleanPath(path))
27
+ return "rule";
28
+ for (const name of path.split("/")) {
29
+ if (/[. ]$/.test(name))
30
+ return "windows-dot";
31
+ if (DEVICE_NAME.test(name))
32
+ return "windows-name";
33
+ }
34
+ return undefined;
35
+ }
36
+ /**
37
+ * The paths of a set that cannot be written beside the others, each with why: the later of two
38
+ * paths that differ only in letter case, and a path that is also the folder of another one.
39
+ */
40
+ export function setProblems(paths) {
41
+ const sorted = [...new Set(paths)].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
42
+ const problems = new Map();
43
+ const seen = new Set();
44
+ const folders = new Set();
45
+ for (const path of sorted) {
46
+ const lower = path.toLowerCase();
47
+ if (seen.has(lower))
48
+ problems.set(path, "letter-case");
49
+ seen.add(lower);
50
+ const names = lower.split("/");
51
+ for (let end = 1; end < names.length; end++)
52
+ folders.add(names.slice(0, end).join("/"));
53
+ }
54
+ for (const path of sorted) {
55
+ if (!problems.has(path) && folders.has(path.toLowerCase())) {
56
+ problems.set(path, "file-and-folder");
57
+ }
58
+ }
59
+ return problems;
60
+ }
61
+ /**
62
+ * A path the cloud answered, safe to print: control characters and line separators (an escape
63
+ * sequence in a name would reach the person's terminal) are written as `\uXXXX`. A path that
64
+ * passes the path rule has none.
65
+ */
66
+ export function printablePath(path) {
67
+ return path.replace(/[\p{Cc}\p{Zl}\p{Zp}]/gu, (char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`);
68
+ }
69
+ /** A path the service made for the loser of a name collision: `<path>~<id>`, 16 base32 characters. */
70
+ const LOSER = /^(.+)~[a-z2-7]{16}$/;
71
+ /**
72
+ * The paths among `paths` that are the losers of a name collision: those the service lists as
73
+ * `shown` in `collisions`, and any `<path>~<id>` whose `<path>` is a valid path. The service shows
74
+ * such a path in its answers but never keeps one; it is never written and never sent.
75
+ */
76
+ export function collisionLosers(paths, collisions) {
77
+ const losers = new Set();
78
+ for (const collision of collisions) {
79
+ const shown = typeof collision === "object" && collision !== null
80
+ ? collision.shown
81
+ : undefined;
82
+ if (typeof shown === "string")
83
+ losers.add(shown);
84
+ }
85
+ for (const path of paths) {
86
+ const stem = LOSER.exec(path)?.[1];
87
+ if (stem !== undefined && isCleanPath(stem))
88
+ losers.add(path);
89
+ }
90
+ return losers;
91
+ }
92
+ /**
93
+ * Where a project path lands under a folder, as a native path, or undefined when the resolved
94
+ * result is not inside the folder (or is the folder itself). `folder` is absolute.
95
+ */
96
+ export function insideFolder(folder, path) {
97
+ const target = resolve(folder, ...path.split("/"));
98
+ const from = relative(folder, target);
99
+ if (from === "" || from === ".." || from.startsWith(`..${sep}`) || isAbsolute(from)) {
100
+ return undefined;
101
+ }
102
+ return target;
103
+ }
104
+ //# sourceMappingURL=cloud-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-paths.js","sourceRoot":"","sources":["../src/cloud-paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Where the command line keeps its sign-in (`cli-cloud`, "Signing in from the command line"):
3
+ * `credentials.json` in the user's configuration folder, one entry `{ token, id, user }` per host,
4
+ * and how a command finds the host and the token it uses.
5
+ *
6
+ * - The host is `--host`, else `MELTEMI_HOST`, else `https://diagrams.meltemi.dev`: never a
7
+ * manifest's (`checkManifestHost` fails with `cloud.host-mismatch` when `project.json` names
8
+ * another one).
9
+ * - The token is `MELTEMI_TOKEN` in the environment, else the file's entry for the host.
10
+ * - The file is written owner-only (`0o600`, in a `0o700` folder) where the system has such modes,
11
+ * through a temporary file and a rename, so a failure never leaves half a file. Windows keeps the
12
+ * ACLs the user's profile folder has.
13
+ * - A file that cannot be read as credentials is reported (`credentials.corrupt`) and never
14
+ * overwritten.
15
+ */
16
+ /** The service every cloud command talks to unless `--host` or `MELTEMI_HOST` says otherwise. */
17
+ export declare const DEFAULT_HOST = "https://diagrams.meltemi.dev";
18
+ /** The folder of the configuration, and the file of the credentials in it. */
19
+ export declare const CONFIGURATION_FOLDER = "meltemi-diagrams";
20
+ export declare const CREDENTIALS_FILE = "credentials.json";
21
+ type Env = Readonly<Record<string, string | undefined>>;
22
+ export interface ConfigurationOptions {
23
+ /** The environment: `APPDATA`, `XDG_CONFIG_HOME`, `HOME`, `USERPROFILE`. */
24
+ readonly env: Env;
25
+ /** The platform, `process.platform` by default. */
26
+ readonly platform?: NodeJS.Platform;
27
+ /** The user's home folder, from the environment or the system by default. */
28
+ readonly home?: string;
29
+ }
30
+ /**
31
+ * The folder of the configuration: `%APPDATA%\meltemi-diagrams` on Windows;
32
+ * `$XDG_CONFIG_HOME/meltemi-diagrams` elsewhere (an absolute value only, as the specification
33
+ * says), else `~/.config/meltemi-diagrams`.
34
+ */
35
+ export declare function configurationFolder(options: ConfigurationOptions): string;
36
+ /** The credentials file of an environment. */
37
+ export declare function credentialsPath(options: ConfigurationOptions): string;
38
+ /**
39
+ * The host a cloud command talks to: `--host` (`flag`), else `MELTEMI_HOST`, else the default. An
40
+ * empty `MELTEMI_HOST` counts as not set, as CI expands an unset variable. The answer is the
41
+ * normalised origin. Throws `cloud.host-invalid` for a text that is not an origin and
42
+ * `cloud.insecure-host` for `http:` anywhere but the loopback (`127.0.0.1`, `localhost`, `[::1]`),
43
+ * before anything is sent.
44
+ */
45
+ export declare function resolveHost(options: {
46
+ readonly flag?: string | undefined;
47
+ readonly env: Env;
48
+ }): string;
49
+ /**
50
+ * Fails with `cloud.host-mismatch`, naming both hosts and `--host`, when a project's `cloud.host`
51
+ * is not the host the command resolved. A manifest never chooses where a token goes. Call it before
52
+ * any request; `manifestHost` is `project.json`'s `cloud.host` (absent when it names none).
53
+ */
54
+ export declare function checkManifestHost(resolved: string, manifestHost: string | null | undefined): void;
55
+ export interface StoredUser {
56
+ readonly sub: string;
57
+ readonly name: string;
58
+ }
59
+ /** What is kept for one host: the token, its id at the service, and who it is for. */
60
+ export interface StoredEntry {
61
+ readonly token: string;
62
+ readonly id: string;
63
+ readonly user: StoredUser;
64
+ }
65
+ /** The token a command uses, and where it came from. */
66
+ export interface ResolvedToken {
67
+ readonly token: string;
68
+ /** `environment`: `MELTEMI_TOKEN`; `file`: the credentials file's entry for the host. */
69
+ readonly source: "environment" | "file";
70
+ /** The stored entry, when the token came from the file. */
71
+ readonly entry?: StoredEntry;
72
+ }
73
+ /** The token of `MELTEMI_TOKEN`, when it is set to something. */
74
+ export declare function environmentToken(env: Env): string | undefined;
75
+ /**
76
+ * The credentials file. A missing file is an empty one. A file that is not JSON, not an object, or
77
+ * whose `hosts` is not an object, or whose entry for the host asked about is not an entry, is
78
+ * `credentials.corrupt`; nothing is written over it, so the person can read what is there.
79
+ * Entries of other hosts and fields it does not know are kept as they were found.
80
+ */
81
+ export declare class CredentialsStore {
82
+ readonly path: string;
83
+ readonly folder: string;
84
+ constructor(options: ConfigurationOptions);
85
+ private corrupt;
86
+ private load;
87
+ /** Reads the file and makes its folder, so that a command finds out before it asks for a token. */
88
+ prepare(): void;
89
+ /** The hosts that have an entry. */
90
+ hosts(): string[];
91
+ /** The entry of a host, or undefined; `credentials.corrupt` when what is there is not an entry. */
92
+ entry(host: string): StoredEntry | undefined;
93
+ /** Keeps the entry of a host, replacing the one it had. */
94
+ save(host: string, entry: StoredEntry): void;
95
+ /** Forgets the entry of a host; whether there was one. The file goes when nothing is left in it. */
96
+ remove(host: string): boolean;
97
+ private unwritable;
98
+ /** Writes owner-only through a temporary file in the same folder, then renames it into place. */
99
+ private write;
100
+ /**
101
+ * The token a command uses for a host: `MELTEMI_TOKEN` when it is set (the file is not even
102
+ * read), else the host's entry. Undefined when there is none.
103
+ */
104
+ resolveToken(host: string, env: Env): ResolvedToken | undefined;
105
+ }
106
+ export {};
107
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAiBH,iGAAiG;AACjG,eAAO,MAAM,YAAY,iCAAiC,CAAC;AAE3D,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AACvD,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAKnD,KAAK,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAExD,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IACpC,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAiBzE;AAED,8CAA8C;AAC9C,wBAAgB,eAAe,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAMrE;AAID;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;CACnB,GAAG,MAAM,CAiBT;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAQjG;AAID,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,sFAAsF;AACtF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAgBD,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yFAAyF;IACzF,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC;IACxC,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAG7D;AAUD;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,OAAO,EAAE,oBAAoB;IAMzC,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,IAAI;IA8BZ,mGAAmG;IACnG,OAAO,IAAI,IAAI;IAaf,oCAAoC;IACpC,KAAK,IAAI,MAAM,EAAE;IAIjB,mGAAmG;IACnG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAY5C,2DAA2D;IAC3D,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;IAK5C,oGAAoG;IACpG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAgB7B,OAAO,CAAC,UAAU;IAQlB,iGAAiG;IACjG,OAAO,CAAC,KAAK;IAwBb;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,aAAa,GAAG,SAAS;CAMhE"}