@logbrew/sdk 0.1.38 → 0.1.39

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 (90) hide show
  1. package/automatic-delivery.cjs +271 -0
  2. package/batch-sender.cjs +164 -0
  3. package/bounded-number.cjs +34 -0
  4. package/browser-breadcrumbs.cjs +346 -136
  5. package/capture-support.cjs +100 -0
  6. package/client-options.cjs +292 -0
  7. package/client-report.cjs +232 -0
  8. package/client.cjs +447 -0
  9. package/console-arguments.cjs +151 -0
  10. package/console-capture.cjs +194 -0
  11. package/core.cjs +30 -2810
  12. package/delivery-health.cjs +133 -0
  13. package/error-causes.cjs +130 -0
  14. package/error-details.cjs +124 -0
  15. package/error-issue.cjs +187 -0
  16. package/event-clone.cjs +55 -0
  17. package/event-metadata.cjs +40 -0
  18. package/event-pipeline.cjs +325 -0
  19. package/event-queue.cjs +306 -0
  20. package/event-store.cjs +237 -0
  21. package/event-validation.cjs +159 -0
  22. package/examples/agent-timeline.cjs +57 -46
  23. package/examples/agent-timeline.mjs +41 -35
  24. package/examples/index.mjs +122 -94
  25. package/examples/readme-example.cjs +36 -27
  26. package/examples/readme-example.mjs +21 -17
  27. package/examples/real-user-smoke.cjs +41 -32
  28. package/examples/real-user-smoke.mjs +26 -22
  29. package/exception-chain.cjs +205 -0
  30. package/index.d.ts +144 -1076
  31. package/index.js +1 -1
  32. package/issue-exception.cjs +13 -8
  33. package/metric-validation.cjs +95 -0
  34. package/network-milestone.cjs +155 -0
  35. package/null-value.cjs +4 -0
  36. package/opentelemetry-bridge.cjs +330 -0
  37. package/opentelemetry-context.cjs +245 -0
  38. package/opentelemetry-exceptions.cjs +69 -0
  39. package/opentelemetry-keys.cjs +183 -0
  40. package/opentelemetry-span.cjs +286 -0
  41. package/opentelemetry-summary.cjs +213 -0
  42. package/opentelemetry-time.cjs +131 -0
  43. package/opentelemetry.cjs +99 -1068
  44. package/package.json +55 -1
  45. package/pino-destination.cjs +108 -0
  46. package/pino-record.cjs +237 -0
  47. package/product-action.cjs +163 -0
  48. package/provided-breadcrumbs.cjs +117 -0
  49. package/random-hex.cjs +29 -0
  50. package/react-native.js +1 -1
  51. package/recording-transport.cjs +68 -0
  52. package/release-artifacts-build.cjs +263 -84
  53. package/release-artifacts-common.js +347 -66
  54. package/release-artifacts-debug-id.js +178 -0
  55. package/release-artifacts-inspect.js +213 -0
  56. package/release-artifacts-issue-event.js +99 -0
  57. package/release-artifacts-manifest-artifact.js +107 -0
  58. package/release-artifacts-manifest.js +77 -0
  59. package/release-artifacts-mappings.js +265 -0
  60. package/release-artifacts-prepare.js +297 -0
  61. package/release-artifacts-source-context.js +210 -0
  62. package/release-artifacts-symbolication.js +272 -421
  63. package/release-artifacts-upload-files.js +122 -0
  64. package/release-artifacts-upload-request.js +246 -0
  65. package/release-artifacts-upload.js +155 -300
  66. package/release-artifacts-urls.js +49 -0
  67. package/release-artifacts.js +189 -662
  68. package/retry-delay.cjs +32 -0
  69. package/span-validation.cjs +191 -0
  70. package/stored-events.cjs +243 -0
  71. package/types/client.d.ts +67 -0
  72. package/types/delivery.d.ts +125 -0
  73. package/types/issues.d.ts +249 -0
  74. package/types/logging.d.ts +175 -0
  75. package/types/opentelemetry.d.ts +205 -0
  76. package/types/product.d.ts +128 -0
  77. package/types/recording-transport.d.ts +15 -0
  78. package/types/sdk-error.d.ts +9 -0
  79. package/types/telemetry.d.ts +171 -0
  80. package/types/trace-context.d.ts +110 -0
  81. package/types/transport-error.d.ts +10 -0
  82. package/utf8.cjs +37 -0
  83. package/validation.cjs +49 -1
  84. package/vite-release-artifacts-config.cjs +120 -0
  85. package/vite-release-artifacts.cjs +199 -99
  86. package/vite-release-artifacts.d.cts +65 -40
  87. package/vite-release-artifacts.d.ts +65 -40
  88. package/vite-release-artifacts.js +2 -2
  89. package/winston-info.cjs +205 -0
  90. package/winston.cjs +189 -289
@@ -0,0 +1,213 @@
1
+ import {
2
+ byteSize,
3
+ errorMessage,
4
+ fileReference,
5
+ isJsonObject,
6
+ mapInOrder,
7
+ pathExists,
8
+ readText,
9
+ relativeTo,
10
+ safeResolve,
11
+ sourceMapDebugId
12
+ } from "./release-artifacts-common.js";
13
+ import { findDebugId, findSourceMappingUrl } from "./release-artifacts-debug-id.js";
14
+ import path from "node:path";
15
+ import { readdir } from "node:fs/promises";
16
+
17
+ /**
18
+ * @import { JsonObject } from "./release-artifacts-common.js"
19
+ * @typedef {{ readonly entryPath: string, readonly isDirectory: boolean, readonly isFile: boolean }} WalkEntry
20
+ * @typedef {{ readonly errors: readonly string[], readonly payload?: JsonObject }} SourceMapRead
21
+ * @typedef {{ readonly errors: readonly string[], readonly path?: string, readonly warnings: readonly string[] }} SourceMapLocation
22
+ * @typedef {{
23
+ * readonly errors: readonly string[],
24
+ * readonly mapDebugId?: string,
25
+ * readonly payload?: JsonObject,
26
+ * readonly relativePath?: string,
27
+ * readonly size?: number
28
+ * }} SourceMapInspection
29
+ * @typedef {{
30
+ * readonly errors: readonly string[],
31
+ * readonly jsDebugId: string | undefined,
32
+ * readonly jsSize: number,
33
+ * readonly jsSource: string,
34
+ * readonly mapDebugId: string | undefined,
35
+ * readonly relJs: string,
36
+ * readonly sourceMapPath: string | undefined,
37
+ * readonly sourceMapPayload: JsonObject | undefined,
38
+ * readonly sourceMapRel: string | undefined,
39
+ * readonly sourceMapSize: number | undefined,
40
+ * readonly sourceMappingUrl: string | undefined,
41
+ * readonly warnings: readonly string[]
42
+ * }} ArtifactInspection
43
+ */
44
+
45
+ const MINIFIED_SOURCE_SUFFIXES = [".js", ".mjs", ".bundle", ".jsbundle"];
46
+ const URL_WITH_SCHEME_RE = /^[A-Za-z][A-Za-z0-9+.-]*:\/\//u;
47
+ const EMPTY_FILE_SIZE = 0;
48
+ const ROOT_PREFIX_LENGTH = 1;
49
+
50
+ /**
51
+ * @param {string} filePath
52
+ * @returns {Promise<SourceMapRead>}
53
+ */
54
+ async function readSourceMap(filePath) {
55
+ try {
56
+ /** @type {unknown} */
57
+ const payload = JSON.parse(await readText(filePath));
58
+ return isJsonObject(payload) ? { errors: [], payload } : { errors: ["source map must be a JSON object"] };
59
+ } catch (error) {
60
+ return { errors: [`source map is not valid JSON: ${errorMessage(error)}`] };
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @param {string} jsPath
66
+ * @param {string} buildDir
67
+ * @param {string} reference
68
+ * @returns {Promise<SourceMapLocation>}
69
+ */
70
+ async function resolveReferencedSourceMap(jsPath, buildDir, reference) {
71
+ const candidate = reference.startsWith("/")
72
+ ? path.join(buildDir, reference.slice(ROOT_PREFIX_LENGTH))
73
+ : path.join(path.dirname(jsPath), reference);
74
+ const resolved = await safeResolve(candidate, buildDir);
75
+ if (resolved === undefined) {
76
+ return { errors: ["sourceMappingURL resolves outside the build directory"], warnings: [] };
77
+ }
78
+ return { errors: [], path: resolved, warnings: [] };
79
+ }
80
+
81
+ /**
82
+ * @param {string} jsPath
83
+ * @param {string} buildDir
84
+ * @param {string | undefined} sourceMappingUrl
85
+ * @returns {Promise<SourceMapLocation>}
86
+ */
87
+ async function resolveSourceMapPath(jsPath, buildDir, sourceMappingUrl) {
88
+ if (sourceMappingUrl === undefined) {
89
+ const fallback = `${jsPath}.map`;
90
+ const warnings = ["sourceMappingURL comment missing; checked sibling .map fallback"];
91
+ return (await pathExists(fallback)) ? { errors: [], path: fallback, warnings } : { errors: [], warnings };
92
+ }
93
+ const reference = fileReference(sourceMappingUrl);
94
+ if (reference.startsWith("data:")) {
95
+ return { errors: ["inline source maps are not accepted for release artifact manifests"], warnings: [] };
96
+ }
97
+ if (URL_WITH_SCHEME_RE.test(reference)) {
98
+ return { errors: ["external sourceMappingURL cannot be validated from the local build directory"], warnings: [] };
99
+ }
100
+ return resolveReferencedSourceMap(jsPath, buildDir, reference);
101
+ }
102
+
103
+ /**
104
+ * @param {string} filePath
105
+ * @returns {boolean}
106
+ */
107
+ function isMinifiedSource(filePath) {
108
+ return !filePath.endsWith(".map") && MINIFIED_SOURCE_SUFFIXES.some((suffix) => filePath.endsWith(suffix));
109
+ }
110
+
111
+ /**
112
+ * @param {string} root
113
+ * @returns {Promise<string[]>}
114
+ */
115
+ async function walkFiles(root) {
116
+ const entries = await readdir(root, { withFileTypes: true });
117
+ /** @type {WalkEntry[]} */
118
+ const descriptors = [];
119
+ for (const entry of entries) {
120
+ descriptors.push({ entryPath: path.join(root, entry.name), isDirectory: entry.isDirectory(), isFile: entry.isFile() });
121
+ }
122
+ const nested = await mapInOrder(descriptors, async ({ entryPath, isDirectory, isFile }) => {
123
+ if (isDirectory) {
124
+ return walkFiles(entryPath);
125
+ }
126
+ return isFile ? [entryPath] : [];
127
+ });
128
+ const results = nested.flat();
129
+ results.sort();
130
+ return results;
131
+ }
132
+
133
+ /**
134
+ * @param {string} buildDir
135
+ * @returns {Promise<string[]>}
136
+ */
137
+ async function iterMinifiedSourceFiles(buildDir) {
138
+ const files = await walkFiles(buildDir);
139
+ return files.filter((filePath) => isMinifiedSource(filePath));
140
+ }
141
+
142
+ /**
143
+ * @param {string} sourceMapPath
144
+ * @param {string} relativePath
145
+ * @param {number} size
146
+ * @returns {Promise<SourceMapInspection>}
147
+ */
148
+ async function inspectSourceMapPayload(sourceMapPath, relativePath, size) {
149
+ const { errors, payload } = await readSourceMap(sourceMapPath);
150
+ if (payload === undefined) {
151
+ return { errors, relativePath, size };
152
+ }
153
+ const mapDebugId = sourceMapDebugId(payload);
154
+ return mapDebugId === undefined
155
+ ? { errors, payload, relativePath, size }
156
+ : { errors, mapDebugId, payload, relativePath, size };
157
+ }
158
+
159
+ /**
160
+ * @param {string | undefined} sourceMapPath
161
+ * @param {string} buildDir
162
+ * @returns {Promise<SourceMapInspection>}
163
+ */
164
+ async function inspectSourceMap(sourceMapPath, buildDir) {
165
+ if (sourceMapPath === undefined) {
166
+ return { errors: ["source map file is missing"] };
167
+ }
168
+ if (!(await pathExists(sourceMapPath))) {
169
+ return { errors: [`source map file is missing: ${relativeTo(buildDir, sourceMapPath)}`] };
170
+ }
171
+ const size = await byteSize(sourceMapPath);
172
+ if (size === EMPTY_FILE_SIZE) {
173
+ return { errors: [`source map file is empty: ${relativeTo(buildDir, sourceMapPath)}`] };
174
+ }
175
+ return inspectSourceMapPayload(sourceMapPath, relativeTo(buildDir, sourceMapPath), size);
176
+ }
177
+
178
+ /**
179
+ * @param {string} jsPath
180
+ * @param {string} buildDir
181
+ * @returns {Promise<ArtifactInspection>}
182
+ */
183
+ async function inspectArtifactFiles(jsPath, buildDir) {
184
+ const jsSize = await byteSize(jsPath);
185
+ const jsSource = await readText(jsPath);
186
+ const jsDebugId = findDebugId(jsSource);
187
+ const sourceMappingUrl = findSourceMappingUrl(jsSource);
188
+ const location = await resolveSourceMapPath(jsPath, buildDir, sourceMappingUrl);
189
+ const sourceMap = await inspectSourceMap(location.path, buildDir);
190
+ const { mapDebugId } = sourceMap;
191
+ const mismatch = jsDebugId !== undefined && mapDebugId !== undefined && jsDebugId !== mapDebugId;
192
+ return {
193
+ errors: [
194
+ ...(jsSize === EMPTY_FILE_SIZE ? ["minified source file is empty"] : []),
195
+ ...location.errors,
196
+ ...sourceMap.errors,
197
+ ...(mismatch ? ["minified source debugId does not match source map debugId"] : [])
198
+ ],
199
+ jsDebugId,
200
+ jsSize,
201
+ jsSource,
202
+ mapDebugId,
203
+ relJs: relativeTo(buildDir, jsPath),
204
+ sourceMapPath: location.path,
205
+ sourceMapPayload: sourceMap.payload,
206
+ sourceMapRel: sourceMap.relativePath,
207
+ sourceMapSize: sourceMap.size,
208
+ sourceMappingUrl,
209
+ warnings: location.warnings
210
+ };
211
+ }
212
+
213
+ export { inspectArtifactFiles, iterMinifiedSourceFiles, readSourceMap };
@@ -0,0 +1,99 @@
1
+ import { isJsonObject } from "./release-artifacts-common.js";
2
+
3
+ /**
4
+ * @import { JsonObject } from "./release-artifacts-common.js"
5
+ * @typedef {{ readonly issueId?: string, readonly metadataSource: string, readonly type: string }} IssueEventInput
6
+ */
7
+
8
+ const FIRST_LINE = 1;
9
+
10
+ /**
11
+ * @param {unknown} value
12
+ * @returns {string | undefined}
13
+ */
14
+ function trimmedString(value) {
15
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : undefined;
16
+ }
17
+
18
+ /**
19
+ * @param {JsonObject} issueEvent
20
+ * @returns {{ readonly input: IssueEventInput, readonly metadata: JsonObject }}
21
+ */
22
+ function metadataFromIssueEvent(issueEvent) {
23
+ const { attributes, metadata } = issueEvent;
24
+ const attributesMetadata = isJsonObject(attributes) ? attributes["metadata"] : undefined;
25
+ if (isJsonObject(attributesMetadata)) {
26
+ const issueId = trimmedString(issueEvent["id"]);
27
+ return {
28
+ input: {
29
+ ...(issueId === undefined ? {} : { issueId }),
30
+ metadataSource: "attributes.metadata",
31
+ type: "sdk_issue_event"
32
+ },
33
+ metadata: attributesMetadata
34
+ };
35
+ }
36
+ if (isJsonObject(metadata)) {
37
+ return { input: { metadataSource: "metadata", type: "issue_attributes" }, metadata };
38
+ }
39
+ throw new Error("issue event must contain attributes.metadata or metadata");
40
+ }
41
+
42
+ /**
43
+ * @param {JsonObject} metadata
44
+ * @param {string} name
45
+ * @returns {string}
46
+ */
47
+ function requireMetadataString(metadata, name) {
48
+ const value = trimmedString(metadata[name]);
49
+ if (value === undefined) {
50
+ throw new Error(`issue event metadata is missing ${name}`);
51
+ }
52
+ return value;
53
+ }
54
+
55
+ /**
56
+ * @param {JsonObject} metadata
57
+ * @param {string} name
58
+ * @returns {number}
59
+ */
60
+ function requireMetadataPositiveInteger(metadata, name) {
61
+ const value = metadata[name];
62
+ if (typeof value !== "number" || !Number.isInteger(value) || value < FIRST_LINE) {
63
+ throw new Error(`issue event metadata ${name} must be a one-based positive integer`);
64
+ }
65
+ return value;
66
+ }
67
+
68
+ /**
69
+ * @param {JsonObject} metadata
70
+ * @param {JsonObject} manifest
71
+ * @returns {void}
72
+ */
73
+ function requireMetadataMatchesManifest(metadata, manifest) {
74
+ for (const name of ["release", "environment", "service"]) {
75
+ if (manifest[name] !== requireMetadataString(metadata, name)) {
76
+ throw new Error(`issue event metadata ${name} does not match the manifest`);
77
+ }
78
+ }
79
+ }
80
+
81
+ /**
82
+ * @param {JsonObject} metadata
83
+ * @returns {string}
84
+ */
85
+ function stackFrameFromIssueMetadata(metadata) {
86
+ const releaseArtifactType = requireMetadataString(metadata, "releaseArtifactType");
87
+ if (releaseArtifactType !== "sourcemap") {
88
+ throw new Error("issue event releaseArtifactType must be sourcemap");
89
+ }
90
+ const codeFile = trimmedString(metadata["releaseArtifactCodeFile"]) ?? trimmedString(metadata["errorFrameFile"]);
91
+ if (codeFile === undefined) {
92
+ throw new Error("issue event metadata is missing releaseArtifactCodeFile");
93
+ }
94
+ const line = requireMetadataPositiveInteger(metadata, "errorFrameLine");
95
+ const column = requireMetadataPositiveInteger(metadata, "errorFrameColumn");
96
+ return `${codeFile}:${String(line)}:${String(column)}`;
97
+ }
98
+
99
+ export { metadataFromIssueEvent, requireMetadataMatchesManifest, requireMetadataString, stackFrameFromIssueMetadata };
@@ -0,0 +1,107 @@
1
+ import { inspectArtifactFiles } from "./release-artifacts-inspect.js";
2
+ import { joinUrlOrPath } from "./release-artifacts-urls.js";
3
+ import { sha256File } from "./release-artifacts-common.js";
4
+
5
+ /**
6
+ * @import { JsonObject } from "./release-artifacts-common.js"
7
+ * @import { ArtifactInspection } from "./release-artifacts-inspect.js"
8
+ * @typedef {{ readonly errors: readonly string[], readonly status: "blocked" | "ready", readonly warnings: readonly string[] }} Validation
9
+ * @typedef {{
10
+ * readonly allowSourcesContent: boolean,
11
+ * readonly buildDir: string,
12
+ * readonly minifiedPathPrefix: string
13
+ * }} ManifestArtifactOptions
14
+ * @typedef {{
15
+ * readonly minifiedSource: JsonObject & { readonly path: string },
16
+ * readonly validation: Validation
17
+ * }} ManifestArtifact
18
+ */
19
+
20
+ const NO_ITEMS = 0;
21
+
22
+ /**
23
+ * @param {JsonObject} payload
24
+ * @param {boolean} allowSourcesContent
25
+ * @returns {{ readonly errors: readonly string[], readonly warnings: readonly string[] }}
26
+ */
27
+ function validateSourceMapPayload(payload, allowSourcesContent) {
28
+ const { mappings, sources, version } = payload;
29
+ const hasSourcesContent = "sourcesContent" in payload;
30
+ return {
31
+ errors: [
32
+ ...(version === undefined ? ["source map version is required"] : []),
33
+ ...(!Array.isArray(sources) || sources.length === NO_ITEMS ? ["source map sources must be a non-empty array"] : []),
34
+ ...(typeof mappings !== "string" || mappings === "" ? ["source map mappings must be a non-empty string"] : []),
35
+ ...(hasSourcesContent && !allowSourcesContent
36
+ ? ["source map contains sourcesContent; rerun with --allow-sources-content only if policy permits it"]
37
+ : [])
38
+ ],
39
+ warnings:
40
+ hasSourcesContent && allowSourcesContent
41
+ ? ["source map contains sourcesContent; ensure app policy permits source upload"]
42
+ : []
43
+ };
44
+ }
45
+
46
+ /**
47
+ * @param {ArtifactInspection} inspection
48
+ * @param {boolean} allowSourcesContent
49
+ * @returns {Promise<{ readonly entry: JsonObject | undefined, readonly errors: readonly string[], readonly warnings: readonly string[] }>}
50
+ */
51
+ async function sourceMapEntry(inspection, allowSourcesContent) {
52
+ const { mapDebugId, sourceMapPath, sourceMapPayload, sourceMapRel, sourceMapSize } = inspection;
53
+ if (sourceMapPayload === undefined || sourceMapPath === undefined || sourceMapRel === undefined) {
54
+ return { entry: undefined, errors: [], warnings: [] };
55
+ }
56
+ const { errors, warnings } = validateSourceMapPayload(sourceMapPayload, allowSourcesContent);
57
+ const { sources } = sourceMapPayload;
58
+ return {
59
+ entry: {
60
+ artifactSha256: await sha256File(sourceMapPath),
61
+ byteSize: sourceMapSize,
62
+ ...(mapDebugId === undefined ? {} : { debugId: mapDebugId }),
63
+ hasSourcesContent: "sourcesContent" in sourceMapPayload,
64
+ path: sourceMapRel,
65
+ sourceCount: Array.isArray(sources) ? sources.length : NO_ITEMS
66
+ },
67
+ errors,
68
+ warnings
69
+ };
70
+ }
71
+
72
+ /**
73
+ * @param {string} jsPath
74
+ * @param {ManifestArtifactOptions} options
75
+ * @returns {Promise<ManifestArtifact & JsonObject>}
76
+ */
77
+ async function buildManifestArtifact(jsPath, { allowSourcesContent, buildDir, minifiedPathPrefix }) {
78
+ const inspection = await inspectArtifactFiles(jsPath, buildDir);
79
+ const { jsDebugId, jsSize, mapDebugId, relJs, sourceMappingUrl } = inspection;
80
+ const sourceMap = await sourceMapEntry(inspection, allowSourcesContent);
81
+ const errors = [...inspection.errors, ...sourceMap.errors];
82
+ const missingDebugId = jsDebugId === undefined && mapDebugId === undefined;
83
+ const warnings = [
84
+ ...inspection.warnings,
85
+ ...sourceMap.warnings,
86
+ ...(missingDebugId ? ["no debugId found; backend matching must rely on release/environment/service and minified path"] : [])
87
+ ];
88
+ const debugId = jsDebugId ?? mapDebugId;
89
+ const minifiedUrl = joinUrlOrPath(minifiedPathPrefix, relJs);
90
+ const artifactSha256 = await sha256File(jsPath);
91
+ return {
92
+ artifactType: "javascript_source_map",
93
+ ...(debugId === undefined ? {} : { debugId }),
94
+ minifiedSource: {
95
+ artifactSha256,
96
+ byteSize: jsSize,
97
+ ...(jsDebugId === undefined ? {} : { debugId: jsDebugId }),
98
+ minifiedUrl,
99
+ path: relJs,
100
+ ...(sourceMappingUrl === undefined ? {} : { sourceMappingUrl })
101
+ },
102
+ sourceMap: sourceMap.entry ?? null,
103
+ validation: { errors, status: errors.length > NO_ITEMS ? "blocked" : "ready", warnings }
104
+ };
105
+ }
106
+
107
+ export { buildManifestArtifact };
@@ -0,0 +1,77 @@
1
+ import { buildManifestArtifact } from "./release-artifacts-manifest-artifact.js";
2
+ import { iterMinifiedSourceFiles } from "./release-artifacts-inspect.js";
3
+ import { mapInOrder } from "./release-artifacts-common.js";
4
+ import { normalizeUrlOrPath } from "./release-artifacts-urls.js";
5
+
6
+ /**
7
+ * @import { JsonObject } from "./release-artifacts-common.js"
8
+ * @import { ManifestArtifact, Validation } from "./release-artifacts-manifest-artifact.js"
9
+ * @typedef {{
10
+ * readonly allowSourcesContent: boolean,
11
+ * readonly buildDir: string,
12
+ * readonly commitSha: string | undefined,
13
+ * readonly environment: string,
14
+ * readonly minifiedPathPrefix: string,
15
+ * readonly projectId: string | undefined,
16
+ * readonly release: string,
17
+ * readonly repositoryUrl: string | undefined,
18
+ * readonly service: string
19
+ * }} ManifestOptions
20
+ */
21
+
22
+ const MANIFEST_VERSION = 1;
23
+ const NO_ITEMS = 0;
24
+ const SCRIPT_VERSION = "0.1.0";
25
+
26
+ /**
27
+ * @param {readonly ManifestArtifact[]} artifacts
28
+ * @param {(artifact: ManifestArtifact) => readonly string[]} messages
29
+ * @returns {string[]}
30
+ */
31
+ function prefixedMessages(artifacts, messages) {
32
+ return artifacts.flatMap((artifact) => messages(artifact).map((message) => `${artifact.minifiedSource.path}: ${message}`));
33
+ }
34
+
35
+ /**
36
+ * @param {string | undefined} repositoryUrl
37
+ * @param {string | undefined} commitSha
38
+ * @returns {JsonObject}
39
+ */
40
+ function gitMetadata(repositoryUrl, commitSha) {
41
+ return {
42
+ ...(commitSha === undefined || commitSha === "" ? {} : { commitSha: commitSha.trim() }),
43
+ ...(repositoryUrl === undefined || repositoryUrl === "" ? {} : { repositoryUrl: repositoryUrl.trim() })
44
+ };
45
+ }
46
+
47
+ /**
48
+ * @param {ManifestOptions} options
49
+ * @returns {Promise<JsonObject & { readonly validation: Validation }>}
50
+ */
51
+ async function createManifest(options) {
52
+ const { allowSourcesContent, buildDir, environment, projectId, release, service } = options;
53
+ const minifiedPathPrefix = normalizeUrlOrPath(options.minifiedPathPrefix.trim());
54
+ const artifacts = await mapInOrder(await iterMinifiedSourceFiles(buildDir), async (filePath) =>
55
+ buildManifestArtifact(filePath, { allowSourcesContent, buildDir, minifiedPathPrefix }));
56
+ const errors = [
57
+ ...(artifacts.length === NO_ITEMS ? ["no JavaScript release artifact files found in build directory"] : []),
58
+ ...prefixedMessages(artifacts, (artifact) => artifact.validation.errors)
59
+ ];
60
+ const warnings = prefixedMessages(artifacts, (artifact) => artifact.validation.warnings);
61
+ const git = gitMetadata(options.repositoryUrl, options.commitSha);
62
+ return {
63
+ artifactType: "javascript_source_map_manifest",
64
+ artifacts,
65
+ environment,
66
+ ...(Object.keys(git).length > NO_ITEMS ? { git } : {}),
67
+ manifestVersion: MANIFEST_VERSION,
68
+ minifiedPathPrefix,
69
+ ...(projectId === undefined ? {} : { projectId }),
70
+ release,
71
+ service,
72
+ uploader: { name: "logbrew-js-release-artifact-manifest", version: SCRIPT_VERSION },
73
+ validation: { errors, status: errors.length > NO_ITEMS ? "blocked" : "ready", warnings }
74
+ };
75
+ }
76
+
77
+ export { createManifest };