mirror of
https://github.com/actions/download-artifact.git
synced 2026-07-09 00:08:34 +08:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fc02353415 | |||
| 77454371a4 | |||
| 84fc7a0a35 | |||
| 67f2bc382f | |||
| 8ea3c2c174 | |||
| d219c630f6 | |||
| 54124fbd88 | |||
| b83057b90d | |||
| 171183c7dc | |||
| e463631f66 | |||
| ec378bcca1 | |||
| 42aef06f22 | |||
| ac35f995fe | |||
| 95815c38cf | |||
| 278fca438a | |||
| 68909842a1 | |||
| f9415c0ec3 | |||
| 76a6eb5cbc | |||
| a2426d7c45 | |||
| 3ffa694f6f | |||
| 53f6aa5f93 | |||
| b456700053 | |||
| 9eab798a98 | |||
| a39a661f39 | |||
| 9a869e9c49 | |||
| 96a6f165f4 | |||
| df4ad15cb8 | |||
| c7cfc3a2a3 | |||
| 2439186eed | |||
| b14cf4c926 | |||
| c5804ef743 | |||
| 956811a503 | |||
| af3c6d3e5b | |||
| 4dd97f8f21 | |||
| da9985dde6 | |||
| 81ba80daa4 | |||
| 727afbf2b0 | |||
| 56c2d7ea8c | |||
| 7797bfcd59 | |||
| 9ff67cb2d2 | |||
| 049eba1e9a | |||
| 503e7a18ae | |||
| a8a786b097 | |||
| 24aef17bbf | |||
| b81a615862 | |||
| cc20338598 | |||
| 1fc0fee191 | |||
| 7fba95161a | |||
| f9ceb7763b | |||
| 533298bc57 | |||
| d06289e120 | |||
| d0ce8fd116 | |||
| 1ce0d91ace | |||
| fa0a91b85d | |||
| b54d0883e1 | |||
| 65a9edc588 | |||
| fdd1595981 | |||
| c13dba102f | |||
| 0daa75ebea |
@@ -10,11 +10,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
name: 'Publish Immutable Action Version'
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checking out
|
||||
uses: actions/checkout@v4
|
||||
- name: Publish
|
||||
id: publish
|
||||
uses: actions/publish-immutable-action@0.0.3
|
||||
@@ -40,6 +40,9 @@ jobs:
|
||||
- name: Format
|
||||
run: npm run format-check
|
||||
|
||||
- name: Run Unit Tests
|
||||
run: npm test
|
||||
|
||||
- name: Create artifacts
|
||||
run: |
|
||||
mkdir -p path/to/artifact-A
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: "@actions/artifact"
|
||||
version: 2.1.6
|
||||
version: 2.3.2
|
||||
type: npm
|
||||
summary: Actions artifact lib
|
||||
homepage: https://github.com/actions/toolkit/tree/main/packages/artifact
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
# `@actions/download-artifact`
|
||||
|
||||
> [!WARNING]
|
||||
> actions/download-artifact@v3 is scheduled for deprecation on **November 30, 2024**. [Learn more.](https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/)
|
||||
> Similarly, v1/v2 are scheduled for deprecation on **June 30, 2024**.
|
||||
> Please update your workflow to use v4 of the artifact actions.
|
||||
> This deprecation will not impact any existing versions of GitHub Enterprise Server being used by customers.
|
||||
|
||||
Download [Actions Artifacts](https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts) from your Workflow Runs. Internally powered by the [@actions/artifact](https://github.com/actions/toolkit/tree/main/packages/artifact) package.
|
||||
|
||||
See also [upload-artifact](https://github.com/actions/upload-artifact).
|
||||
@@ -19,6 +13,7 @@ See also [upload-artifact](https://github.com/actions/upload-artifact).
|
||||
- [Outputs](#outputs)
|
||||
- [Examples](#examples)
|
||||
- [Download Single Artifact](#download-single-artifact)
|
||||
- [Download Artifacts by ID](#download-artifacts-by-id)
|
||||
- [Download All Artifacts](#download-all-artifacts)
|
||||
- [Download multiple (filtered) Artifacts to the same directory](#download-multiple-filtered-artifacts-to-the-same-directory)
|
||||
- [Download Artifacts from other Workflow Runs or Repositories](#download-artifacts-from-other-workflow-runs-or-repositories)
|
||||
@@ -59,6 +54,11 @@ For assistance with breaking changes, see [MIGRATION.md](docs/MIGRATION.md).
|
||||
# Optional.
|
||||
name:
|
||||
|
||||
# IDs of the artifacts to download, comma-separated.
|
||||
# Either inputs `artifact-ids` or `name` can be used, but not both.
|
||||
# Optional.
|
||||
artifact-ids:
|
||||
|
||||
# Destination path. Supports basic tilde expansion.
|
||||
# Optional. Default is $GITHUB_WORKSPACE
|
||||
path:
|
||||
@@ -123,6 +123,32 @@ steps:
|
||||
run: ls -R your/destination/dir
|
||||
```
|
||||
|
||||
### Download Artifacts by ID
|
||||
|
||||
The `artifact-ids` input allows downloading artifacts using their unique ID rather than name. This is particularly useful when working with immutable artifacts from `actions/upload-artifact@v4` which assigns a unique ID to each artifact.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
artifact-ids: 12345
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -R
|
||||
```
|
||||
|
||||
Multiple artifacts can be downloaded by providing a comma-separated list of IDs:
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
artifact-ids: 12345,67890
|
||||
path: path/to/artifacts
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -R path/to/artifacts
|
||||
```
|
||||
|
||||
This will download multiple artifacts to separate directories (similar to downloading multiple artifacts by name).
|
||||
|
||||
### Download All Artifacts
|
||||
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
import * as core from '@actions/core'
|
||||
import artifact, {ArtifactNotFoundError} from '@actions/artifact'
|
||||
import {run} from '../src/download-artifact'
|
||||
import {Inputs} from '../src/constants'
|
||||
|
||||
jest.mock('@actions/github', () => ({
|
||||
context: {
|
||||
repo: {
|
||||
owner: 'actions',
|
||||
repo: 'toolkit'
|
||||
},
|
||||
runId: 123,
|
||||
serverUrl: 'https://github.com'
|
||||
}
|
||||
}))
|
||||
|
||||
jest.mock('@actions/core')
|
||||
|
||||
/* eslint-disable no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
const mockInputs = (overrides?: Partial<{[K in Inputs]?: any}>) => {
|
||||
const inputs = {
|
||||
[Inputs.Name]: 'artifact-name',
|
||||
[Inputs.Path]: '/some/artifact/path',
|
||||
[Inputs.GitHubToken]: 'warn',
|
||||
[Inputs.Repository]: 'owner/some-repository',
|
||||
[Inputs.RunID]: 'some-run-id',
|
||||
[Inputs.Pattern]: 'some-pattern',
|
||||
...overrides
|
||||
}
|
||||
|
||||
;(core.getInput as jest.Mock).mockImplementation((name: string) => {
|
||||
return inputs[name]
|
||||
})
|
||||
;(core.getBooleanInput as jest.Mock).mockImplementation((name: string) => {
|
||||
return inputs[name]
|
||||
})
|
||||
|
||||
return inputs
|
||||
}
|
||||
|
||||
describe('download', () => {
|
||||
beforeEach(async () => {
|
||||
mockInputs()
|
||||
jest.clearAllMocks()
|
||||
|
||||
// Mock artifact client methods
|
||||
jest
|
||||
.spyOn(artifact, 'listArtifacts')
|
||||
.mockImplementation(() => Promise.resolve({artifacts: []}))
|
||||
jest.spyOn(artifact, 'getArtifact').mockImplementation(name => {
|
||||
throw new ArtifactNotFoundError(`Artifact '${name}' not found`)
|
||||
})
|
||||
jest
|
||||
.spyOn(artifact, 'downloadArtifact')
|
||||
.mockImplementation(() => Promise.resolve({digestMismatch: false}))
|
||||
})
|
||||
|
||||
test('downloads a single artifact by name', async () => {
|
||||
const mockArtifact = {
|
||||
id: 123,
|
||||
name: 'artifact-name',
|
||||
size: 1024,
|
||||
digest: 'abc123'
|
||||
}
|
||||
|
||||
jest
|
||||
.spyOn(artifact, 'getArtifact')
|
||||
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
|
||||
|
||||
await run()
|
||||
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
||||
mockArtifact.id,
|
||||
expect.objectContaining({
|
||||
expectedHash: mockArtifact.digest
|
||||
})
|
||||
)
|
||||
expect(core.info).toHaveBeenCalledWith('Total of 1 artifact(s) downloaded')
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith(
|
||||
'download-path',
|
||||
expect.any(String)
|
||||
)
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith(
|
||||
'Download artifact has finished successfully'
|
||||
)
|
||||
})
|
||||
|
||||
test('downloads multiple artifacts when no name or pattern provided', async () => {
|
||||
jest.clearAllMocks()
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: ''
|
||||
})
|
||||
|
||||
const mockArtifacts = [
|
||||
{id: 123, name: 'artifact1', size: 1024, digest: 'abc123'},
|
||||
{id: 456, name: 'artifact2', size: 2048, digest: 'def456'}
|
||||
]
|
||||
|
||||
// Set up artifact mock after clearing mocks
|
||||
jest
|
||||
.spyOn(artifact, 'listArtifacts')
|
||||
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
|
||||
|
||||
// Reset downloadArtifact mock as well
|
||||
jest
|
||||
.spyOn(artifact, 'downloadArtifact')
|
||||
.mockImplementation(() => Promise.resolve({digestMismatch: false}))
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith(
|
||||
'No input name, artifact-ids or pattern filtered specified, downloading all artifacts'
|
||||
)
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith('Total of 2 artifact(s) downloaded')
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
test('sets download path output even when no artifacts are found', async () => {
|
||||
mockInputs({[Inputs.Name]: ''})
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith(
|
||||
'download-path',
|
||||
expect.any(String)
|
||||
)
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith(
|
||||
'Download artifact has finished successfully'
|
||||
)
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith('Total of 0 artifact(s) downloaded')
|
||||
})
|
||||
|
||||
test('filters artifacts by pattern', async () => {
|
||||
const mockArtifacts = [
|
||||
{id: 123, name: 'test-artifact', size: 1024, digest: 'abc123'},
|
||||
{id: 456, name: 'prod-artifact', size: 2048, digest: 'def456'}
|
||||
]
|
||||
|
||||
jest
|
||||
.spyOn(artifact, 'listArtifacts')
|
||||
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: 'test-*'
|
||||
})
|
||||
|
||||
await run()
|
||||
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1)
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
||||
123,
|
||||
expect.anything()
|
||||
)
|
||||
})
|
||||
|
||||
test('uses token and repository information when provided', async () => {
|
||||
const token = 'ghp_testtoken123'
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.GitHubToken]: token,
|
||||
[Inputs.Repository]: 'myorg/myrepo',
|
||||
[Inputs.RunID]: '789'
|
||||
})
|
||||
|
||||
jest
|
||||
.spyOn(artifact, 'listArtifacts')
|
||||
.mockImplementation(() => Promise.resolve({artifacts: []}))
|
||||
|
||||
await run()
|
||||
|
||||
expect(artifact.listArtifacts).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
findBy: {
|
||||
token,
|
||||
workflowRunId: 789,
|
||||
repositoryName: 'myrepo',
|
||||
repositoryOwner: 'myorg'
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
test('throws error when repository format is invalid', async () => {
|
||||
mockInputs({
|
||||
[Inputs.GitHubToken]: 'some-token',
|
||||
[Inputs.Repository]: 'invalid-format' // Missing the owner/repo format
|
||||
})
|
||||
|
||||
await expect(run()).rejects.toThrow(
|
||||
"Invalid repository: 'invalid-format'. Must be in format owner/repo"
|
||||
)
|
||||
})
|
||||
|
||||
test('warns when digest validation fails', async () => {
|
||||
const mockArtifact = {
|
||||
id: 123,
|
||||
name: 'corrupted-artifact',
|
||||
size: 1024,
|
||||
digest: 'abc123'
|
||||
}
|
||||
|
||||
jest
|
||||
.spyOn(artifact, 'getArtifact')
|
||||
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
|
||||
|
||||
jest
|
||||
.spyOn(artifact, 'downloadArtifact')
|
||||
.mockImplementation(() => Promise.resolve({digestMismatch: true}))
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.warning).toHaveBeenCalledWith(
|
||||
expect.stringContaining('digest validation failed')
|
||||
)
|
||||
})
|
||||
|
||||
test('downloads a single artifact by ID', async () => {
|
||||
const mockArtifact = {
|
||||
id: 456,
|
||||
name: 'artifact-by-id',
|
||||
size: 1024,
|
||||
digest: 'def456'
|
||||
}
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '456'
|
||||
})
|
||||
|
||||
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
artifacts: [mockArtifact]
|
||||
})
|
||||
)
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith('Downloading artifacts by ID')
|
||||
expect(core.debug).toHaveBeenCalledWith('Parsed artifact IDs: ["456"]')
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1)
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
||||
456,
|
||||
expect.objectContaining({
|
||||
expectedHash: mockArtifact.digest
|
||||
})
|
||||
)
|
||||
expect(core.info).toHaveBeenCalledWith('Total of 1 artifact(s) downloaded')
|
||||
})
|
||||
|
||||
test('downloads multiple artifacts by ID', async () => {
|
||||
const mockArtifacts = [
|
||||
{id: 123, name: 'first-artifact', size: 1024, digest: 'abc123'},
|
||||
{id: 456, name: 'second-artifact', size: 2048, digest: 'def456'},
|
||||
{id: 789, name: 'third-artifact', size: 3072, digest: 'ghi789'}
|
||||
]
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '123, 456, 789'
|
||||
})
|
||||
|
||||
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
artifacts: mockArtifacts
|
||||
})
|
||||
)
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith('Downloading artifacts by ID')
|
||||
expect(core.debug).toHaveBeenCalledWith(
|
||||
'Parsed artifact IDs: ["123","456","789"]'
|
||||
)
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(3)
|
||||
mockArtifacts.forEach(mockArtifact => {
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
||||
mockArtifact.id,
|
||||
expect.objectContaining({
|
||||
expectedHash: mockArtifact.digest
|
||||
})
|
||||
)
|
||||
})
|
||||
expect(core.info).toHaveBeenCalledWith('Total of 3 artifact(s) downloaded')
|
||||
})
|
||||
|
||||
test('warns when some artifact IDs are not found', async () => {
|
||||
const mockArtifacts = [
|
||||
{id: 123, name: 'found-artifact', size: 1024, digest: 'abc123'}
|
||||
]
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '123, 456, 789'
|
||||
})
|
||||
|
||||
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
artifacts: mockArtifacts
|
||||
})
|
||||
)
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.warning).toHaveBeenCalledWith(
|
||||
'Could not find the following artifact IDs: 456, 789'
|
||||
)
|
||||
expect(core.debug).toHaveBeenCalledWith('Found 1 artifacts by ID')
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
test('throws error when no artifacts with requested IDs are found', async () => {
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '123, 456'
|
||||
})
|
||||
|
||||
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
artifacts: []
|
||||
})
|
||||
)
|
||||
|
||||
await expect(run()).rejects.toThrow(
|
||||
'None of the provided artifact IDs were found'
|
||||
)
|
||||
})
|
||||
|
||||
test('throws error when artifact-ids input is empty', async () => {
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: ' '
|
||||
})
|
||||
|
||||
await expect(run()).rejects.toThrow(
|
||||
"No valid artifact IDs provided in 'artifact-ids' input"
|
||||
)
|
||||
})
|
||||
|
||||
test('throws error when some artifact IDs are not valid numbers', async () => {
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '123, abc, 456'
|
||||
})
|
||||
|
||||
await expect(run()).rejects.toThrow(
|
||||
"Invalid artifact ID: 'abc'. Must be a number."
|
||||
)
|
||||
})
|
||||
|
||||
test('throws error when both name and artifact-ids are provided', async () => {
|
||||
mockInputs({
|
||||
[Inputs.Name]: 'some-artifact',
|
||||
[Inputs.ArtifactIds]: '123'
|
||||
})
|
||||
|
||||
await expect(run()).rejects.toThrow(
|
||||
"Inputs 'name' and 'artifact-ids' cannot be used together. Please specify only one."
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -5,6 +5,9 @@ inputs:
|
||||
name:
|
||||
description: 'Name of the artifact to download. If unspecified, all artifacts for the run are downloaded.'
|
||||
required: false
|
||||
artifact-ids:
|
||||
description: 'IDs of the artifacts to download, comma-separated. Either inputs `artifact-ids` or `name` can be used, but not both.'
|
||||
required: false
|
||||
path:
|
||||
description: 'Destination path. Supports basic tilde expansion. Defaults to $GITHUB_WORKSPACE'
|
||||
required: false
|
||||
|
||||
Vendored
+786
-2321
@@ -813,7 +813,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
__exportStar(__nccwpck_require__(54622), exports);
|
||||
__exportStar(__nccwpck_require__(8626), exports);
|
||||
__exportStar(__nccwpck_require__(58178), exports);
|
||||
__exportStar(__nccwpck_require__(63077), exports);
|
||||
__exportStar(__nccwpck_require__(49773), exports);
|
||||
//# sourceMappingURL=index.js.map
|
||||
|
||||
/***/ }),
|
||||
@@ -824,7 +824,7 @@ __exportStar(__nccwpck_require__(63077), exports);
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.ArtifactService = exports.DeleteArtifactResponse = exports.DeleteArtifactRequest = exports.GetSignedArtifactURLResponse = exports.GetSignedArtifactURLRequest = exports.ListArtifactsResponse_MonolithArtifact = exports.ListArtifactsResponse = exports.ListArtifactsRequest = exports.FinalizeArtifactResponse = exports.FinalizeArtifactRequest = exports.CreateArtifactResponse = exports.CreateArtifactRequest = void 0;
|
||||
exports.ArtifactService = exports.DeleteArtifactResponse = exports.DeleteArtifactRequest = exports.GetSignedArtifactURLResponse = exports.GetSignedArtifactURLRequest = exports.ListArtifactsResponse_MonolithArtifact = exports.ListArtifactsResponse = exports.ListArtifactsRequest = exports.FinalizeArtifactResponse = exports.FinalizeArtifactRequest = exports.CreateArtifactResponse = exports.CreateArtifactRequest = exports.FinalizeMigratedArtifactResponse = exports.FinalizeMigratedArtifactRequest = exports.MigrateArtifactResponse = exports.MigrateArtifactRequest = void 0;
|
||||
// @generated by protobuf-ts 2.9.1 with parameter long_type_string,client_none,generate_dependencies
|
||||
// @generated from protobuf file "results/api/v1/artifact.proto" (package "github.actions.results.api.v1", syntax proto3)
|
||||
// tslint:disable
|
||||
@@ -838,6 +838,236 @@ const wrappers_1 = __nccwpck_require__(8626);
|
||||
const wrappers_2 = __nccwpck_require__(8626);
|
||||
const timestamp_1 = __nccwpck_require__(54622);
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class MigrateArtifactRequest$Type extends runtime_5.MessageType {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.MigrateArtifactRequest", [
|
||||
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "expires_at", kind: "message", T: () => timestamp_1.Timestamp }
|
||||
]);
|
||||
}
|
||||
create(value) {
|
||||
const message = { workflowRunBackendId: "", name: "" };
|
||||
globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
(0, runtime_3.reflectionMergePartial)(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader, length, options, target) {
|
||||
let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string workflow_run_backend_id */ 1:
|
||||
message.workflowRunBackendId = reader.string();
|
||||
break;
|
||||
case /* string name */ 2:
|
||||
message.name = reader.string();
|
||||
break;
|
||||
case /* google.protobuf.Timestamp expires_at */ 3:
|
||||
message.expiresAt = timestamp_1.Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.expiresAt);
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message, writer, options) {
|
||||
/* string workflow_run_backend_id = 1; */
|
||||
if (message.workflowRunBackendId !== "")
|
||||
writer.tag(1, runtime_1.WireType.LengthDelimited).string(message.workflowRunBackendId);
|
||||
/* string name = 2; */
|
||||
if (message.name !== "")
|
||||
writer.tag(2, runtime_1.WireType.LengthDelimited).string(message.name);
|
||||
/* google.protobuf.Timestamp expires_at = 3; */
|
||||
if (message.expiresAt)
|
||||
timestamp_1.Timestamp.internalBinaryWrite(message.expiresAt, writer.tag(3, runtime_1.WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.MigrateArtifactRequest
|
||||
*/
|
||||
exports.MigrateArtifactRequest = new MigrateArtifactRequest$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class MigrateArtifactResponse$Type extends runtime_5.MessageType {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.MigrateArtifactResponse", [
|
||||
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
||||
{ no: 2, name: "signed_upload_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
||||
]);
|
||||
}
|
||||
create(value) {
|
||||
const message = { ok: false, signedUploadUrl: "" };
|
||||
globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
(0, runtime_3.reflectionMergePartial)(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader, length, options, target) {
|
||||
let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* bool ok */ 1:
|
||||
message.ok = reader.bool();
|
||||
break;
|
||||
case /* string signed_upload_url */ 2:
|
||||
message.signedUploadUrl = reader.string();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message, writer, options) {
|
||||
/* bool ok = 1; */
|
||||
if (message.ok !== false)
|
||||
writer.tag(1, runtime_1.WireType.Varint).bool(message.ok);
|
||||
/* string signed_upload_url = 2; */
|
||||
if (message.signedUploadUrl !== "")
|
||||
writer.tag(2, runtime_1.WireType.LengthDelimited).string(message.signedUploadUrl);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.MigrateArtifactResponse
|
||||
*/
|
||||
exports.MigrateArtifactResponse = new MigrateArtifactResponse$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class FinalizeMigratedArtifactRequest$Type extends runtime_5.MessageType {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.FinalizeMigratedArtifactRequest", [
|
||||
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
|
||||
]);
|
||||
}
|
||||
create(value) {
|
||||
const message = { workflowRunBackendId: "", name: "", size: "0" };
|
||||
globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
(0, runtime_3.reflectionMergePartial)(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader, length, options, target) {
|
||||
let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string workflow_run_backend_id */ 1:
|
||||
message.workflowRunBackendId = reader.string();
|
||||
break;
|
||||
case /* string name */ 2:
|
||||
message.name = reader.string();
|
||||
break;
|
||||
case /* int64 size */ 3:
|
||||
message.size = reader.int64().toString();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message, writer, options) {
|
||||
/* string workflow_run_backend_id = 1; */
|
||||
if (message.workflowRunBackendId !== "")
|
||||
writer.tag(1, runtime_1.WireType.LengthDelimited).string(message.workflowRunBackendId);
|
||||
/* string name = 2; */
|
||||
if (message.name !== "")
|
||||
writer.tag(2, runtime_1.WireType.LengthDelimited).string(message.name);
|
||||
/* int64 size = 3; */
|
||||
if (message.size !== "0")
|
||||
writer.tag(3, runtime_1.WireType.Varint).int64(message.size);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeMigratedArtifactRequest
|
||||
*/
|
||||
exports.FinalizeMigratedArtifactRequest = new FinalizeMigratedArtifactRequest$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class FinalizeMigratedArtifactResponse$Type extends runtime_5.MessageType {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.FinalizeMigratedArtifactResponse", [
|
||||
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
||||
{ no: 2, name: "artifact_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
|
||||
]);
|
||||
}
|
||||
create(value) {
|
||||
const message = { ok: false, artifactId: "0" };
|
||||
globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
(0, runtime_3.reflectionMergePartial)(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader, length, options, target) {
|
||||
let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* bool ok */ 1:
|
||||
message.ok = reader.bool();
|
||||
break;
|
||||
case /* int64 artifact_id */ 2:
|
||||
message.artifactId = reader.int64().toString();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message, writer, options) {
|
||||
/* bool ok = 1; */
|
||||
if (message.ok !== false)
|
||||
writer.tag(1, runtime_1.WireType.Varint).bool(message.ok);
|
||||
/* int64 artifact_id = 2; */
|
||||
if (message.artifactId !== "0")
|
||||
writer.tag(2, runtime_1.WireType.Varint).int64(message.artifactId);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeMigratedArtifactResponse
|
||||
*/
|
||||
exports.FinalizeMigratedArtifactResponse = new FinalizeMigratedArtifactResponse$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class CreateArtifactRequest$Type extends runtime_5.MessageType {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.CreateArtifactRequest", [
|
||||
@@ -1219,7 +1449,8 @@ class ListArtifactsResponse_MonolithArtifact$Type extends runtime_5.MessageType
|
||||
{ no: 3, name: "database_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
|
||||
{ no: 4, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 5, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
|
||||
{ no: 6, name: "created_at", kind: "message", T: () => timestamp_1.Timestamp }
|
||||
{ no: 6, name: "created_at", kind: "message", T: () => timestamp_1.Timestamp },
|
||||
{ no: 7, name: "digest", kind: "message", T: () => wrappers_2.StringValue }
|
||||
]);
|
||||
}
|
||||
create(value) {
|
||||
@@ -1252,6 +1483,9 @@ class ListArtifactsResponse_MonolithArtifact$Type extends runtime_5.MessageType
|
||||
case /* google.protobuf.Timestamp created_at */ 6:
|
||||
message.createdAt = timestamp_1.Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.createdAt);
|
||||
break;
|
||||
case /* google.protobuf.StringValue digest */ 7:
|
||||
message.digest = wrappers_2.StringValue.internalBinaryRead(reader, reader.uint32(), options, message.digest);
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
@@ -1282,6 +1516,9 @@ class ListArtifactsResponse_MonolithArtifact$Type extends runtime_5.MessageType
|
||||
/* google.protobuf.Timestamp created_at = 6; */
|
||||
if (message.createdAt)
|
||||
timestamp_1.Timestamp.internalBinaryWrite(message.createdAt, writer.tag(6, runtime_1.WireType.LengthDelimited).fork(), options).join();
|
||||
/* google.protobuf.StringValue digest = 7; */
|
||||
if (message.digest)
|
||||
wrappers_2.StringValue.internalBinaryWrite(message.digest, writer.tag(7, runtime_1.WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
@@ -1523,29 +1760,21 @@ exports.ArtifactService = new runtime_rpc_1.ServiceType("github.actions.results.
|
||||
{ name: "FinalizeArtifact", options: {}, I: exports.FinalizeArtifactRequest, O: exports.FinalizeArtifactResponse },
|
||||
{ name: "ListArtifacts", options: {}, I: exports.ListArtifactsRequest, O: exports.ListArtifactsResponse },
|
||||
{ name: "GetSignedArtifactURL", options: {}, I: exports.GetSignedArtifactURLRequest, O: exports.GetSignedArtifactURLResponse },
|
||||
{ name: "DeleteArtifact", options: {}, I: exports.DeleteArtifactRequest, O: exports.DeleteArtifactResponse }
|
||||
{ name: "DeleteArtifact", options: {}, I: exports.DeleteArtifactRequest, O: exports.DeleteArtifactResponse },
|
||||
{ name: "MigrateArtifact", options: {}, I: exports.MigrateArtifactRequest, O: exports.MigrateArtifactResponse },
|
||||
{ name: "FinalizeMigratedArtifact", options: {}, I: exports.FinalizeMigratedArtifactRequest, O: exports.FinalizeMigratedArtifactResponse }
|
||||
]);
|
||||
//# sourceMappingURL=artifact.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 63077:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
/***/ 49773:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.createArtifactServiceServer = exports.ArtifactServiceMethodList = exports.ArtifactServiceMethod = exports.ArtifactServiceClientProtobuf = exports.ArtifactServiceClientJSON = void 0;
|
||||
const twirp_ts_1 = __nccwpck_require__(66465);
|
||||
exports.ArtifactServiceClientProtobuf = exports.ArtifactServiceClientJSON = void 0;
|
||||
const artifact_1 = __nccwpck_require__(58178);
|
||||
class ArtifactServiceClientJSON {
|
||||
constructor(rpc) {
|
||||
@@ -1642,405 +1871,7 @@ class ArtifactServiceClientProtobuf {
|
||||
}
|
||||
}
|
||||
exports.ArtifactServiceClientProtobuf = ArtifactServiceClientProtobuf;
|
||||
var ArtifactServiceMethod;
|
||||
(function (ArtifactServiceMethod) {
|
||||
ArtifactServiceMethod["CreateArtifact"] = "CreateArtifact";
|
||||
ArtifactServiceMethod["FinalizeArtifact"] = "FinalizeArtifact";
|
||||
ArtifactServiceMethod["ListArtifacts"] = "ListArtifacts";
|
||||
ArtifactServiceMethod["GetSignedArtifactURL"] = "GetSignedArtifactURL";
|
||||
ArtifactServiceMethod["DeleteArtifact"] = "DeleteArtifact";
|
||||
})(ArtifactServiceMethod || (exports.ArtifactServiceMethod = ArtifactServiceMethod = {}));
|
||||
exports.ArtifactServiceMethodList = [
|
||||
ArtifactServiceMethod.CreateArtifact,
|
||||
ArtifactServiceMethod.FinalizeArtifact,
|
||||
ArtifactServiceMethod.ListArtifacts,
|
||||
ArtifactServiceMethod.GetSignedArtifactURL,
|
||||
ArtifactServiceMethod.DeleteArtifact,
|
||||
];
|
||||
function createArtifactServiceServer(service) {
|
||||
return new twirp_ts_1.TwirpServer({
|
||||
service,
|
||||
packageName: "github.actions.results.api.v1",
|
||||
serviceName: "ArtifactService",
|
||||
methodList: exports.ArtifactServiceMethodList,
|
||||
matchRoute: matchArtifactServiceRoute,
|
||||
});
|
||||
}
|
||||
exports.createArtifactServiceServer = createArtifactServiceServer;
|
||||
function matchArtifactServiceRoute(method, events) {
|
||||
switch (method) {
|
||||
case "CreateArtifact":
|
||||
return (ctx, service, data, interceptors) => __awaiter(this, void 0, void 0, function* () {
|
||||
ctx = Object.assign(Object.assign({}, ctx), { methodName: "CreateArtifact" });
|
||||
yield events.onMatch(ctx);
|
||||
return handleArtifactServiceCreateArtifactRequest(ctx, service, data, interceptors);
|
||||
});
|
||||
case "FinalizeArtifact":
|
||||
return (ctx, service, data, interceptors) => __awaiter(this, void 0, void 0, function* () {
|
||||
ctx = Object.assign(Object.assign({}, ctx), { methodName: "FinalizeArtifact" });
|
||||
yield events.onMatch(ctx);
|
||||
return handleArtifactServiceFinalizeArtifactRequest(ctx, service, data, interceptors);
|
||||
});
|
||||
case "ListArtifacts":
|
||||
return (ctx, service, data, interceptors) => __awaiter(this, void 0, void 0, function* () {
|
||||
ctx = Object.assign(Object.assign({}, ctx), { methodName: "ListArtifacts" });
|
||||
yield events.onMatch(ctx);
|
||||
return handleArtifactServiceListArtifactsRequest(ctx, service, data, interceptors);
|
||||
});
|
||||
case "GetSignedArtifactURL":
|
||||
return (ctx, service, data, interceptors) => __awaiter(this, void 0, void 0, function* () {
|
||||
ctx = Object.assign(Object.assign({}, ctx), { methodName: "GetSignedArtifactURL" });
|
||||
yield events.onMatch(ctx);
|
||||
return handleArtifactServiceGetSignedArtifactURLRequest(ctx, service, data, interceptors);
|
||||
});
|
||||
case "DeleteArtifact":
|
||||
return (ctx, service, data, interceptors) => __awaiter(this, void 0, void 0, function* () {
|
||||
ctx = Object.assign(Object.assign({}, ctx), { methodName: "DeleteArtifact" });
|
||||
yield events.onMatch(ctx);
|
||||
return handleArtifactServiceDeleteArtifactRequest(ctx, service, data, interceptors);
|
||||
});
|
||||
default:
|
||||
events.onNotFound();
|
||||
const msg = `no handler found`;
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
function handleArtifactServiceCreateArtifactRequest(ctx, service, data, interceptors) {
|
||||
switch (ctx.contentType) {
|
||||
case twirp_ts_1.TwirpContentType.JSON:
|
||||
return handleArtifactServiceCreateArtifactJSON(ctx, service, data, interceptors);
|
||||
case twirp_ts_1.TwirpContentType.Protobuf:
|
||||
return handleArtifactServiceCreateArtifactProtobuf(ctx, service, data, interceptors);
|
||||
default:
|
||||
const msg = "unexpected Content-Type";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
function handleArtifactServiceFinalizeArtifactRequest(ctx, service, data, interceptors) {
|
||||
switch (ctx.contentType) {
|
||||
case twirp_ts_1.TwirpContentType.JSON:
|
||||
return handleArtifactServiceFinalizeArtifactJSON(ctx, service, data, interceptors);
|
||||
case twirp_ts_1.TwirpContentType.Protobuf:
|
||||
return handleArtifactServiceFinalizeArtifactProtobuf(ctx, service, data, interceptors);
|
||||
default:
|
||||
const msg = "unexpected Content-Type";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
function handleArtifactServiceListArtifactsRequest(ctx, service, data, interceptors) {
|
||||
switch (ctx.contentType) {
|
||||
case twirp_ts_1.TwirpContentType.JSON:
|
||||
return handleArtifactServiceListArtifactsJSON(ctx, service, data, interceptors);
|
||||
case twirp_ts_1.TwirpContentType.Protobuf:
|
||||
return handleArtifactServiceListArtifactsProtobuf(ctx, service, data, interceptors);
|
||||
default:
|
||||
const msg = "unexpected Content-Type";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
function handleArtifactServiceGetSignedArtifactURLRequest(ctx, service, data, interceptors) {
|
||||
switch (ctx.contentType) {
|
||||
case twirp_ts_1.TwirpContentType.JSON:
|
||||
return handleArtifactServiceGetSignedArtifactURLJSON(ctx, service, data, interceptors);
|
||||
case twirp_ts_1.TwirpContentType.Protobuf:
|
||||
return handleArtifactServiceGetSignedArtifactURLProtobuf(ctx, service, data, interceptors);
|
||||
default:
|
||||
const msg = "unexpected Content-Type";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
function handleArtifactServiceDeleteArtifactRequest(ctx, service, data, interceptors) {
|
||||
switch (ctx.contentType) {
|
||||
case twirp_ts_1.TwirpContentType.JSON:
|
||||
return handleArtifactServiceDeleteArtifactJSON(ctx, service, data, interceptors);
|
||||
case twirp_ts_1.TwirpContentType.Protobuf:
|
||||
return handleArtifactServiceDeleteArtifactProtobuf(ctx, service, data, interceptors);
|
||||
default:
|
||||
const msg = "unexpected Content-Type";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
function handleArtifactServiceCreateArtifactJSON(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
const body = JSON.parse(data.toString() || "{}");
|
||||
request = artifact_1.CreateArtifactRequest.fromJson(body, {
|
||||
ignoreUnknownFields: true,
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.CreateArtifact(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.CreateArtifact(ctx, request);
|
||||
}
|
||||
return JSON.stringify(artifact_1.CreateArtifactResponse.toJson(response, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false,
|
||||
}));
|
||||
});
|
||||
}
|
||||
function handleArtifactServiceFinalizeArtifactJSON(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
const body = JSON.parse(data.toString() || "{}");
|
||||
request = artifact_1.FinalizeArtifactRequest.fromJson(body, {
|
||||
ignoreUnknownFields: true,
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.FinalizeArtifact(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.FinalizeArtifact(ctx, request);
|
||||
}
|
||||
return JSON.stringify(artifact_1.FinalizeArtifactResponse.toJson(response, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false,
|
||||
}));
|
||||
});
|
||||
}
|
||||
function handleArtifactServiceListArtifactsJSON(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
const body = JSON.parse(data.toString() || "{}");
|
||||
request = artifact_1.ListArtifactsRequest.fromJson(body, {
|
||||
ignoreUnknownFields: true,
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.ListArtifacts(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.ListArtifacts(ctx, request);
|
||||
}
|
||||
return JSON.stringify(artifact_1.ListArtifactsResponse.toJson(response, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false,
|
||||
}));
|
||||
});
|
||||
}
|
||||
function handleArtifactServiceGetSignedArtifactURLJSON(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
const body = JSON.parse(data.toString() || "{}");
|
||||
request = artifact_1.GetSignedArtifactURLRequest.fromJson(body, {
|
||||
ignoreUnknownFields: true,
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.GetSignedArtifactURL(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.GetSignedArtifactURL(ctx, request);
|
||||
}
|
||||
return JSON.stringify(artifact_1.GetSignedArtifactURLResponse.toJson(response, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false,
|
||||
}));
|
||||
});
|
||||
}
|
||||
function handleArtifactServiceDeleteArtifactJSON(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
const body = JSON.parse(data.toString() || "{}");
|
||||
request = artifact_1.DeleteArtifactRequest.fromJson(body, {
|
||||
ignoreUnknownFields: true,
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.DeleteArtifact(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.DeleteArtifact(ctx, request);
|
||||
}
|
||||
return JSON.stringify(artifact_1.DeleteArtifactResponse.toJson(response, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false,
|
||||
}));
|
||||
});
|
||||
}
|
||||
function handleArtifactServiceCreateArtifactProtobuf(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
request = artifact_1.CreateArtifactRequest.fromBinary(data);
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the protobuf request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.CreateArtifact(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.CreateArtifact(ctx, request);
|
||||
}
|
||||
return Buffer.from(artifact_1.CreateArtifactResponse.toBinary(response));
|
||||
});
|
||||
}
|
||||
function handleArtifactServiceFinalizeArtifactProtobuf(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
request = artifact_1.FinalizeArtifactRequest.fromBinary(data);
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the protobuf request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.FinalizeArtifact(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.FinalizeArtifact(ctx, request);
|
||||
}
|
||||
return Buffer.from(artifact_1.FinalizeArtifactResponse.toBinary(response));
|
||||
});
|
||||
}
|
||||
function handleArtifactServiceListArtifactsProtobuf(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
request = artifact_1.ListArtifactsRequest.fromBinary(data);
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the protobuf request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.ListArtifacts(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.ListArtifacts(ctx, request);
|
||||
}
|
||||
return Buffer.from(artifact_1.ListArtifactsResponse.toBinary(response));
|
||||
});
|
||||
}
|
||||
function handleArtifactServiceGetSignedArtifactURLProtobuf(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
request = artifact_1.GetSignedArtifactURLRequest.fromBinary(data);
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the protobuf request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.GetSignedArtifactURL(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.GetSignedArtifactURL(ctx, request);
|
||||
}
|
||||
return Buffer.from(artifact_1.GetSignedArtifactURLResponse.toBinary(response));
|
||||
});
|
||||
}
|
||||
function handleArtifactServiceDeleteArtifactProtobuf(ctx, service, data, interceptors) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let request;
|
||||
let response;
|
||||
try {
|
||||
request = artifact_1.DeleteArtifactRequest.fromBinary(data);
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the protobuf request could not be decoded";
|
||||
throw new twirp_ts_1.TwirpError(twirp_ts_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = (0, twirp_ts_1.chainInterceptors)(...interceptors);
|
||||
response = yield interceptor(ctx, request, (ctx, inputReq) => {
|
||||
return service.DeleteArtifact(ctx, inputReq);
|
||||
});
|
||||
}
|
||||
else {
|
||||
response = yield service.DeleteArtifact(ctx, request);
|
||||
}
|
||||
return Buffer.from(artifact_1.DeleteArtifactResponse.toBinary(response));
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=artifact.twirp.js.map
|
||||
//# sourceMappingURL=artifact.twirp-client.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
@@ -2328,9 +2159,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.downloadArtifactInternal = exports.downloadArtifactPublic = exports.streamExtractExternal = void 0;
|
||||
const promises_1 = __importDefault(__nccwpck_require__(73292));
|
||||
const crypto = __importStar(__nccwpck_require__(6113));
|
||||
const stream = __importStar(__nccwpck_require__(12781));
|
||||
const fs_1 = __nccwpck_require__(57147);
|
||||
const path = __importStar(__nccwpck_require__(71017));
|
||||
const github = __importStar(__nccwpck_require__(95438));
|
||||
const core = __importStar(__nccwpck_require__(42186));
|
||||
const httpClient = __importStar(__nccwpck_require__(96255));
|
||||
@@ -2367,13 +2197,9 @@ function streamExtract(url, directory) {
|
||||
let retryCount = 0;
|
||||
while (retryCount < 5) {
|
||||
try {
|
||||
yield streamExtractExternal(url, directory);
|
||||
return;
|
||||
return yield streamExtractExternal(url, directory);
|
||||
}
|
||||
catch (error) {
|
||||
if (error.message.includes('Malformed extraction path')) {
|
||||
throw new Error(`Artifact download failed with unretryable error: ${error.message}`);
|
||||
}
|
||||
retryCount++;
|
||||
core.debug(`Failed to download artifact after ${retryCount} retries due to ${error.message}. Retrying in 5 seconds...`);
|
||||
// wait 5 seconds before retrying
|
||||
@@ -2391,14 +2217,18 @@ function streamExtractExternal(url, directory) {
|
||||
throw new Error(`Unexpected HTTP response from blob storage: ${response.message.statusCode} ${response.message.statusMessage}`);
|
||||
}
|
||||
const timeout = 30 * 1000; // 30 seconds
|
||||
let sha256Digest = undefined;
|
||||
return new Promise((resolve, reject) => {
|
||||
const timerFn = () => {
|
||||
response.message.destroy(new Error(`Blob storage chunk did not respond in ${timeout}ms`));
|
||||
};
|
||||
const timer = setTimeout(timerFn, timeout);
|
||||
const createdDirectories = new Set();
|
||||
createdDirectories.add(directory);
|
||||
response.message
|
||||
const hashStream = crypto.createHash('sha256').setEncoding('hex');
|
||||
const passThrough = new stream.PassThrough();
|
||||
response.message.pipe(passThrough);
|
||||
passThrough.pipe(hashStream);
|
||||
const extractStream = passThrough;
|
||||
extractStream
|
||||
.on('data', () => {
|
||||
timer.refresh();
|
||||
})
|
||||
@@ -2407,47 +2237,16 @@ function streamExtractExternal(url, directory) {
|
||||
clearTimeout(timer);
|
||||
reject(error);
|
||||
})
|
||||
.pipe(unzip_stream_1.default.Parse())
|
||||
.pipe(new stream.Transform({
|
||||
objectMode: true,
|
||||
transform: (entry, _, callback) => __awaiter(this, void 0, void 0, function* () {
|
||||
const fullPath = path.normalize(path.join(directory, entry.path));
|
||||
if (!directory.endsWith(path.sep)) {
|
||||
directory += path.sep;
|
||||
}
|
||||
if (!fullPath.startsWith(directory)) {
|
||||
reject(new Error(`Malformed extraction path: ${fullPath}`));
|
||||
}
|
||||
if (entry.type === 'Directory') {
|
||||
if (!createdDirectories.has(fullPath)) {
|
||||
createdDirectories.add(fullPath);
|
||||
yield resolveOrCreateDirectory(fullPath).then(() => {
|
||||
entry.autodrain();
|
||||
callback();
|
||||
});
|
||||
}
|
||||
else {
|
||||
entry.autodrain();
|
||||
callback();
|
||||
}
|
||||
}
|
||||
else {
|
||||
core.info(`Extracting artifact entry: ${fullPath}`);
|
||||
if (!createdDirectories.has(path.dirname(fullPath))) {
|
||||
createdDirectories.add(path.dirname(fullPath));
|
||||
yield resolveOrCreateDirectory(path.dirname(fullPath));
|
||||
}
|
||||
const writeStream = (0, fs_1.createWriteStream)(fullPath);
|
||||
writeStream.on('finish', callback);
|
||||
writeStream.on('error', reject);
|
||||
entry.pipe(writeStream);
|
||||
}
|
||||
})
|
||||
}))
|
||||
.on('finish', () => __awaiter(this, void 0, void 0, function* () {
|
||||
.pipe(unzip_stream_1.default.Extract({ path: directory }))
|
||||
.on('close', () => {
|
||||
clearTimeout(timer);
|
||||
resolve();
|
||||
}))
|
||||
if (hashStream) {
|
||||
hashStream.end();
|
||||
sha256Digest = hashStream.read();
|
||||
core.info(`SHA256 digest of downloaded artifact is ${sha256Digest}`);
|
||||
}
|
||||
resolve({ sha256Digest: `sha256:${sha256Digest}` });
|
||||
})
|
||||
.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
@@ -2459,6 +2258,7 @@ function downloadArtifactPublic(artifactId, repositoryOwner, repositoryName, tok
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const downloadPath = yield resolveOrCreateDirectory(options === null || options === void 0 ? void 0 : options.path);
|
||||
const api = github.getOctokit(token);
|
||||
let digestMismatch = false;
|
||||
core.info(`Downloading artifact '${artifactId}' from '${repositoryOwner}/${repositoryName}'`);
|
||||
const { headers, status } = yield api.rest.actions.downloadArtifact({
|
||||
owner: repositoryOwner,
|
||||
@@ -2479,13 +2279,20 @@ function downloadArtifactPublic(artifactId, repositoryOwner, repositoryName, tok
|
||||
core.info(`Redirecting to blob download url: ${scrubQueryParameters(location)}`);
|
||||
try {
|
||||
core.info(`Starting download of artifact to: ${downloadPath}`);
|
||||
yield streamExtract(location, downloadPath);
|
||||
const extractResponse = yield streamExtract(location, downloadPath);
|
||||
core.info(`Artifact download completed successfully.`);
|
||||
if (options === null || options === void 0 ? void 0 : options.expectedHash) {
|
||||
if ((options === null || options === void 0 ? void 0 : options.expectedHash) !== extractResponse.sha256Digest) {
|
||||
digestMismatch = true;
|
||||
core.debug(`Computed digest: ${extractResponse.sha256Digest}`);
|
||||
core.debug(`Expected digest: ${options.expectedHash}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error(`Unable to download and extract artifact: ${error.message}`);
|
||||
}
|
||||
return { downloadPath };
|
||||
return { downloadPath, digestMismatch };
|
||||
});
|
||||
}
|
||||
exports.downloadArtifactPublic = downloadArtifactPublic;
|
||||
@@ -2493,6 +2300,7 @@ function downloadArtifactInternal(artifactId, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const downloadPath = yield resolveOrCreateDirectory(options === null || options === void 0 ? void 0 : options.path);
|
||||
const artifactClient = (0, artifact_twirp_client_1.internalArtifactTwirpClient)();
|
||||
let digestMismatch = false;
|
||||
const { workflowRunBackendId, workflowJobRunBackendId } = (0, util_1.getBackendIdsFromToken)();
|
||||
const listReq = {
|
||||
workflowRunBackendId,
|
||||
@@ -2515,13 +2323,20 @@ function downloadArtifactInternal(artifactId, options) {
|
||||
core.info(`Redirecting to blob download url: ${scrubQueryParameters(signedUrl)}`);
|
||||
try {
|
||||
core.info(`Starting download of artifact to: ${downloadPath}`);
|
||||
yield streamExtract(signedUrl, downloadPath);
|
||||
const extractResponse = yield streamExtract(signedUrl, downloadPath);
|
||||
core.info(`Artifact download completed successfully.`);
|
||||
if (options === null || options === void 0 ? void 0 : options.expectedHash) {
|
||||
if ((options === null || options === void 0 ? void 0 : options.expectedHash) !== extractResponse.sha256Digest) {
|
||||
digestMismatch = true;
|
||||
core.debug(`Computed digest: ${extractResponse.sha256Digest}`);
|
||||
core.debug(`Expected digest: ${options.expectedHash}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error(`Unable to download and extract artifact: ${error.message}`);
|
||||
}
|
||||
return { downloadPath };
|
||||
return { downloadPath, digestMismatch };
|
||||
});
|
||||
}
|
||||
exports.downloadArtifactInternal = downloadArtifactInternal;
|
||||
@@ -2627,13 +2442,17 @@ function getArtifactPublic(artifactName, workflowRunId, repositoryOwner, reposit
|
||||
name: artifact.name,
|
||||
id: artifact.id,
|
||||
size: artifact.size_in_bytes,
|
||||
createdAt: artifact.created_at ? new Date(artifact.created_at) : undefined
|
||||
createdAt: artifact.created_at
|
||||
? new Date(artifact.created_at)
|
||||
: undefined,
|
||||
digest: artifact.digest
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
exports.getArtifactPublic = getArtifactPublic;
|
||||
function getArtifactInternal(artifactName) {
|
||||
var _a;
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const artifactClient = (0, artifact_twirp_client_1.internalArtifactTwirpClient)();
|
||||
const { workflowRunBackendId, workflowJobRunBackendId } = (0, util_1.getBackendIdsFromToken)();
|
||||
@@ -2660,7 +2479,8 @@ function getArtifactInternal(artifactName) {
|
||||
size: Number(artifact.size),
|
||||
createdAt: artifact.createdAt
|
||||
? generated_1.Timestamp.toDate(artifact.createdAt)
|
||||
: undefined
|
||||
: undefined,
|
||||
digest: (_a = artifact.digest) === null || _a === void 0 ? void 0 : _a.value
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -2714,7 +2534,7 @@ function listArtifactsPublic(workflowRunId, repositoryOwner, repositoryName, tok
|
||||
};
|
||||
const github = (0, github_1.getOctokit)(token, opts, plugin_retry_1.retry, plugin_request_log_1.requestLog);
|
||||
let currentPageNumber = 1;
|
||||
const { data: listArtifactResponse } = yield github.rest.actions.listWorkflowRunArtifacts({
|
||||
const { data: listArtifactResponse } = yield github.request('GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts', {
|
||||
owner: repositoryOwner,
|
||||
repo: repositoryName,
|
||||
run_id: workflowRunId,
|
||||
@@ -2733,14 +2553,18 @@ function listArtifactsPublic(workflowRunId, repositoryOwner, repositoryName, tok
|
||||
name: artifact.name,
|
||||
id: artifact.id,
|
||||
size: artifact.size_in_bytes,
|
||||
createdAt: artifact.created_at ? new Date(artifact.created_at) : undefined
|
||||
createdAt: artifact.created_at
|
||||
? new Date(artifact.created_at)
|
||||
: undefined,
|
||||
digest: artifact.digest
|
||||
});
|
||||
}
|
||||
// Move to the next page
|
||||
currentPageNumber++;
|
||||
// Iterate over any remaining pages
|
||||
for (currentPageNumber; currentPageNumber < numberOfPages; currentPageNumber++) {
|
||||
currentPageNumber++;
|
||||
(0, core_1.debug)(`Fetching page ${currentPageNumber} of artifact list`);
|
||||
const { data: listArtifactResponse } = yield github.rest.actions.listWorkflowRunArtifacts({
|
||||
const { data: listArtifactResponse } = yield github.request('GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts', {
|
||||
owner: repositoryOwner,
|
||||
repo: repositoryName,
|
||||
run_id: workflowRunId,
|
||||
@@ -2754,7 +2578,8 @@ function listArtifactsPublic(workflowRunId, repositoryOwner, repositoryName, tok
|
||||
size: artifact.size_in_bytes,
|
||||
createdAt: artifact.created_at
|
||||
? new Date(artifact.created_at)
|
||||
: undefined
|
||||
: undefined,
|
||||
digest: artifact.digest
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2777,14 +2602,18 @@ function listArtifactsInternal(latest = false) {
|
||||
workflowJobRunBackendId
|
||||
};
|
||||
const res = yield artifactClient.ListArtifacts(req);
|
||||
let artifacts = res.artifacts.map(artifact => ({
|
||||
name: artifact.name,
|
||||
id: Number(artifact.databaseId),
|
||||
size: Number(artifact.size),
|
||||
createdAt: artifact.createdAt
|
||||
? generated_1.Timestamp.toDate(artifact.createdAt)
|
||||
: undefined
|
||||
}));
|
||||
let artifacts = res.artifacts.map(artifact => {
|
||||
var _a;
|
||||
return ({
|
||||
name: artifact.name,
|
||||
id: Number(artifact.databaseId),
|
||||
size: Number(artifact.size),
|
||||
createdAt: artifact.createdAt
|
||||
? generated_1.Timestamp.toDate(artifact.createdAt)
|
||||
: undefined,
|
||||
digest: (_a = artifact.digest) === null || _a === void 0 ? void 0 : _a.value
|
||||
});
|
||||
});
|
||||
if (latest) {
|
||||
artifacts = filterLatest(artifacts);
|
||||
}
|
||||
@@ -2896,6 +2725,7 @@ const generated_1 = __nccwpck_require__(49960);
|
||||
const config_1 = __nccwpck_require__(74610);
|
||||
const user_agent_1 = __nccwpck_require__(85164);
|
||||
const errors_1 = __nccwpck_require__(38182);
|
||||
const util_1 = __nccwpck_require__(63062);
|
||||
class ArtifactHttpClient {
|
||||
constructor(userAgent, maxAttempts, baseRetryIntervalMilliseconds, retryMultiplier) {
|
||||
this.maxAttempts = 5;
|
||||
@@ -2948,6 +2778,7 @@ class ArtifactHttpClient {
|
||||
(0, core_1.debug)(`[Response] - ${response.message.statusCode}`);
|
||||
(0, core_1.debug)(`Headers: ${JSON.stringify(response.message.headers, null, 2)}`);
|
||||
const body = JSON.parse(rawBody);
|
||||
(0, util_1.maskSecretUrls)(body);
|
||||
(0, core_1.debug)(`Body: ${JSON.stringify(body, null, 2)}`);
|
||||
if (this.isSuccessStatusCode(statusCode)) {
|
||||
return { response, body };
|
||||
@@ -3041,8 +2872,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.getConcurrency = exports.getGitHubWorkspaceDir = exports.isGhes = exports.getResultsServiceUrl = exports.getRuntimeToken = exports.getUploadChunkSize = void 0;
|
||||
exports.getUploadChunkTimeout = exports.getConcurrency = exports.getGitHubWorkspaceDir = exports.isGhes = exports.getResultsServiceUrl = exports.getRuntimeToken = exports.getUploadChunkSize = void 0;
|
||||
const os_1 = __importDefault(__nccwpck_require__(22037));
|
||||
const core_1 = __nccwpck_require__(42186);
|
||||
// Used for controlling the highWaterMark value of the zip that is being streamed
|
||||
// The same value is used as the chunk size that is use during upload to blob storage
|
||||
function getUploadChunkSize() {
|
||||
@@ -3069,8 +2901,9 @@ function isGhes() {
|
||||
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
||||
const hostname = ghUrl.hostname.trimEnd().toUpperCase();
|
||||
const isGitHubHost = hostname === 'GITHUB.COM';
|
||||
const isGheHost = hostname.endsWith('.GHE.COM') || hostname.endsWith('.GHE.LOCALHOST');
|
||||
return !isGitHubHost && !isGheHost;
|
||||
const isGheHost = hostname.endsWith('.GHE.COM');
|
||||
const isLocalHost = hostname.endsWith('.LOCALHOST');
|
||||
return !isGitHubHost && !isGheHost && !isLocalHost;
|
||||
}
|
||||
exports.isGhes = isGhes;
|
||||
function getGitHubWorkspaceDir() {
|
||||
@@ -3081,18 +2914,44 @@ function getGitHubWorkspaceDir() {
|
||||
return ghWorkspaceDir;
|
||||
}
|
||||
exports.getGitHubWorkspaceDir = getGitHubWorkspaceDir;
|
||||
// Mimics behavior of azcopy: https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-optimize
|
||||
// If your machine has fewer than 5 CPUs, then the value of this variable is set to 32.
|
||||
// Otherwise, the default value is equal to 16 multiplied by the number of CPUs. The maximum value of this variable is 300.
|
||||
// The maximum value of concurrency is 300.
|
||||
// This value can be changed with ACTIONS_ARTIFACT_UPLOAD_CONCURRENCY variable.
|
||||
function getConcurrency() {
|
||||
const numCPUs = os_1.default.cpus().length;
|
||||
if (numCPUs <= 4) {
|
||||
return 32;
|
||||
let concurrencyCap = 32;
|
||||
if (numCPUs > 4) {
|
||||
const concurrency = 16 * numCPUs;
|
||||
concurrencyCap = concurrency > 300 ? 300 : concurrency;
|
||||
}
|
||||
const concurrency = 16 * numCPUs;
|
||||
return concurrency > 300 ? 300 : concurrency;
|
||||
const concurrencyOverride = process.env['ACTIONS_ARTIFACT_UPLOAD_CONCURRENCY'];
|
||||
if (concurrencyOverride) {
|
||||
const concurrency = parseInt(concurrencyOverride);
|
||||
if (isNaN(concurrency) || concurrency < 1) {
|
||||
throw new Error('Invalid value set for ACTIONS_ARTIFACT_UPLOAD_CONCURRENCY env variable');
|
||||
}
|
||||
if (concurrency < concurrencyCap) {
|
||||
(0, core_1.info)(`Set concurrency based on the value set in ACTIONS_ARTIFACT_UPLOAD_CONCURRENCY.`);
|
||||
return concurrency;
|
||||
}
|
||||
(0, core_1.info)(`ACTIONS_ARTIFACT_UPLOAD_CONCURRENCY is higher than the cap of ${concurrencyCap} based on the number of cpus. Set it to the maximum value allowed.`);
|
||||
return concurrencyCap;
|
||||
}
|
||||
// default concurrency to 5
|
||||
return 5;
|
||||
}
|
||||
exports.getConcurrency = getConcurrency;
|
||||
function getUploadChunkTimeout() {
|
||||
const timeoutVar = process.env['ACTIONS_ARTIFACT_UPLOAD_TIMEOUT_MS'];
|
||||
if (!timeoutVar) {
|
||||
return 300000; // 5 minutes
|
||||
}
|
||||
const timeout = parseInt(timeoutVar);
|
||||
if (isNaN(timeout)) {
|
||||
throw new Error('Invalid value set for ACTIONS_ARTIFACT_UPLOAD_TIMEOUT_MS env variable');
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
exports.getUploadChunkTimeout = getUploadChunkTimeout;
|
||||
//# sourceMappingURL=config.js.map
|
||||
|
||||
/***/ }),
|
||||
@@ -3236,10 +3095,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.getBackendIdsFromToken = void 0;
|
||||
exports.maskSecretUrls = exports.maskSigUrl = exports.getBackendIdsFromToken = void 0;
|
||||
const core = __importStar(__nccwpck_require__(42186));
|
||||
const config_1 = __nccwpck_require__(74610);
|
||||
const jwt_decode_1 = __importDefault(__nccwpck_require__(84329));
|
||||
const core_1 = __nccwpck_require__(42186);
|
||||
const InvalidJwtError = new Error('Failed to get backend IDs: The provided JWT token is invalid and/or missing claims');
|
||||
// uses the JWT token claims to get the
|
||||
// workflow run and workflow job run backend ids
|
||||
@@ -3288,6 +3148,74 @@ function getBackendIdsFromToken() {
|
||||
throw InvalidJwtError;
|
||||
}
|
||||
exports.getBackendIdsFromToken = getBackendIdsFromToken;
|
||||
/**
|
||||
* Masks the `sig` parameter in a URL and sets it as a secret.
|
||||
*
|
||||
* @param url - The URL containing the signature parameter to mask
|
||||
* @remarks
|
||||
* This function attempts to parse the provided URL and identify the 'sig' query parameter.
|
||||
* If found, it registers both the raw and URL-encoded signature values as secrets using
|
||||
* the Actions `setSecret` API, which prevents them from being displayed in logs.
|
||||
*
|
||||
* The function handles errors gracefully if URL parsing fails, logging them as debug messages.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Mask a signature in an Azure SAS token URL
|
||||
* maskSigUrl('https://example.blob.core.windows.net/container/file.txt?sig=abc123&se=2023-01-01');
|
||||
* ```
|
||||
*/
|
||||
function maskSigUrl(url) {
|
||||
if (!url)
|
||||
return;
|
||||
try {
|
||||
const parsedUrl = new URL(url);
|
||||
const signature = parsedUrl.searchParams.get('sig');
|
||||
if (signature) {
|
||||
(0, core_1.setSecret)(signature);
|
||||
(0, core_1.setSecret)(encodeURIComponent(signature));
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
(0, core_1.debug)(`Failed to parse URL: ${url} ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
}
|
||||
exports.maskSigUrl = maskSigUrl;
|
||||
/**
|
||||
* Masks sensitive information in URLs containing signature parameters.
|
||||
* Currently supports masking 'sig' parameters in the 'signed_upload_url'
|
||||
* and 'signed_download_url' properties of the provided object.
|
||||
*
|
||||
* @param body - The object should contain a signature
|
||||
* @remarks
|
||||
* This function extracts URLs from the object properties and calls maskSigUrl
|
||||
* on each one to redact sensitive signature information. The function doesn't
|
||||
* modify the original object; it only marks the signatures as secrets for
|
||||
* logging purposes.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const responseBody = {
|
||||
* signed_upload_url: 'https://example.com?sig=abc123',
|
||||
* signed_download_url: 'https://example.com?sig=def456'
|
||||
* };
|
||||
* maskSecretUrls(responseBody);
|
||||
* ```
|
||||
*/
|
||||
function maskSecretUrls(body) {
|
||||
if (typeof body !== 'object' || body === null) {
|
||||
(0, core_1.debug)('body is not an object or is null');
|
||||
return;
|
||||
}
|
||||
if ('signed_upload_url' in body &&
|
||||
typeof body.signed_upload_url === 'string') {
|
||||
maskSigUrl(body.signed_upload_url);
|
||||
}
|
||||
if ('signed_url' in body && typeof body.signed_url === 'string') {
|
||||
maskSigUrl(body.signed_url);
|
||||
}
|
||||
}
|
||||
exports.maskSecretUrls = maskSecretUrls;
|
||||
//# sourceMappingURL=util.js.map
|
||||
|
||||
/***/ }),
|
||||
@@ -3341,37 +3269,34 @@ function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let uploadByteCount = 0;
|
||||
let lastProgressTime = Date.now();
|
||||
let timeoutId;
|
||||
const chunkTimer = (timeout) => {
|
||||
// clear the previous timeout
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
timeoutId = setTimeout(() => {
|
||||
const now = Date.now();
|
||||
// if there's been more than 30 seconds since the
|
||||
// last progress event, then we'll consider the upload stalled
|
||||
if (now - lastProgressTime > timeout) {
|
||||
throw new Error('Upload progress stalled.');
|
||||
}
|
||||
}, timeout);
|
||||
return timeoutId;
|
||||
};
|
||||
const abortController = new AbortController();
|
||||
const chunkTimer = (interval) => __awaiter(this, void 0, void 0, function* () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timer = setInterval(() => {
|
||||
if (Date.now() - lastProgressTime > interval) {
|
||||
reject(new Error('Upload progress stalled.'));
|
||||
}
|
||||
}, interval);
|
||||
abortController.signal.addEventListener('abort', () => {
|
||||
clearInterval(timer);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
const maxConcurrency = (0, config_1.getConcurrency)();
|
||||
const bufferSize = (0, config_1.getUploadChunkSize)();
|
||||
const blobClient = new storage_blob_1.BlobClient(authenticatedUploadURL);
|
||||
const blockBlobClient = blobClient.getBlockBlobClient();
|
||||
const timeoutDuration = 300000; // 30 seconds
|
||||
core.debug(`Uploading artifact zip to blob storage with maxConcurrency: ${maxConcurrency}, bufferSize: ${bufferSize}`);
|
||||
const uploadCallback = (progress) => {
|
||||
core.info(`Uploaded bytes ${progress.loadedBytes}`);
|
||||
uploadByteCount = progress.loadedBytes;
|
||||
chunkTimer(timeoutDuration);
|
||||
lastProgressTime = Date.now();
|
||||
};
|
||||
const options = {
|
||||
blobHTTPHeaders: { blobContentType: 'zip' },
|
||||
onProgress: uploadCallback
|
||||
onProgress: uploadCallback,
|
||||
abortSignal: abortController.signal
|
||||
};
|
||||
let sha256Hash = undefined;
|
||||
const uploadStream = new stream.PassThrough();
|
||||
@@ -3380,9 +3305,10 @@ function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) {
|
||||
zipUploadStream.pipe(hashStream).setEncoding('hex'); // This stream is used to compute a hash of the zip content that gets used. Integrity check
|
||||
core.info('Beginning upload of artifact content to blob storage');
|
||||
try {
|
||||
// Start the chunk timer
|
||||
timeoutId = chunkTimer(timeoutDuration);
|
||||
yield blockBlobClient.uploadStream(uploadStream, bufferSize, maxConcurrency, options);
|
||||
yield Promise.race([
|
||||
blockBlobClient.uploadStream(uploadStream, bufferSize, maxConcurrency, options),
|
||||
chunkTimer((0, config_1.getUploadChunkTimeout)())
|
||||
]);
|
||||
}
|
||||
catch (error) {
|
||||
if (errors_1.NetworkError.isNetworkErrorCode(error === null || error === void 0 ? void 0 : error.code)) {
|
||||
@@ -3391,15 +3317,12 @@ function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) {
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
// clear the timeout whether or not the upload completes
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
abortController.abort();
|
||||
}
|
||||
core.info('Finished uploading artifact content to blob storage!');
|
||||
hashStream.end();
|
||||
sha256Hash = hashStream.read();
|
||||
core.info(`SHA256 hash of uploaded artifact zip is ${sha256Hash}`);
|
||||
core.info(`SHA256 digest of uploaded artifact zip is ${sha256Hash}`);
|
||||
if (uploadByteCount === 0) {
|
||||
core.warning(`No data was uploaded to blob storage. Reported upload byte count is 0.`);
|
||||
}
|
||||
@@ -3650,6 +3573,7 @@ function uploadArtifact(name, files, rootDirectory, options) {
|
||||
core.info(`Artifact ${name}.zip successfully finalized. Artifact ID ${artifactId}`);
|
||||
return {
|
||||
size: uploadResult.uploadSize,
|
||||
digest: uploadResult.sha256Hash,
|
||||
id: Number(artifactId)
|
||||
};
|
||||
});
|
||||
@@ -3744,10 +3668,11 @@ function getUploadZipSpecification(filesToZip, rootDirectory) {
|
||||
- file3.txt
|
||||
*/
|
||||
for (let file of filesToZip) {
|
||||
if (!fs.existsSync(file)) {
|
||||
const stats = fs.lstatSync(file, { throwIfNoEntry: false });
|
||||
if (!stats) {
|
||||
throw new Error(`File ${file} does not exist`);
|
||||
}
|
||||
if (!fs.statSync(file).isDirectory()) {
|
||||
if (!stats.isDirectory()) {
|
||||
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
||||
file = (0, path_1.normalize)(file);
|
||||
file = (0, path_1.resolve)(file);
|
||||
@@ -3759,7 +3684,8 @@ function getUploadZipSpecification(filesToZip, rootDirectory) {
|
||||
(0, path_and_artifact_name_validation_1.validateFilePath)(uploadPath);
|
||||
specification.push({
|
||||
sourcePath: file,
|
||||
destinationPath: uploadPath
|
||||
destinationPath: uploadPath,
|
||||
stats
|
||||
});
|
||||
}
|
||||
else {
|
||||
@@ -3768,7 +3694,8 @@ function getUploadZipSpecification(filesToZip, rootDirectory) {
|
||||
(0, path_and_artifact_name_validation_1.validateFilePath)(directoryPath);
|
||||
specification.push({
|
||||
sourcePath: null,
|
||||
destinationPath: directoryPath
|
||||
destinationPath: directoryPath,
|
||||
stats
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3819,9 +3746,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.createZipUploadStream = exports.ZipUploadStream = exports.DEFAULT_COMPRESSION_LEVEL = void 0;
|
||||
const stream = __importStar(__nccwpck_require__(12781));
|
||||
const promises_1 = __nccwpck_require__(73292);
|
||||
const archiver = __importStar(__nccwpck_require__(43084));
|
||||
const core = __importStar(__nccwpck_require__(42186));
|
||||
const fs_1 = __nccwpck_require__(57147);
|
||||
const config_1 = __nccwpck_require__(74610);
|
||||
exports.DEFAULT_COMPRESSION_LEVEL = 6;
|
||||
// Custom stream transformer so we can set the highWaterMark property
|
||||
@@ -3852,8 +3779,13 @@ function createZipUploadStream(uploadSpecification, compressionLevel = exports.D
|
||||
zip.on('end', zipEndCallback);
|
||||
for (const file of uploadSpecification) {
|
||||
if (file.sourcePath !== null) {
|
||||
// Add a normal file to the zip
|
||||
zip.append((0, fs_1.createReadStream)(file.sourcePath), {
|
||||
// Check if symlink and resolve the source path
|
||||
let sourcePath = file.sourcePath;
|
||||
if (file.stats.isSymbolicLink()) {
|
||||
sourcePath = yield (0, promises_1.realpath)(file.sourcePath);
|
||||
}
|
||||
// Add the file to the zip
|
||||
zip.file(sourcePath, {
|
||||
name: file.destinationPath
|
||||
});
|
||||
}
|
||||
@@ -48153,6 +48085,7 @@ const json_format_contract_1 = __nccwpck_require__(48139);
|
||||
const reflection_equals_1 = __nccwpck_require__(39473);
|
||||
const binary_writer_1 = __nccwpck_require__(44354);
|
||||
const binary_reader_1 = __nccwpck_require__(65210);
|
||||
const baseDescriptors = Object.getOwnPropertyDescriptors(Object.getPrototypeOf({}));
|
||||
/**
|
||||
* This standard message type provides reflection-based
|
||||
* operations to work with a message.
|
||||
@@ -48163,7 +48096,7 @@ class MessageType {
|
||||
this.typeName = name;
|
||||
this.fields = fields.map(reflection_info_1.normalizeFieldInfo);
|
||||
this.options = options !== null && options !== void 0 ? options : {};
|
||||
this.messagePrototype = Object.defineProperty({}, message_type_contract_1.MESSAGE_TYPE, { value: this });
|
||||
this.messagePrototype = Object.create(null, Object.assign(Object.assign({}, baseDescriptors), { [message_type_contract_1.MESSAGE_TYPE]: { value: this } }));
|
||||
this.refTypeCheck = new reflection_type_check_1.ReflectionTypeCheck(this);
|
||||
this.refJsonReader = new reflection_json_reader_1.ReflectionJsonReader(this);
|
||||
this.refJsonWriter = new reflection_json_writer_1.ReflectionJsonWriter(this);
|
||||
@@ -64254,599 +64187,6 @@ class Deprecation extends Error {
|
||||
exports.Deprecation = Deprecation;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 13598:
|
||||
/***/ ((module) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
function _process (v, mod) {
|
||||
var i
|
||||
var r
|
||||
|
||||
if (typeof mod === 'function') {
|
||||
r = mod(v)
|
||||
if (r !== undefined) {
|
||||
v = r
|
||||
}
|
||||
} else if (Array.isArray(mod)) {
|
||||
for (i = 0; i < mod.length; i++) {
|
||||
r = mod[i](v)
|
||||
if (r !== undefined) {
|
||||
v = r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
function parseKey (key, val) {
|
||||
// detect negative index notation
|
||||
if (key[0] === '-' && Array.isArray(val) && /^-\d+$/.test(key)) {
|
||||
return val.length + parseInt(key, 10)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
function isIndex (k) {
|
||||
return /^\d+$/.test(k)
|
||||
}
|
||||
|
||||
function isObject (val) {
|
||||
return Object.prototype.toString.call(val) === '[object Object]'
|
||||
}
|
||||
|
||||
function isArrayOrObject (val) {
|
||||
return Object(val) === val
|
||||
}
|
||||
|
||||
function isEmptyObject (val) {
|
||||
return Object.keys(val).length === 0
|
||||
}
|
||||
|
||||
var blacklist = ['__proto__', 'prototype', 'constructor']
|
||||
var blacklistFilter = function (part) { return blacklist.indexOf(part) === -1 }
|
||||
|
||||
function parsePath (path, sep) {
|
||||
if (path.indexOf('[') >= 0) {
|
||||
path = path.replace(/\[/g, sep).replace(/]/g, '')
|
||||
}
|
||||
|
||||
var parts = path.split(sep)
|
||||
|
||||
var check = parts.filter(blacklistFilter)
|
||||
|
||||
if (check.length !== parts.length) {
|
||||
throw Error('Refusing to update blacklisted property ' + path)
|
||||
}
|
||||
|
||||
return parts
|
||||
}
|
||||
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty
|
||||
|
||||
function DotObject (separator, override, useArray, useBrackets) {
|
||||
if (!(this instanceof DotObject)) {
|
||||
return new DotObject(separator, override, useArray, useBrackets)
|
||||
}
|
||||
|
||||
if (typeof override === 'undefined') override = false
|
||||
if (typeof useArray === 'undefined') useArray = true
|
||||
if (typeof useBrackets === 'undefined') useBrackets = true
|
||||
this.separator = separator || '.'
|
||||
this.override = override
|
||||
this.useArray = useArray
|
||||
this.useBrackets = useBrackets
|
||||
this.keepArray = false
|
||||
|
||||
// contains touched arrays
|
||||
this.cleanup = []
|
||||
}
|
||||
|
||||
var dotDefault = new DotObject('.', false, true, true)
|
||||
function wrap (method) {
|
||||
return function () {
|
||||
return dotDefault[method].apply(dotDefault, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
DotObject.prototype._fill = function (a, obj, v, mod) {
|
||||
var k = a.shift()
|
||||
|
||||
if (a.length > 0) {
|
||||
obj[k] = obj[k] || (this.useArray && isIndex(a[0]) ? [] : {})
|
||||
|
||||
if (!isArrayOrObject(obj[k])) {
|
||||
if (this.override) {
|
||||
obj[k] = {}
|
||||
} else {
|
||||
if (!(isArrayOrObject(v) && isEmptyObject(v))) {
|
||||
throw new Error(
|
||||
'Trying to redefine `' + k + '` which is a ' + typeof obj[k]
|
||||
)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this._fill(a, obj[k], v, mod)
|
||||
} else {
|
||||
if (!this.override && isArrayOrObject(obj[k]) && !isEmptyObject(obj[k])) {
|
||||
if (!(isArrayOrObject(v) && isEmptyObject(v))) {
|
||||
throw new Error("Trying to redefine non-empty obj['" + k + "']")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
obj[k] = _process(v, mod)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Converts an object with dotted-key/value pairs to it's expanded version
|
||||
*
|
||||
* Optionally transformed by a set of modifiers.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* var row = {
|
||||
* 'nr': 200,
|
||||
* 'doc.name': ' My Document '
|
||||
* }
|
||||
*
|
||||
* var mods = {
|
||||
* 'doc.name': [_s.trim, _s.underscored]
|
||||
* }
|
||||
*
|
||||
* dot.object(row, mods)
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @param {Object} mods
|
||||
*/
|
||||
DotObject.prototype.object = function (obj, mods) {
|
||||
var self = this
|
||||
|
||||
Object.keys(obj).forEach(function (k) {
|
||||
var mod = mods === undefined ? null : mods[k]
|
||||
// normalize array notation.
|
||||
var ok = parsePath(k, self.separator).join(self.separator)
|
||||
|
||||
if (ok.indexOf(self.separator) !== -1) {
|
||||
self._fill(ok.split(self.separator), obj, obj[k], mod)
|
||||
delete obj[k]
|
||||
} else {
|
||||
obj[k] = _process(obj[k], mod)
|
||||
}
|
||||
})
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} path dotted path
|
||||
* @param {String} v value to be set
|
||||
* @param {Object} obj object to be modified
|
||||
* @param {Function|Array} mod optional modifier
|
||||
*/
|
||||
DotObject.prototype.str = function (path, v, obj, mod) {
|
||||
var ok = parsePath(path, this.separator).join(this.separator)
|
||||
|
||||
if (path.indexOf(this.separator) !== -1) {
|
||||
this._fill(ok.split(this.separator), obj, v, mod)
|
||||
} else {
|
||||
obj[path] = _process(v, mod)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Pick a value from an object using dot notation.
|
||||
*
|
||||
* Optionally remove the value
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Object} obj
|
||||
* @param {Boolean} remove
|
||||
*/
|
||||
DotObject.prototype.pick = function (path, obj, remove, reindexArray) {
|
||||
var i
|
||||
var keys
|
||||
var val
|
||||
var key
|
||||
var cp
|
||||
|
||||
keys = parsePath(path, this.separator)
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
key = parseKey(keys[i], obj)
|
||||
if (obj && typeof obj === 'object' && key in obj) {
|
||||
if (i === keys.length - 1) {
|
||||
if (remove) {
|
||||
val = obj[key]
|
||||
if (reindexArray && Array.isArray(obj)) {
|
||||
obj.splice(key, 1)
|
||||
} else {
|
||||
delete obj[key]
|
||||
}
|
||||
if (Array.isArray(obj)) {
|
||||
cp = keys.slice(0, -1).join('.')
|
||||
if (this.cleanup.indexOf(cp) === -1) {
|
||||
this.cleanup.push(cp)
|
||||
}
|
||||
}
|
||||
return val
|
||||
} else {
|
||||
return obj[key]
|
||||
}
|
||||
} else {
|
||||
obj = obj[key]
|
||||
}
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
if (remove && Array.isArray(obj)) {
|
||||
obj = obj.filter(function (n) {
|
||||
return n !== undefined
|
||||
})
|
||||
}
|
||||
return obj
|
||||
}
|
||||
/**
|
||||
*
|
||||
* Delete value from an object using dot notation.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Object} obj
|
||||
* @return {any} The removed value
|
||||
*/
|
||||
DotObject.prototype.delete = function (path, obj) {
|
||||
return this.remove(path, obj, true)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Remove value from an object using dot notation.
|
||||
*
|
||||
* Will remove multiple items if path is an array.
|
||||
* In this case array indexes will be retained until all
|
||||
* removals have been processed.
|
||||
*
|
||||
* Use dot.delete() to automatically re-index arrays.
|
||||
*
|
||||
* @param {String|Array<String>} path
|
||||
* @param {Object} obj
|
||||
* @param {Boolean} reindexArray
|
||||
* @return {any} The removed value
|
||||
*/
|
||||
DotObject.prototype.remove = function (path, obj, reindexArray) {
|
||||
var i
|
||||
|
||||
this.cleanup = []
|
||||
if (Array.isArray(path)) {
|
||||
for (i = 0; i < path.length; i++) {
|
||||
this.pick(path[i], obj, true, reindexArray)
|
||||
}
|
||||
if (!reindexArray) {
|
||||
this._cleanup(obj)
|
||||
}
|
||||
return obj
|
||||
} else {
|
||||
return this.pick(path, obj, true, reindexArray)
|
||||
}
|
||||
}
|
||||
|
||||
DotObject.prototype._cleanup = function (obj) {
|
||||
var ret
|
||||
var i
|
||||
var keys
|
||||
var root
|
||||
if (this.cleanup.length) {
|
||||
for (i = 0; i < this.cleanup.length; i++) {
|
||||
keys = this.cleanup[i].split('.')
|
||||
root = keys.splice(0, -1).join('.')
|
||||
ret = root ? this.pick(root, obj) : obj
|
||||
ret = ret[keys[0]].filter(function (v) {
|
||||
return v !== undefined
|
||||
})
|
||||
this.set(this.cleanup[i], ret, obj)
|
||||
}
|
||||
this.cleanup = []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias method for `dot.remove`
|
||||
*
|
||||
* Note: this is not an alias for dot.delete()
|
||||
*
|
||||
* @param {String|Array<String>} path
|
||||
* @param {Object} obj
|
||||
* @param {Boolean} reindexArray
|
||||
* @return {any} The removed value
|
||||
*/
|
||||
DotObject.prototype.del = DotObject.prototype.remove
|
||||
|
||||
/**
|
||||
*
|
||||
* Move a property from one place to the other.
|
||||
*
|
||||
* If the source path does not exist (undefined)
|
||||
* the target property will not be set.
|
||||
*
|
||||
* @param {String} source
|
||||
* @param {String} target
|
||||
* @param {Object} obj
|
||||
* @param {Function|Array} mods
|
||||
* @param {Boolean} merge
|
||||
*/
|
||||
DotObject.prototype.move = function (source, target, obj, mods, merge) {
|
||||
if (typeof mods === 'function' || Array.isArray(mods)) {
|
||||
this.set(target, _process(this.pick(source, obj, true), mods), obj, merge)
|
||||
} else {
|
||||
merge = mods
|
||||
this.set(target, this.pick(source, obj, true), obj, merge)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Transfer a property from one object to another object.
|
||||
*
|
||||
* If the source path does not exist (undefined)
|
||||
* the property on the other object will not be set.
|
||||
*
|
||||
* @param {String} source
|
||||
* @param {String} target
|
||||
* @param {Object} obj1
|
||||
* @param {Object} obj2
|
||||
* @param {Function|Array} mods
|
||||
* @param {Boolean} merge
|
||||
*/
|
||||
DotObject.prototype.transfer = function (
|
||||
source,
|
||||
target,
|
||||
obj1,
|
||||
obj2,
|
||||
mods,
|
||||
merge
|
||||
) {
|
||||
if (typeof mods === 'function' || Array.isArray(mods)) {
|
||||
this.set(
|
||||
target,
|
||||
_process(this.pick(source, obj1, true), mods),
|
||||
obj2,
|
||||
merge
|
||||
)
|
||||
} else {
|
||||
merge = mods
|
||||
this.set(target, this.pick(source, obj1, true), obj2, merge)
|
||||
}
|
||||
|
||||
return obj2
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Copy a property from one object to another object.
|
||||
*
|
||||
* If the source path does not exist (undefined)
|
||||
* the property on the other object will not be set.
|
||||
*
|
||||
* @param {String} source
|
||||
* @param {String} target
|
||||
* @param {Object} obj1
|
||||
* @param {Object} obj2
|
||||
* @param {Function|Array} mods
|
||||
* @param {Boolean} merge
|
||||
*/
|
||||
DotObject.prototype.copy = function (source, target, obj1, obj2, mods, merge) {
|
||||
if (typeof mods === 'function' || Array.isArray(mods)) {
|
||||
this.set(
|
||||
target,
|
||||
_process(
|
||||
// clone what is picked
|
||||
JSON.parse(JSON.stringify(this.pick(source, obj1, false))),
|
||||
mods
|
||||
),
|
||||
obj2,
|
||||
merge
|
||||
)
|
||||
} else {
|
||||
merge = mods
|
||||
this.set(target, this.pick(source, obj1, false), obj2, merge)
|
||||
}
|
||||
|
||||
return obj2
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Set a property on an object using dot notation.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {any} val
|
||||
* @param {Object} obj
|
||||
* @param {Boolean} merge
|
||||
*/
|
||||
DotObject.prototype.set = function (path, val, obj, merge) {
|
||||
var i
|
||||
var k
|
||||
var keys
|
||||
var key
|
||||
|
||||
// Do not operate if the value is undefined.
|
||||
if (typeof val === 'undefined') {
|
||||
return obj
|
||||
}
|
||||
keys = parsePath(path, this.separator)
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
key = keys[i]
|
||||
if (i === keys.length - 1) {
|
||||
if (merge && isObject(val) && isObject(obj[key])) {
|
||||
for (k in val) {
|
||||
if (hasOwnProperty.call(val, k)) {
|
||||
obj[key][k] = val[k]
|
||||
}
|
||||
}
|
||||
} else if (merge && Array.isArray(obj[key]) && Array.isArray(val)) {
|
||||
for (var j = 0; j < val.length; j++) {
|
||||
obj[keys[i]].push(val[j])
|
||||
}
|
||||
} else {
|
||||
obj[key] = val
|
||||
}
|
||||
} else if (
|
||||
// force the value to be an object
|
||||
!hasOwnProperty.call(obj, key) ||
|
||||
(!isObject(obj[key]) && !Array.isArray(obj[key]))
|
||||
) {
|
||||
// initialize as array if next key is numeric
|
||||
if (/^\d+$/.test(keys[i + 1])) {
|
||||
obj[key] = []
|
||||
} else {
|
||||
obj[key] = {}
|
||||
}
|
||||
}
|
||||
obj = obj[key]
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Transform an object
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* var obj = {
|
||||
* "id": 1,
|
||||
* "some": {
|
||||
* "thing": "else"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* var transform = {
|
||||
* "id": "nr",
|
||||
* "some.thing": "name"
|
||||
* }
|
||||
*
|
||||
* var tgt = dot.transform(transform, obj)
|
||||
*
|
||||
* @param {Object} recipe Transform recipe
|
||||
* @param {Object} obj Object to be transformed
|
||||
* @param {Array} mods modifiers for the target
|
||||
*/
|
||||
DotObject.prototype.transform = function (recipe, obj, tgt) {
|
||||
obj = obj || {}
|
||||
tgt = tgt || {}
|
||||
Object.keys(recipe).forEach(
|
||||
function (key) {
|
||||
this.set(recipe[key], this.pick(key, obj), tgt)
|
||||
}.bind(this)
|
||||
)
|
||||
return tgt
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Convert object to dotted-key/value pair
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* var tgt = dot.dot(obj)
|
||||
*
|
||||
* or
|
||||
*
|
||||
* var tgt = {}
|
||||
* dot.dot(obj, tgt)
|
||||
*
|
||||
* @param {Object} obj source object
|
||||
* @param {Object} tgt target object
|
||||
* @param {Array} path path array (internal)
|
||||
*/
|
||||
DotObject.prototype.dot = function (obj, tgt, path) {
|
||||
tgt = tgt || {}
|
||||
path = path || []
|
||||
var isArray = Array.isArray(obj)
|
||||
|
||||
Object.keys(obj).forEach(
|
||||
function (key) {
|
||||
var index = isArray && this.useBrackets ? '[' + key + ']' : key
|
||||
if (
|
||||
isArrayOrObject(obj[key]) &&
|
||||
((isObject(obj[key]) && !isEmptyObject(obj[key])) ||
|
||||
(Array.isArray(obj[key]) && !this.keepArray && obj[key].length !== 0))
|
||||
) {
|
||||
if (isArray && this.useBrackets) {
|
||||
var previousKey = path[path.length - 1] || ''
|
||||
return this.dot(
|
||||
obj[key],
|
||||
tgt,
|
||||
path.slice(0, -1).concat(previousKey + index)
|
||||
)
|
||||
} else {
|
||||
return this.dot(obj[key], tgt, path.concat(index))
|
||||
}
|
||||
} else {
|
||||
if (isArray && this.useBrackets) {
|
||||
tgt[path.join(this.separator).concat('[' + key + ']')] = obj[key]
|
||||
} else {
|
||||
tgt[path.concat(index).join(this.separator)] = obj[key]
|
||||
}
|
||||
}
|
||||
}.bind(this)
|
||||
)
|
||||
return tgt
|
||||
}
|
||||
|
||||
DotObject.pick = wrap('pick')
|
||||
DotObject.move = wrap('move')
|
||||
DotObject.transfer = wrap('transfer')
|
||||
DotObject.transform = wrap('transform')
|
||||
DotObject.copy = wrap('copy')
|
||||
DotObject.object = wrap('object')
|
||||
DotObject.str = wrap('str')
|
||||
DotObject.set = wrap('set')
|
||||
DotObject.delete = wrap('delete')
|
||||
DotObject.del = DotObject.remove = wrap('remove')
|
||||
DotObject.dot = wrap('dot');
|
||||
['override', 'overwrite'].forEach(function (prop) {
|
||||
Object.defineProperty(DotObject, prop, {
|
||||
get: function () {
|
||||
return dotDefault.override
|
||||
},
|
||||
set: function (val) {
|
||||
dotDefault.override = !!val
|
||||
}
|
||||
})
|
||||
});
|
||||
['useArray', 'keepArray', 'useBrackets'].forEach(function (prop) {
|
||||
Object.defineProperty(DotObject, prop, {
|
||||
get: function () {
|
||||
return dotDefault[prop]
|
||||
},
|
||||
set: function (val) {
|
||||
dotDefault[prop] = val
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
DotObject._process = _process
|
||||
|
||||
module.exports = DotObject
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 84697:
|
||||
@@ -88254,1152 +87594,6 @@ if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) {
|
||||
exports.debug = debug; // for test
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 31524:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 66647:
|
||||
/***/ ((__unused_webpack_module, exports) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.isValidErrorCode = exports.httpStatusFromErrorCode = exports.TwirpErrorCode = exports.BadRouteError = exports.InternalServerErrorWith = exports.InternalServerError = exports.RequiredArgumentError = exports.InvalidArgumentError = exports.NotFoundError = exports.TwirpError = void 0;
|
||||
/**
|
||||
* Represents a twirp error
|
||||
*/
|
||||
class TwirpError extends Error {
|
||||
constructor(code, msg) {
|
||||
super(msg);
|
||||
this.code = TwirpErrorCode.Internal;
|
||||
this.meta = {};
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
Object.setPrototypeOf(this, TwirpError.prototype);
|
||||
}
|
||||
/**
|
||||
* Adds a metadata kv to the error
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
withMeta(key, value) {
|
||||
this.meta[key] = value;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Returns a single metadata value
|
||||
* return "" if not found
|
||||
* @param key
|
||||
*/
|
||||
getMeta(key) {
|
||||
return this.meta[key] || "";
|
||||
}
|
||||
/**
|
||||
* Add the original error cause
|
||||
* @param err
|
||||
* @param addMeta
|
||||
*/
|
||||
withCause(err, addMeta = false) {
|
||||
this._originalCause = err;
|
||||
if (addMeta) {
|
||||
this.withMeta("cause", err.message);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
cause() {
|
||||
return this._originalCause;
|
||||
}
|
||||
/**
|
||||
* Returns the error representation to JSON
|
||||
*/
|
||||
toJSON() {
|
||||
try {
|
||||
return JSON.stringify({
|
||||
code: this.code,
|
||||
msg: this.msg,
|
||||
meta: this.meta,
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
return `{"code": "internal", "msg": "There was an error but it could not be serialized into JSON"}`;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a twirp error from an object
|
||||
* @param obj
|
||||
*/
|
||||
static fromObject(obj) {
|
||||
const code = obj["code"] || TwirpErrorCode.Unknown;
|
||||
const msg = obj["msg"] || "unknown";
|
||||
const error = new TwirpError(code, msg);
|
||||
if (obj["meta"]) {
|
||||
Object.keys(obj["meta"]).forEach((key) => {
|
||||
error.withMeta(key, obj["meta"][key]);
|
||||
});
|
||||
}
|
||||
return error;
|
||||
}
|
||||
}
|
||||
exports.TwirpError = TwirpError;
|
||||
/**
|
||||
* NotFoundError constructor for the common NotFound error.
|
||||
*/
|
||||
class NotFoundError extends TwirpError {
|
||||
constructor(msg) {
|
||||
super(TwirpErrorCode.NotFound, msg);
|
||||
}
|
||||
}
|
||||
exports.NotFoundError = NotFoundError;
|
||||
/**
|
||||
* InvalidArgumentError constructor for the common InvalidArgument error. Can be
|
||||
* used when an argument has invalid format, is a number out of range, is a bad
|
||||
* option, etc).
|
||||
*/
|
||||
class InvalidArgumentError extends TwirpError {
|
||||
constructor(argument, validationMsg) {
|
||||
super(TwirpErrorCode.InvalidArgument, argument + " " + validationMsg);
|
||||
this.withMeta("argument", argument);
|
||||
}
|
||||
}
|
||||
exports.InvalidArgumentError = InvalidArgumentError;
|
||||
/**
|
||||
* RequiredArgumentError is a more specific constructor for InvalidArgument
|
||||
* error. Should be used when the argument is required (expected to have a
|
||||
* non-zero value).
|
||||
*/
|
||||
class RequiredArgumentError extends InvalidArgumentError {
|
||||
constructor(argument) {
|
||||
super(argument, "is required");
|
||||
}
|
||||
}
|
||||
exports.RequiredArgumentError = RequiredArgumentError;
|
||||
/**
|
||||
* InternalError constructor for the common Internal error. Should be used to
|
||||
* specify that something bad or unexpected happened.
|
||||
*/
|
||||
class InternalServerError extends TwirpError {
|
||||
constructor(msg) {
|
||||
super(TwirpErrorCode.Internal, msg);
|
||||
}
|
||||
}
|
||||
exports.InternalServerError = InternalServerError;
|
||||
/**
|
||||
* InternalErrorWith makes an internal error, wrapping the original error and using it
|
||||
* for the error message, and with metadata "cause" with the original error type.
|
||||
* This function is used by Twirp services to wrap non-Twirp errors as internal errors.
|
||||
* The wrapped error can be extracted later with err.cause()
|
||||
*/
|
||||
class InternalServerErrorWith extends InternalServerError {
|
||||
constructor(err) {
|
||||
super(err.message);
|
||||
this.withMeta("cause", err.name);
|
||||
this.withCause(err);
|
||||
}
|
||||
}
|
||||
exports.InternalServerErrorWith = InternalServerErrorWith;
|
||||
/**
|
||||
* A standard BadRoute Error
|
||||
*/
|
||||
class BadRouteError extends TwirpError {
|
||||
constructor(msg, method, url) {
|
||||
super(TwirpErrorCode.BadRoute, msg);
|
||||
this.withMeta("twirp_invalid_route", method + " " + url);
|
||||
}
|
||||
}
|
||||
exports.BadRouteError = BadRouteError;
|
||||
var TwirpErrorCode;
|
||||
(function (TwirpErrorCode) {
|
||||
// Canceled indicates the operation was cancelled (typically by the caller).
|
||||
TwirpErrorCode["Canceled"] = "canceled";
|
||||
// Unknown error. For example when handling errors raised by APIs that do not
|
||||
// return enough error information.
|
||||
TwirpErrorCode["Unknown"] = "unknown";
|
||||
// InvalidArgument indicates client specified an invalid argument. It
|
||||
// indicates arguments that are problematic regardless of the state of the
|
||||
// system (i.e. a malformed file name, required argument, number out of range,
|
||||
// etc.).
|
||||
TwirpErrorCode["InvalidArgument"] = "invalid_argument";
|
||||
// Malformed indicates an error occurred while decoding the client's request.
|
||||
// This may mean that the message was encoded improperly, or that there is a
|
||||
// disagreement in message format between the client and server.
|
||||
TwirpErrorCode["Malformed"] = "malformed";
|
||||
// DeadlineExceeded means operation expired before completion. For operations
|
||||
// that change the state of the system, this error may be returned even if the
|
||||
// operation has completed successfully (timeout).
|
||||
TwirpErrorCode["DeadlineExceeded"] = "deadline_exceeded";
|
||||
// NotFound means some requested entity was not found.
|
||||
TwirpErrorCode["NotFound"] = "not_found";
|
||||
// BadRoute means that the requested URL path wasn't routable to a Twirp
|
||||
// service and method. This is returned by the generated server, and usually
|
||||
// shouldn't be returned by applications. Instead, applications should use
|
||||
// NotFound or Unimplemented.
|
||||
TwirpErrorCode["BadRoute"] = "bad_route";
|
||||
// AlreadyExists means an attempt to create an entity failed because one
|
||||
// already exists.
|
||||
TwirpErrorCode["AlreadyExists"] = "already_exists";
|
||||
// PermissionDenied indicates the caller does not have permission to execute
|
||||
// the specified operation. It must not be used if the caller cannot be
|
||||
// identified (Unauthenticated).
|
||||
TwirpErrorCode["PermissionDenied"] = "permission_denied";
|
||||
// Unauthenticated indicates the request does not have valid authentication
|
||||
// credentials for the operation.
|
||||
TwirpErrorCode["Unauthenticated"] = "unauthenticated";
|
||||
// ResourceExhausted indicates some resource has been exhausted, perhaps a
|
||||
// per-user quota, or perhaps the entire file system is out of space.
|
||||
TwirpErrorCode["ResourceExhausted"] = "resource_exhausted";
|
||||
// FailedPrecondition indicates operation was rejected because the system is
|
||||
// not in a state required for the operation's execution. For example, doing
|
||||
// an rmdir operation on a directory that is non-empty, or on a non-directory
|
||||
// object, or when having conflicting read-modify-write on the same resource.
|
||||
TwirpErrorCode["FailedPrecondition"] = "failed_precondition";
|
||||
// Aborted indicates the operation was aborted, typically due to a concurrency
|
||||
// issue like sequencer check failures, transaction aborts, etc.
|
||||
TwirpErrorCode["Aborted"] = "aborted";
|
||||
// OutOfRange means operation was attempted past the valid range. For example,
|
||||
// seeking or reading past end of a paginated collection.
|
||||
//
|
||||
// Unlike InvalidArgument, this error indicates a problem that may be fixed if
|
||||
// the system state changes (i.e. adding more items to the collection).
|
||||
//
|
||||
// There is a fair bit of overlap between FailedPrecondition and OutOfRange.
|
||||
// We recommend using OutOfRange (the more specific error) when it applies so
|
||||
// that callers who are iterating through a space can easily look for an
|
||||
// OutOfRange error to detect when they are done.
|
||||
TwirpErrorCode["OutOfRange"] = "out_of_range";
|
||||
// Unimplemented indicates operation is not implemented or not
|
||||
// supported/enabled in this service.
|
||||
TwirpErrorCode["Unimplemented"] = "unimplemented";
|
||||
// Internal errors. When some invariants expected by the underlying system
|
||||
// have been broken. In other words, something bad happened in the library or
|
||||
// backend service. Do not confuse with HTTP Internal Server Error; an
|
||||
// Internal error could also happen on the client code, i.e. when parsing a
|
||||
// server response.
|
||||
TwirpErrorCode["Internal"] = "internal";
|
||||
// Unavailable indicates the service is currently unavailable. This is a most
|
||||
// likely a transient condition and may be corrected by retrying with a
|
||||
// backoff.
|
||||
TwirpErrorCode["Unavailable"] = "unavailable";
|
||||
// DataLoss indicates unrecoverable data loss or corruption.
|
||||
TwirpErrorCode["DataLoss"] = "data_loss";
|
||||
})(TwirpErrorCode = exports.TwirpErrorCode || (exports.TwirpErrorCode = {}));
|
||||
// ServerHTTPStatusFromErrorCode maps a Twirp error type into a similar HTTP
|
||||
// response status. It is used by the Twirp server handler to set the HTTP
|
||||
// response status code. Returns 0 if the ErrorCode is invalid.
|
||||
function httpStatusFromErrorCode(code) {
|
||||
switch (code) {
|
||||
case TwirpErrorCode.Canceled:
|
||||
return 408; // RequestTimeout
|
||||
case TwirpErrorCode.Unknown:
|
||||
return 500; // Internal Server Error
|
||||
case TwirpErrorCode.InvalidArgument:
|
||||
return 400; // BadRequest
|
||||
case TwirpErrorCode.Malformed:
|
||||
return 400; // BadRequest
|
||||
case TwirpErrorCode.DeadlineExceeded:
|
||||
return 408; // RequestTimeout
|
||||
case TwirpErrorCode.NotFound:
|
||||
return 404; // Not Found
|
||||
case TwirpErrorCode.BadRoute:
|
||||
return 404; // Not Found
|
||||
case TwirpErrorCode.AlreadyExists:
|
||||
return 409; // Conflict
|
||||
case TwirpErrorCode.PermissionDenied:
|
||||
return 403; // Forbidden
|
||||
case TwirpErrorCode.Unauthenticated:
|
||||
return 401; // Unauthorized
|
||||
case TwirpErrorCode.ResourceExhausted:
|
||||
return 429; // Too Many Requests
|
||||
case TwirpErrorCode.FailedPrecondition:
|
||||
return 412; // Precondition Failed
|
||||
case TwirpErrorCode.Aborted:
|
||||
return 409; // Conflict
|
||||
case TwirpErrorCode.OutOfRange:
|
||||
return 400; // Bad Request
|
||||
case TwirpErrorCode.Unimplemented:
|
||||
return 501; // Not Implemented
|
||||
case TwirpErrorCode.Internal:
|
||||
return 500; // Internal Server Error
|
||||
case TwirpErrorCode.Unavailable:
|
||||
return 503; // Service Unavailable
|
||||
case TwirpErrorCode.DataLoss:
|
||||
return 500; // Internal Server Error
|
||||
default:
|
||||
return 0; // Invalid!
|
||||
}
|
||||
}
|
||||
exports.httpStatusFromErrorCode = httpStatusFromErrorCode;
|
||||
// IsValidErrorCode returns true if is one of the valid predefined constants.
|
||||
function isValidErrorCode(code) {
|
||||
return httpStatusFromErrorCode(code) != 0;
|
||||
}
|
||||
exports.isValidErrorCode = isValidErrorCode;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 56748:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.Gateway = exports.Pattern = void 0;
|
||||
const querystring_1 = __nccwpck_require__(63477);
|
||||
const dotObject = __importStar(__nccwpck_require__(13598));
|
||||
const request_1 = __nccwpck_require__(8347);
|
||||
const errors_1 = __nccwpck_require__(66647);
|
||||
const http_client_1 = __nccwpck_require__(94091);
|
||||
const server_1 = __nccwpck_require__(26604);
|
||||
var Pattern;
|
||||
(function (Pattern) {
|
||||
Pattern["POST"] = "post";
|
||||
Pattern["GET"] = "get";
|
||||
Pattern["PATCH"] = "patch";
|
||||
Pattern["PUT"] = "put";
|
||||
Pattern["DELETE"] = "delete";
|
||||
})(Pattern = exports.Pattern || (exports.Pattern = {}));
|
||||
/**
|
||||
* The Gateway proxies http requests to Twirp Compliant
|
||||
* handlers
|
||||
*/
|
||||
class Gateway {
|
||||
constructor(routes) {
|
||||
this.routes = routes;
|
||||
}
|
||||
/**
|
||||
* Middleware that rewrite the current request
|
||||
* to a Twirp compliant request
|
||||
*/
|
||||
twirpRewrite(prefix = "/twirp") {
|
||||
return (req, resp, next) => {
|
||||
this.rewrite(req, resp, prefix)
|
||||
.then(() => next())
|
||||
.catch((e) => {
|
||||
if (e instanceof errors_1.TwirpError) {
|
||||
if (e.code !== errors_1.TwirpErrorCode.NotFound) {
|
||||
server_1.writeError(resp, e);
|
||||
}
|
||||
else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Rewrite an incoming request to a Twirp compliant request
|
||||
* @param req
|
||||
* @param resp
|
||||
* @param prefix
|
||||
*/
|
||||
rewrite(req, resp, prefix = "/twirp") {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const [match, route] = this.matchRoute(req);
|
||||
const body = yield this.prepareTwirpBody(req, match, route);
|
||||
const twirpUrl = `${prefix}/${route.packageName}.${route.serviceName}/${route.methodName}`;
|
||||
req.url = twirpUrl;
|
||||
req.originalUrl = twirpUrl;
|
||||
req.method = "POST";
|
||||
req.headers["content-type"] = "application/json";
|
||||
req.rawBody = Buffer.from(JSON.stringify(body));
|
||||
if (route.responseBodyKey) {
|
||||
const endFn = resp.end.bind(resp);
|
||||
resp.end = function (chunk) {
|
||||
if (resp.statusCode === 200) {
|
||||
endFn(`{ "${route.responseBodyKey}": ${chunk} }`);
|
||||
}
|
||||
else {
|
||||
endFn(chunk);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Create a reverse proxy handler to
|
||||
* proxy http requests to Twirp Compliant handlers
|
||||
* @param httpClientOption
|
||||
*/
|
||||
reverseProxy(httpClientOption) {
|
||||
const client = http_client_1.NodeHttpRPC(httpClientOption);
|
||||
return (req, res) => __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
const [match, route] = this.matchRoute(req);
|
||||
const body = yield this.prepareTwirpBody(req, match, route);
|
||||
const response = yield client.request(`${route.packageName}.${route.serviceName}`, route.methodName, "application/json", body);
|
||||
res.statusCode = 200;
|
||||
res.setHeader("content-type", "application/json");
|
||||
let jsonResponse;
|
||||
if (route.responseBodyKey) {
|
||||
jsonResponse = JSON.stringify({ [route.responseBodyKey]: response });
|
||||
}
|
||||
else {
|
||||
jsonResponse = JSON.stringify(response);
|
||||
}
|
||||
res.end(jsonResponse);
|
||||
}
|
||||
catch (e) {
|
||||
server_1.writeError(res, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Prepares twirp body requests using http.google.annotions
|
||||
* compliant spec
|
||||
*
|
||||
* @param req
|
||||
* @param match
|
||||
* @param route
|
||||
* @protected
|
||||
*/
|
||||
prepareTwirpBody(req, match, route) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const _a = match.params, { query_string } = _a, params = __rest(_a, ["query_string"]);
|
||||
let requestBody = Object.assign({}, params);
|
||||
if (query_string && route.bodyKey !== "*") {
|
||||
const queryParams = this.parseQueryString(query_string);
|
||||
requestBody = Object.assign(Object.assign({}, queryParams), requestBody);
|
||||
}
|
||||
let body = {};
|
||||
if (route.bodyKey) {
|
||||
const data = yield request_1.getRequestData(req);
|
||||
try {
|
||||
const jsonBody = JSON.parse(data.toString() || "{}");
|
||||
if (route.bodyKey === "*") {
|
||||
body = jsonBody;
|
||||
}
|
||||
else {
|
||||
body[route.bodyKey] = jsonBody;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new errors_1.TwirpError(errors_1.TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
return Object.assign(Object.assign({}, body), requestBody);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Matches a route
|
||||
* @param req
|
||||
*/
|
||||
matchRoute(req) {
|
||||
var _a;
|
||||
const httpMethod = (_a = req.method) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
||||
if (!httpMethod) {
|
||||
throw new errors_1.BadRouteError(`method not allowed`, req.method || "", req.url || "");
|
||||
}
|
||||
const routes = this.routes[httpMethod];
|
||||
for (const route of routes) {
|
||||
const match = route.matcher(req.url || "/");
|
||||
if (match) {
|
||||
return [match, route];
|
||||
}
|
||||
}
|
||||
throw new errors_1.NotFoundError(`url ${req.url} not found`);
|
||||
}
|
||||
/**
|
||||
* Parse query string
|
||||
* @param queryString
|
||||
*/
|
||||
parseQueryString(queryString) {
|
||||
const queryParams = querystring_1.parse(queryString.replace("?", ""));
|
||||
return dotObject.object(queryParams);
|
||||
}
|
||||
}
|
||||
exports.Gateway = Gateway;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 4263:
|
||||
/***/ (function(__unused_webpack_module, exports) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.isHook = exports.chainHooks = void 0;
|
||||
// ChainHooks creates a new ServerHook which chains the callbacks in
|
||||
// each of the constituent hooks passed in. Each hook function will be
|
||||
// called in the order of the ServerHooks values passed in.
|
||||
//
|
||||
// For the erroring hooks, RequestReceived and RequestRouted, any returned
|
||||
// errors prevent processing by later hooks.
|
||||
function chainHooks(...hooks) {
|
||||
if (hooks.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (hooks.length === 1) {
|
||||
return hooks[0];
|
||||
}
|
||||
const serverHook = {
|
||||
requestReceived(ctx) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const hook of hooks) {
|
||||
if (!hook.requestReceived) {
|
||||
continue;
|
||||
}
|
||||
yield hook.requestReceived(ctx);
|
||||
}
|
||||
});
|
||||
},
|
||||
requestPrepared(ctx) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const hook of hooks) {
|
||||
if (!hook.requestPrepared) {
|
||||
continue;
|
||||
}
|
||||
console.warn("hook requestPrepared is deprecated and will be removed in the next release. " +
|
||||
"Please use responsePrepared instead.");
|
||||
yield hook.requestPrepared(ctx);
|
||||
}
|
||||
});
|
||||
},
|
||||
responsePrepared(ctx) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const hook of hooks) {
|
||||
if (!hook.responsePrepared) {
|
||||
continue;
|
||||
}
|
||||
yield hook.responsePrepared(ctx);
|
||||
}
|
||||
});
|
||||
},
|
||||
requestSent(ctx) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const hook of hooks) {
|
||||
if (!hook.requestSent) {
|
||||
continue;
|
||||
}
|
||||
console.warn("hook requestSent is deprecated and will be removed in the next release. " +
|
||||
"Please use responseSent instead.");
|
||||
yield hook.requestSent(ctx);
|
||||
}
|
||||
});
|
||||
},
|
||||
responseSent(ctx) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const hook of hooks) {
|
||||
if (!hook.responseSent) {
|
||||
continue;
|
||||
}
|
||||
yield hook.responseSent(ctx);
|
||||
}
|
||||
});
|
||||
},
|
||||
requestRouted(ctx) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const hook of hooks) {
|
||||
if (!hook.requestRouted) {
|
||||
continue;
|
||||
}
|
||||
yield hook.requestRouted(ctx);
|
||||
}
|
||||
});
|
||||
},
|
||||
error(ctx, err) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const hook of hooks) {
|
||||
if (!hook.error) {
|
||||
continue;
|
||||
}
|
||||
yield hook.error(ctx, err);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
return serverHook;
|
||||
}
|
||||
exports.chainHooks = chainHooks;
|
||||
function isHook(object) {
|
||||
return ("requestReceived" in object ||
|
||||
"requestPrepared" in object ||
|
||||
"requestSent" in object ||
|
||||
"requestRouted" in object ||
|
||||
"responsePrepared" in object ||
|
||||
"responseSent" in object ||
|
||||
"error" in object);
|
||||
}
|
||||
exports.isHook = isHook;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 94091:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.FetchRPC = exports.wrapErrorResponseToTwirpError = exports.NodeHttpRPC = void 0;
|
||||
const http = __importStar(__nccwpck_require__(13685));
|
||||
const https = __importStar(__nccwpck_require__(95687));
|
||||
const url_1 = __nccwpck_require__(57310);
|
||||
const errors_1 = __nccwpck_require__(66647);
|
||||
/**
|
||||
* a node HTTP RPC implementation
|
||||
* @param options
|
||||
* @constructor
|
||||
*/
|
||||
const NodeHttpRPC = (options) => ({
|
||||
request(service, method, contentType, data) {
|
||||
let client;
|
||||
return new Promise((resolve, rejected) => {
|
||||
const responseChunks = [];
|
||||
const requestData = contentType === "application/protobuf"
|
||||
? Buffer.from(data)
|
||||
: JSON.stringify(data);
|
||||
const url = new url_1.URL(options.baseUrl);
|
||||
const isHttps = url.protocol === "https:";
|
||||
if (isHttps) {
|
||||
client = https;
|
||||
}
|
||||
else {
|
||||
client = http;
|
||||
}
|
||||
const prefix = url.pathname !== "/" ? url.pathname : "";
|
||||
const req = client
|
||||
.request(Object.assign(Object.assign({}, (options ? options : {})), { method: "POST", protocol: url.protocol, host: url.hostname, port: url.port ? url.port : isHttps ? 443 : 80, path: `${prefix}/${service}/${method}`, headers: Object.assign(Object.assign({}, (options.headers ? options.headers : {})), { "Content-Type": contentType, "Content-Length": contentType === "application/protobuf"
|
||||
? Buffer.byteLength(requestData)
|
||||
: Buffer.from(requestData).byteLength }) }), (res) => {
|
||||
res.on("data", (chunk) => responseChunks.push(chunk));
|
||||
res.on("end", () => {
|
||||
const data = Buffer.concat(responseChunks);
|
||||
if (res.statusCode != 200) {
|
||||
rejected(wrapErrorResponseToTwirpError(data.toString()));
|
||||
}
|
||||
else {
|
||||
if (contentType === "application/json") {
|
||||
resolve(JSON.parse(data.toString()));
|
||||
}
|
||||
else {
|
||||
resolve(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
res.on("error", (err) => {
|
||||
rejected(err);
|
||||
});
|
||||
})
|
||||
.on("error", (err) => {
|
||||
rejected(err);
|
||||
});
|
||||
req.end(requestData);
|
||||
});
|
||||
},
|
||||
});
|
||||
exports.NodeHttpRPC = NodeHttpRPC;
|
||||
function wrapErrorResponseToTwirpError(errorResponse) {
|
||||
return errors_1.TwirpError.fromObject(JSON.parse(errorResponse));
|
||||
}
|
||||
exports.wrapErrorResponseToTwirpError = wrapErrorResponseToTwirpError;
|
||||
/**
|
||||
* a browser fetch RPC implementation
|
||||
*/
|
||||
const FetchRPC = (options) => ({
|
||||
request(service, method, contentType, data) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const headers = new Headers(options.headers);
|
||||
headers.set("content-type", contentType);
|
||||
const response = yield fetch(`${options.baseUrl}/${service}/${method}`, Object.assign(Object.assign({}, options), { method: "POST", headers, body: data instanceof Uint8Array ? data : JSON.stringify(data) }));
|
||||
if (response.status === 200) {
|
||||
if (contentType === "application/json") {
|
||||
return yield response.json();
|
||||
}
|
||||
return new Uint8Array(yield response.arrayBuffer());
|
||||
}
|
||||
throw errors_1.TwirpError.fromObject(yield response.json());
|
||||
});
|
||||
},
|
||||
});
|
||||
exports.FetchRPC = FetchRPC;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 66465:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.TwirpContentType = void 0;
|
||||
__exportStar(__nccwpck_require__(31524), exports);
|
||||
__exportStar(__nccwpck_require__(26604), exports);
|
||||
__exportStar(__nccwpck_require__(48913), exports);
|
||||
__exportStar(__nccwpck_require__(4263), exports);
|
||||
__exportStar(__nccwpck_require__(66647), exports);
|
||||
__exportStar(__nccwpck_require__(56748), exports);
|
||||
__exportStar(__nccwpck_require__(94091), exports);
|
||||
var request_1 = __nccwpck_require__(8347);
|
||||
Object.defineProperty(exports, "TwirpContentType", ({ enumerable: true, get: function () { return request_1.TwirpContentType; } }));
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 48913:
|
||||
/***/ (function(__unused_webpack_module, exports) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.chainInterceptors = void 0;
|
||||
// chains multiple Interceptors into a single Interceptor.
|
||||
// The first interceptor wraps the second one, and so on.
|
||||
// Returns null if interceptors is empty.
|
||||
function chainInterceptors(...interceptors) {
|
||||
if (interceptors.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (interceptors.length === 1) {
|
||||
return interceptors[0];
|
||||
}
|
||||
const first = interceptors[0];
|
||||
return (ctx, request, handler) => __awaiter(this, void 0, void 0, function* () {
|
||||
let next = handler;
|
||||
for (let i = interceptors.length - 1; i > 0; i--) {
|
||||
next = ((next) => (ctx, typedRequest) => {
|
||||
return interceptors[i](ctx, typedRequest, next);
|
||||
})(next);
|
||||
}
|
||||
return first(ctx, request, next);
|
||||
});
|
||||
}
|
||||
exports.chainInterceptors = chainInterceptors;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 8347:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.parseTwirpPath = exports.getRequestData = exports.validateRequest = exports.getContentType = exports.TwirpContentType = void 0;
|
||||
const errors_1 = __nccwpck_require__(66647);
|
||||
/**
|
||||
* Supported Twirp Content-Type
|
||||
*/
|
||||
var TwirpContentType;
|
||||
(function (TwirpContentType) {
|
||||
TwirpContentType[TwirpContentType["Protobuf"] = 0] = "Protobuf";
|
||||
TwirpContentType[TwirpContentType["JSON"] = 1] = "JSON";
|
||||
TwirpContentType[TwirpContentType["Unknown"] = 2] = "Unknown";
|
||||
})(TwirpContentType = exports.TwirpContentType || (exports.TwirpContentType = {}));
|
||||
/**
|
||||
* Get supported content-type
|
||||
* @param mimeType
|
||||
*/
|
||||
function getContentType(mimeType) {
|
||||
switch (mimeType) {
|
||||
case "application/protobuf":
|
||||
return TwirpContentType.Protobuf;
|
||||
case "application/json":
|
||||
return TwirpContentType.JSON;
|
||||
default:
|
||||
return TwirpContentType.Unknown;
|
||||
}
|
||||
}
|
||||
exports.getContentType = getContentType;
|
||||
/**
|
||||
* Validate a twirp request
|
||||
* @param ctx
|
||||
* @param request
|
||||
* @param pathPrefix
|
||||
*/
|
||||
function validateRequest(ctx, request, pathPrefix) {
|
||||
if (request.method !== "POST") {
|
||||
const msg = `unsupported method ${request.method} (only POST is allowed)`;
|
||||
throw new errors_1.BadRouteError(msg, request.method || "", request.url || "");
|
||||
}
|
||||
const path = parseTwirpPath(request.url || "");
|
||||
if (path.pkgService !==
|
||||
(ctx.packageName ? ctx.packageName + "." : "") + ctx.serviceName) {
|
||||
const msg = `no handler for path ${request.url}`;
|
||||
throw new errors_1.BadRouteError(msg, request.method || "", request.url || "");
|
||||
}
|
||||
if (path.prefix !== pathPrefix) {
|
||||
const msg = `invalid path prefix ${path.prefix}, expected ${pathPrefix}, on path ${request.url}`;
|
||||
throw new errors_1.BadRouteError(msg, request.method || "", request.url || "");
|
||||
}
|
||||
const mimeContentType = request.headers["content-type"] || "";
|
||||
if (ctx.contentType === TwirpContentType.Unknown) {
|
||||
const msg = `unexpected Content-Type: ${request.headers["content-type"]}`;
|
||||
throw new errors_1.BadRouteError(msg, request.method || "", request.url || "");
|
||||
}
|
||||
return Object.assign(Object.assign({}, path), { mimeContentType, contentType: ctx.contentType });
|
||||
}
|
||||
exports.validateRequest = validateRequest;
|
||||
/**
|
||||
* Get request data from the body
|
||||
* @param req
|
||||
*/
|
||||
function getRequestData(req) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reqWithRawBody = req;
|
||||
if (reqWithRawBody.rawBody instanceof Buffer) {
|
||||
resolve(reqWithRawBody.rawBody);
|
||||
return;
|
||||
}
|
||||
const chunks = [];
|
||||
req.on("data", (chunk) => chunks.push(chunk));
|
||||
req.on("end", () => __awaiter(this, void 0, void 0, function* () {
|
||||
const data = Buffer.concat(chunks);
|
||||
resolve(data);
|
||||
}));
|
||||
req.on("error", (err) => {
|
||||
if (req.aborted) {
|
||||
reject(new errors_1.TwirpError(errors_1.TwirpErrorCode.DeadlineExceeded, "failed to read request: deadline exceeded"));
|
||||
}
|
||||
else {
|
||||
reject(new errors_1.TwirpError(errors_1.TwirpErrorCode.Malformed, err.message).withCause(err));
|
||||
}
|
||||
});
|
||||
req.on("close", () => {
|
||||
reject(new errors_1.TwirpError(errors_1.TwirpErrorCode.Canceled, "failed to read request: context canceled"));
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.getRequestData = getRequestData;
|
||||
/**
|
||||
* Parses twirp url path
|
||||
* @param path
|
||||
*/
|
||||
function parseTwirpPath(path) {
|
||||
const parts = path.split("/");
|
||||
if (parts.length < 2) {
|
||||
return {
|
||||
pkgService: "",
|
||||
method: "",
|
||||
prefix: "",
|
||||
};
|
||||
}
|
||||
return {
|
||||
method: parts[parts.length - 1],
|
||||
pkgService: parts[parts.length - 2],
|
||||
prefix: parts.slice(0, parts.length - 2).join("/"),
|
||||
};
|
||||
}
|
||||
exports.parseTwirpPath = parseTwirpPath;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 26604:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.writeError = exports.TwirpServer = void 0;
|
||||
const hooks_1 = __nccwpck_require__(4263);
|
||||
const request_1 = __nccwpck_require__(8347);
|
||||
const errors_1 = __nccwpck_require__(66647);
|
||||
/**
|
||||
* Runtime server implementation of a TwirpServer
|
||||
*/
|
||||
class TwirpServer {
|
||||
constructor(options) {
|
||||
this.pathPrefix = "/twirp";
|
||||
this.hooks = [];
|
||||
this.interceptors = [];
|
||||
this.packageName = options.packageName;
|
||||
this.serviceName = options.serviceName;
|
||||
this.methodList = options.methodList;
|
||||
this.matchRoute = options.matchRoute;
|
||||
this.service = options.service;
|
||||
}
|
||||
/**
|
||||
* Returns the prefix for this server
|
||||
*/
|
||||
get prefix() {
|
||||
return this.pathPrefix;
|
||||
}
|
||||
/**
|
||||
* The http handler for twirp complaint endpoints
|
||||
* @param options
|
||||
*/
|
||||
httpHandler(options) {
|
||||
return (req, resp) => {
|
||||
// setup prefix
|
||||
if ((options === null || options === void 0 ? void 0 : options.prefix) !== undefined) {
|
||||
this.withPrefix(options.prefix);
|
||||
}
|
||||
return this._httpHandler(req, resp);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Adds interceptors or hooks to the request stack
|
||||
* @param middlewares
|
||||
*/
|
||||
use(...middlewares) {
|
||||
middlewares.forEach((middleware) => {
|
||||
if (hooks_1.isHook(middleware)) {
|
||||
this.hooks.push(middleware);
|
||||
return this;
|
||||
}
|
||||
this.interceptors.push(middleware);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Adds a prefix to the service url path
|
||||
* @param prefix
|
||||
*/
|
||||
withPrefix(prefix) {
|
||||
if (prefix === false) {
|
||||
this.pathPrefix = "";
|
||||
}
|
||||
else {
|
||||
this.pathPrefix = prefix;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Returns the regex matching path for this twirp server
|
||||
*/
|
||||
matchingPath() {
|
||||
const baseRegex = this.baseURI().replace(/\./g, "\\.");
|
||||
return new RegExp(`${baseRegex}\/(${this.methodList.join("|")})`);
|
||||
}
|
||||
/**
|
||||
* Returns the base URI for this twirp server
|
||||
*/
|
||||
baseURI() {
|
||||
return `${this.pathPrefix}/${this.packageName ? this.packageName + "." : ""}${this.serviceName}`;
|
||||
}
|
||||
/**
|
||||
* Create a twirp context
|
||||
* @param req
|
||||
* @param res
|
||||
* @private
|
||||
*/
|
||||
createContext(req, res) {
|
||||
return {
|
||||
packageName: this.packageName,
|
||||
serviceName: this.serviceName,
|
||||
methodName: "",
|
||||
contentType: request_1.getContentType(req.headers["content-type"]),
|
||||
req: req,
|
||||
res: res,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Twrip server http handler implementation
|
||||
* @param req
|
||||
* @param resp
|
||||
* @private
|
||||
*/
|
||||
_httpHandler(req, resp) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const ctx = this.createContext(req, resp);
|
||||
try {
|
||||
yield this.invokeHook("requestReceived", ctx);
|
||||
const { method, mimeContentType } = request_1.validateRequest(ctx, req, this.pathPrefix || "");
|
||||
const handler = this.matchRoute(method, {
|
||||
onMatch: (ctx) => {
|
||||
return this.invokeHook("requestRouted", ctx);
|
||||
},
|
||||
onNotFound: () => {
|
||||
const msg = `no handler for path ${req.url}`;
|
||||
throw new errors_1.BadRouteError(msg, req.method || "", req.url || "");
|
||||
},
|
||||
});
|
||||
const body = yield request_1.getRequestData(req);
|
||||
const response = yield handler(ctx, this.service, body, this.interceptors);
|
||||
yield Promise.all([
|
||||
this.invokeHook("responsePrepared", ctx),
|
||||
// keep backwards compatibility till next release
|
||||
this.invokeHook("requestPrepared", ctx),
|
||||
]);
|
||||
resp.statusCode = 200;
|
||||
resp.setHeader("Content-Type", mimeContentType);
|
||||
resp.end(response);
|
||||
}
|
||||
catch (e) {
|
||||
yield this.invokeHook("error", ctx, mustBeTwirpError(e));
|
||||
if (!resp.headersSent) {
|
||||
writeError(resp, e);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
yield Promise.all([
|
||||
this.invokeHook("responseSent", ctx),
|
||||
// keep backwards compatibility till next release
|
||||
this.invokeHook("requestSent", ctx),
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Invoke a hook
|
||||
* @param hookName
|
||||
* @param ctx
|
||||
* @param err
|
||||
* @protected
|
||||
*/
|
||||
invokeHook(hookName, ctx, err) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (this.hooks.length === 0) {
|
||||
return;
|
||||
}
|
||||
const chainedHooks = hooks_1.chainHooks(...this.hooks);
|
||||
const hook = chainedHooks === null || chainedHooks === void 0 ? void 0 : chainedHooks[hookName];
|
||||
if (hook) {
|
||||
yield hook(ctx, err || new errors_1.InternalServerError("internal server error"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.TwirpServer = TwirpServer;
|
||||
/**
|
||||
* Write http error response
|
||||
* @param res
|
||||
* @param error
|
||||
*/
|
||||
function writeError(res, error) {
|
||||
const twirpError = mustBeTwirpError(error);
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.statusCode = errors_1.httpStatusFromErrorCode(twirpError.code);
|
||||
res.end(twirpError.toJSON());
|
||||
}
|
||||
exports.writeError = writeError;
|
||||
/**
|
||||
* Make sure that the error passed is a TwirpError
|
||||
* otherwise it will wrap it into an InternalError
|
||||
* @param err
|
||||
*/
|
||||
function mustBeTwirpError(err) {
|
||||
if (err instanceof errors_1.TwirpError) {
|
||||
return err;
|
||||
}
|
||||
return new errors_1.InternalServerErrorWith(err);
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 41773:
|
||||
@@ -95734,6 +93928,132 @@ function onConnectTimeout (socket) {
|
||||
module.exports = buildConnector
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 14462:
|
||||
/***/ ((module) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
/** @type {Record<string, string | undefined>} */
|
||||
const headerNameLowerCasedRecord = {}
|
||||
|
||||
// https://developer.mozilla.org/docs/Web/HTTP/Headers
|
||||
const wellknownHeaderNames = [
|
||||
'Accept',
|
||||
'Accept-Encoding',
|
||||
'Accept-Language',
|
||||
'Accept-Ranges',
|
||||
'Access-Control-Allow-Credentials',
|
||||
'Access-Control-Allow-Headers',
|
||||
'Access-Control-Allow-Methods',
|
||||
'Access-Control-Allow-Origin',
|
||||
'Access-Control-Expose-Headers',
|
||||
'Access-Control-Max-Age',
|
||||
'Access-Control-Request-Headers',
|
||||
'Access-Control-Request-Method',
|
||||
'Age',
|
||||
'Allow',
|
||||
'Alt-Svc',
|
||||
'Alt-Used',
|
||||
'Authorization',
|
||||
'Cache-Control',
|
||||
'Clear-Site-Data',
|
||||
'Connection',
|
||||
'Content-Disposition',
|
||||
'Content-Encoding',
|
||||
'Content-Language',
|
||||
'Content-Length',
|
||||
'Content-Location',
|
||||
'Content-Range',
|
||||
'Content-Security-Policy',
|
||||
'Content-Security-Policy-Report-Only',
|
||||
'Content-Type',
|
||||
'Cookie',
|
||||
'Cross-Origin-Embedder-Policy',
|
||||
'Cross-Origin-Opener-Policy',
|
||||
'Cross-Origin-Resource-Policy',
|
||||
'Date',
|
||||
'Device-Memory',
|
||||
'Downlink',
|
||||
'ECT',
|
||||
'ETag',
|
||||
'Expect',
|
||||
'Expect-CT',
|
||||
'Expires',
|
||||
'Forwarded',
|
||||
'From',
|
||||
'Host',
|
||||
'If-Match',
|
||||
'If-Modified-Since',
|
||||
'If-None-Match',
|
||||
'If-Range',
|
||||
'If-Unmodified-Since',
|
||||
'Keep-Alive',
|
||||
'Last-Modified',
|
||||
'Link',
|
||||
'Location',
|
||||
'Max-Forwards',
|
||||
'Origin',
|
||||
'Permissions-Policy',
|
||||
'Pragma',
|
||||
'Proxy-Authenticate',
|
||||
'Proxy-Authorization',
|
||||
'RTT',
|
||||
'Range',
|
||||
'Referer',
|
||||
'Referrer-Policy',
|
||||
'Refresh',
|
||||
'Retry-After',
|
||||
'Sec-WebSocket-Accept',
|
||||
'Sec-WebSocket-Extensions',
|
||||
'Sec-WebSocket-Key',
|
||||
'Sec-WebSocket-Protocol',
|
||||
'Sec-WebSocket-Version',
|
||||
'Server',
|
||||
'Server-Timing',
|
||||
'Service-Worker-Allowed',
|
||||
'Service-Worker-Navigation-Preload',
|
||||
'Set-Cookie',
|
||||
'SourceMap',
|
||||
'Strict-Transport-Security',
|
||||
'Supports-Loading-Mode',
|
||||
'TE',
|
||||
'Timing-Allow-Origin',
|
||||
'Trailer',
|
||||
'Transfer-Encoding',
|
||||
'Upgrade',
|
||||
'Upgrade-Insecure-Requests',
|
||||
'User-Agent',
|
||||
'Vary',
|
||||
'Via',
|
||||
'WWW-Authenticate',
|
||||
'X-Content-Type-Options',
|
||||
'X-DNS-Prefetch-Control',
|
||||
'X-Frame-Options',
|
||||
'X-Permitted-Cross-Domain-Policies',
|
||||
'X-Powered-By',
|
||||
'X-Requested-With',
|
||||
'X-XSS-Protection'
|
||||
]
|
||||
|
||||
for (let i = 0; i < wellknownHeaderNames.length; ++i) {
|
||||
const key = wellknownHeaderNames[i]
|
||||
const lowerCasedKey = key.toLowerCase()
|
||||
headerNameLowerCasedRecord[key] = headerNameLowerCasedRecord[lowerCasedKey] =
|
||||
lowerCasedKey
|
||||
}
|
||||
|
||||
// Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`.
|
||||
Object.setPrototypeOf(headerNameLowerCasedRecord, null)
|
||||
|
||||
module.exports = {
|
||||
wellknownHeaderNames,
|
||||
headerNameLowerCasedRecord
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 48045:
|
||||
@@ -96566,6 +94886,7 @@ const { InvalidArgumentError } = __nccwpck_require__(48045)
|
||||
const { Blob } = __nccwpck_require__(14300)
|
||||
const nodeUtil = __nccwpck_require__(73837)
|
||||
const { stringify } = __nccwpck_require__(63477)
|
||||
const { headerNameLowerCasedRecord } = __nccwpck_require__(14462)
|
||||
|
||||
const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(v => Number(v))
|
||||
|
||||
@@ -96775,6 +95096,15 @@ function parseKeepAliveTimeout (val) {
|
||||
return m ? parseInt(m[1], 10) * 1000 : null
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a header name and returns its lowercase value.
|
||||
* @param {string | Buffer} value Header name
|
||||
* @returns {string}
|
||||
*/
|
||||
function headerNameToString (value) {
|
||||
return headerNameLowerCasedRecord[value] || value.toLowerCase()
|
||||
}
|
||||
|
||||
function parseHeaders (headers, obj = {}) {
|
||||
// For H2 support
|
||||
if (!Array.isArray(headers)) return headers
|
||||
@@ -97046,6 +95376,7 @@ module.exports = {
|
||||
isIterable,
|
||||
isAsyncIterable,
|
||||
isDestroyed,
|
||||
headerNameToString,
|
||||
parseRawHeaders,
|
||||
parseHeaders,
|
||||
parseKeepAliveTimeout,
|
||||
@@ -101182,6 +99513,9 @@ function httpRedirectFetch (fetchParams, response) {
|
||||
// https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name
|
||||
request.headersList.delete('authorization')
|
||||
|
||||
// https://fetch.spec.whatwg.org/#authentication-entries
|
||||
request.headersList.delete('proxy-authorization', true)
|
||||
|
||||
// "Cookie" and "Host" are forbidden request-headers, which undici doesn't implement.
|
||||
request.headersList.delete('cookie')
|
||||
request.headersList.delete('host')
|
||||
@@ -103690,14 +102024,18 @@ const { isBlobLike, toUSVString, ReadableStreamFrom } = __nccwpck_require__(8398
|
||||
const assert = __nccwpck_require__(39491)
|
||||
const { isUint8Array } = __nccwpck_require__(84978)
|
||||
|
||||
let supportedHashes = []
|
||||
|
||||
// https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable
|
||||
/** @type {import('crypto')|undefined} */
|
||||
let crypto
|
||||
|
||||
try {
|
||||
crypto = __nccwpck_require__(6113)
|
||||
const possibleRelevantHashes = ['sha256', 'sha384', 'sha512']
|
||||
supportedHashes = crypto.getHashes().filter((hash) => possibleRelevantHashes.includes(hash))
|
||||
/* c8 ignore next 3 */
|
||||
} catch {
|
||||
|
||||
}
|
||||
|
||||
function responseURL (response) {
|
||||
@@ -104225,66 +102563,56 @@ function bytesMatch (bytes, metadataList) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 3. If parsedMetadata is the empty set, return true.
|
||||
// 3. If response is not eligible for integrity validation, return false.
|
||||
// TODO
|
||||
|
||||
// 4. If parsedMetadata is the empty set, return true.
|
||||
if (parsedMetadata.length === 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 4. Let metadata be the result of getting the strongest
|
||||
// 5. Let metadata be the result of getting the strongest
|
||||
// metadata from parsedMetadata.
|
||||
const list = parsedMetadata.sort((c, d) => d.algo.localeCompare(c.algo))
|
||||
// get the strongest algorithm
|
||||
const strongest = list[0].algo
|
||||
// get all entries that use the strongest algorithm; ignore weaker
|
||||
const metadata = list.filter((item) => item.algo === strongest)
|
||||
const strongest = getStrongestMetadata(parsedMetadata)
|
||||
const metadata = filterMetadataListByAlgorithm(parsedMetadata, strongest)
|
||||
|
||||
// 5. For each item in metadata:
|
||||
// 6. For each item in metadata:
|
||||
for (const item of metadata) {
|
||||
// 1. Let algorithm be the alg component of item.
|
||||
const algorithm = item.algo
|
||||
|
||||
// 2. Let expectedValue be the val component of item.
|
||||
let expectedValue = item.hash
|
||||
const expectedValue = item.hash
|
||||
|
||||
// See https://github.com/web-platform-tests/wpt/commit/e4c5cc7a5e48093220528dfdd1c4012dc3837a0e
|
||||
// "be liberal with padding". This is annoying, and it's not even in the spec.
|
||||
|
||||
if (expectedValue.endsWith('==')) {
|
||||
expectedValue = expectedValue.slice(0, -2)
|
||||
}
|
||||
|
||||
// 3. Let actualValue be the result of applying algorithm to bytes.
|
||||
let actualValue = crypto.createHash(algorithm).update(bytes).digest('base64')
|
||||
|
||||
if (actualValue.endsWith('==')) {
|
||||
actualValue = actualValue.slice(0, -2)
|
||||
if (actualValue[actualValue.length - 1] === '=') {
|
||||
if (actualValue[actualValue.length - 2] === '=') {
|
||||
actualValue = actualValue.slice(0, -2)
|
||||
} else {
|
||||
actualValue = actualValue.slice(0, -1)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. If actualValue is a case-sensitive match for expectedValue,
|
||||
// return true.
|
||||
if (actualValue === expectedValue) {
|
||||
return true
|
||||
}
|
||||
|
||||
let actualBase64URL = crypto.createHash(algorithm).update(bytes).digest('base64url')
|
||||
|
||||
if (actualBase64URL.endsWith('==')) {
|
||||
actualBase64URL = actualBase64URL.slice(0, -2)
|
||||
}
|
||||
|
||||
if (actualBase64URL === expectedValue) {
|
||||
if (compareBase64Mixed(actualValue, expectedValue)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Return false.
|
||||
// 7. Return false.
|
||||
return false
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-subresource-integrity/#grammardef-hash-with-options
|
||||
// https://www.w3.org/TR/CSP2/#source-list-syntax
|
||||
// https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1
|
||||
const parseHashWithOptions = /((?<algo>sha256|sha384|sha512)-(?<hash>[A-z0-9+/]{1}.*={0,2}))( +[\x21-\x7e]?)?/i
|
||||
const parseHashWithOptions = /(?<algo>sha256|sha384|sha512)-((?<hash>[A-Za-z0-9+/]+|[A-Za-z0-9_-]+)={0,2}(?:\s|$)( +[!-~]*)?)?/i
|
||||
|
||||
/**
|
||||
* @see https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata
|
||||
@@ -104298,8 +102626,6 @@ function parseMetadata (metadata) {
|
||||
// 2. Let empty be equal to true.
|
||||
let empty = true
|
||||
|
||||
const supportedHashes = crypto.getHashes()
|
||||
|
||||
// 3. For each token returned by splitting metadata on spaces:
|
||||
for (const token of metadata.split(' ')) {
|
||||
// 1. Set empty to false.
|
||||
@@ -104309,7 +102635,11 @@ function parseMetadata (metadata) {
|
||||
const parsedToken = parseHashWithOptions.exec(token)
|
||||
|
||||
// 3. If token does not parse, continue to the next token.
|
||||
if (parsedToken === null || parsedToken.groups === undefined) {
|
||||
if (
|
||||
parsedToken === null ||
|
||||
parsedToken.groups === undefined ||
|
||||
parsedToken.groups.algo === undefined
|
||||
) {
|
||||
// Note: Chromium blocks the request at this point, but Firefox
|
||||
// gives a warning that an invalid integrity was given. The
|
||||
// correct behavior is to ignore these, and subsequently not
|
||||
@@ -104318,11 +102648,11 @@ function parseMetadata (metadata) {
|
||||
}
|
||||
|
||||
// 4. Let algorithm be the hash-algo component of token.
|
||||
const algorithm = parsedToken.groups.algo
|
||||
const algorithm = parsedToken.groups.algo.toLowerCase()
|
||||
|
||||
// 5. If algorithm is a hash function recognized by the user
|
||||
// agent, add the parsed token to result.
|
||||
if (supportedHashes.includes(algorithm.toLowerCase())) {
|
||||
if (supportedHashes.includes(algorithm)) {
|
||||
result.push(parsedToken.groups)
|
||||
}
|
||||
}
|
||||
@@ -104335,6 +102665,82 @@ function parseMetadata (metadata) {
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ algo: 'sha256' | 'sha384' | 'sha512' }[]} metadataList
|
||||
*/
|
||||
function getStrongestMetadata (metadataList) {
|
||||
// Let algorithm be the algo component of the first item in metadataList.
|
||||
// Can be sha256
|
||||
let algorithm = metadataList[0].algo
|
||||
// If the algorithm is sha512, then it is the strongest
|
||||
// and we can return immediately
|
||||
if (algorithm[3] === '5') {
|
||||
return algorithm
|
||||
}
|
||||
|
||||
for (let i = 1; i < metadataList.length; ++i) {
|
||||
const metadata = metadataList[i]
|
||||
// If the algorithm is sha512, then it is the strongest
|
||||
// and we can break the loop immediately
|
||||
if (metadata.algo[3] === '5') {
|
||||
algorithm = 'sha512'
|
||||
break
|
||||
// If the algorithm is sha384, then a potential sha256 or sha384 is ignored
|
||||
} else if (algorithm[3] === '3') {
|
||||
continue
|
||||
// algorithm is sha256, check if algorithm is sha384 and if so, set it as
|
||||
// the strongest
|
||||
} else if (metadata.algo[3] === '3') {
|
||||
algorithm = 'sha384'
|
||||
}
|
||||
}
|
||||
return algorithm
|
||||
}
|
||||
|
||||
function filterMetadataListByAlgorithm (metadataList, algorithm) {
|
||||
if (metadataList.length === 1) {
|
||||
return metadataList
|
||||
}
|
||||
|
||||
let pos = 0
|
||||
for (let i = 0; i < metadataList.length; ++i) {
|
||||
if (metadataList[i].algo === algorithm) {
|
||||
metadataList[pos++] = metadataList[i]
|
||||
}
|
||||
}
|
||||
|
||||
metadataList.length = pos
|
||||
|
||||
return metadataList
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two base64 strings, allowing for base64url
|
||||
* in the second string.
|
||||
*
|
||||
* @param {string} actualValue always base64
|
||||
* @param {string} expectedValue base64 or base64url
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function compareBase64Mixed (actualValue, expectedValue) {
|
||||
if (actualValue.length !== expectedValue.length) {
|
||||
return false
|
||||
}
|
||||
for (let i = 0; i < actualValue.length; ++i) {
|
||||
if (actualValue[i] !== expectedValue[i]) {
|
||||
if (
|
||||
(actualValue[i] === '+' && expectedValue[i] === '-') ||
|
||||
(actualValue[i] === '/' && expectedValue[i] === '_')
|
||||
) {
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-upgrade-insecure-requests/#upgrade-request
|
||||
function tryUpgradeRequestToAPotentiallyTrustworthyURL (request) {
|
||||
// TODO
|
||||
@@ -104750,7 +103156,8 @@ module.exports = {
|
||||
urlHasHttpsScheme,
|
||||
urlIsHttpHttpsScheme,
|
||||
readAllBytes,
|
||||
normalizeMethodRecord
|
||||
normalizeMethodRecord,
|
||||
parseMetadata
|
||||
}
|
||||
|
||||
|
||||
@@ -106837,12 +105244,17 @@ function parseLocation (statusCode, headers) {
|
||||
|
||||
// https://tools.ietf.org/html/rfc7231#section-6.4.4
|
||||
function shouldRemoveHeader (header, removeContent, unknownOrigin) {
|
||||
return (
|
||||
(header.length === 4 && header.toString().toLowerCase() === 'host') ||
|
||||
(removeContent && header.toString().toLowerCase().indexOf('content-') === 0) ||
|
||||
(unknownOrigin && header.length === 13 && header.toString().toLowerCase() === 'authorization') ||
|
||||
(unknownOrigin && header.length === 6 && header.toString().toLowerCase() === 'cookie')
|
||||
)
|
||||
if (header.length === 4) {
|
||||
return util.headerNameToString(header) === 'host'
|
||||
}
|
||||
if (removeContent && util.headerNameToString(header).startsWith('content-')) {
|
||||
return true
|
||||
}
|
||||
if (unknownOrigin && (header.length === 13 || header.length === 6 || header.length === 19)) {
|
||||
const name = util.headerNameToString(header)
|
||||
return name === 'authorization' || name === 'cookie' || name === 'proxy-authorization'
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc7231#section-6.4
|
||||
@@ -120298,6 +118710,7 @@ var Inputs;
|
||||
Inputs["RunID"] = "run-id";
|
||||
Inputs["Pattern"] = "pattern";
|
||||
Inputs["MergeMultiple"] = "merge-multiple";
|
||||
Inputs["ArtifactIds"] = "artifact-ids";
|
||||
})(Inputs || (exports.Inputs = Inputs = {}));
|
||||
var Outputs;
|
||||
(function (Outputs) {
|
||||
@@ -120348,7 +118761,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.chunk = void 0;
|
||||
exports.run = exports.chunk = void 0;
|
||||
const os = __importStar(__nccwpck_require__(22037));
|
||||
const path = __importStar(__nccwpck_require__(71017));
|
||||
const core = __importStar(__nccwpck_require__(42186));
|
||||
@@ -120371,7 +118784,10 @@ function run() {
|
||||
repository: core.getInput(constants_1.Inputs.Repository, { required: false }),
|
||||
runID: parseInt(core.getInput(constants_1.Inputs.RunID, { required: false })),
|
||||
pattern: core.getInput(constants_1.Inputs.Pattern, { required: false }),
|
||||
mergeMultiple: core.getBooleanInput(constants_1.Inputs.MergeMultiple, { required: false })
|
||||
mergeMultiple: core.getBooleanInput(constants_1.Inputs.MergeMultiple, {
|
||||
required: false
|
||||
}),
|
||||
artifactIds: core.getInput(constants_1.Inputs.ArtifactIds, { required: false })
|
||||
};
|
||||
if (!inputs.path) {
|
||||
inputs.path = process.env['GITHUB_WORKSPACE'] || process.cwd();
|
||||
@@ -120379,7 +118795,12 @@ function run() {
|
||||
if (inputs.path.startsWith(`~`)) {
|
||||
inputs.path = inputs.path.replace('~', os.homedir());
|
||||
}
|
||||
// Check for mutually exclusive inputs
|
||||
if (inputs.name && inputs.artifactIds) {
|
||||
throw new Error(`Inputs 'name' and 'artifact-ids' cannot be used together. Please specify only one.`);
|
||||
}
|
||||
const isSingleArtifactDownload = !!inputs.name;
|
||||
const isDownloadByIds = !!inputs.artifactIds;
|
||||
const resolvedPath = path.resolve(inputs.path);
|
||||
core.debug(`Resolved path is ${resolvedPath}`);
|
||||
const options = {};
|
||||
@@ -120396,6 +118817,7 @@ function run() {
|
||||
};
|
||||
}
|
||||
let artifacts = [];
|
||||
let artifactIds = [];
|
||||
if (isSingleArtifactDownload) {
|
||||
core.info(`Downloading single artifact`);
|
||||
const { artifact: targetArtifact } = yield artifact_1.default.getArtifact(inputs.name, options);
|
||||
@@ -120405,6 +118827,37 @@ function run() {
|
||||
core.debug(`Found named artifact '${inputs.name}' (ID: ${targetArtifact.id}, Size: ${targetArtifact.size})`);
|
||||
artifacts = [targetArtifact];
|
||||
}
|
||||
else if (isDownloadByIds) {
|
||||
core.info(`Downloading artifacts by ID`);
|
||||
const artifactIdList = inputs.artifactIds
|
||||
.split(',')
|
||||
.map(id => id.trim())
|
||||
.filter(id => id !== '');
|
||||
if (artifactIdList.length === 0) {
|
||||
throw new Error(`No valid artifact IDs provided in 'artifact-ids' input`);
|
||||
}
|
||||
core.debug(`Parsed artifact IDs: ${JSON.stringify(artifactIdList)}`);
|
||||
// Parse the artifact IDs
|
||||
artifactIds = artifactIdList.map(id => {
|
||||
const numericId = parseInt(id, 10);
|
||||
if (isNaN(numericId)) {
|
||||
throw new Error(`Invalid artifact ID: '${id}'. Must be a number.`);
|
||||
}
|
||||
return numericId;
|
||||
});
|
||||
// We need to fetch all artifacts to get metadata for the specified IDs
|
||||
const listArtifactResponse = yield artifact_1.default.listArtifacts(Object.assign({ latest: true }, options));
|
||||
artifacts = listArtifactResponse.artifacts.filter(artifact => artifactIds.includes(artifact.id));
|
||||
if (artifacts.length === 0) {
|
||||
throw new Error(`None of the provided artifact IDs were found`);
|
||||
}
|
||||
if (artifacts.length < artifactIds.length) {
|
||||
const foundIds = artifacts.map(a => a.id);
|
||||
const missingIds = artifactIds.filter(id => !foundIds.includes(id));
|
||||
core.warning(`Could not find the following artifact IDs: ${missingIds.join(', ')}`);
|
||||
}
|
||||
core.debug(`Found ${artifacts.length} artifacts by ID`);
|
||||
}
|
||||
else {
|
||||
const listArtifactResponse = yield artifact_1.default.listArtifacts(Object.assign({ latest: true }, options));
|
||||
artifacts = listArtifactResponse.artifacts;
|
||||
@@ -120416,7 +118869,7 @@ function run() {
|
||||
core.debug(`Filtered from ${listArtifactResponse.artifacts.length} to ${artifacts.length} artifacts`);
|
||||
}
|
||||
else {
|
||||
core.info('No input name or pattern filtered specified, downloading all artifacts');
|
||||
core.info('No input name, artifact-ids or pattern filtered specified, downloading all artifacts');
|
||||
if (!inputs.mergeMultiple) {
|
||||
core.info('An extra directory with the artifact name will be created for each download');
|
||||
}
|
||||
@@ -120425,21 +118878,33 @@ function run() {
|
||||
if (artifacts.length) {
|
||||
core.info(`Preparing to download the following artifacts:`);
|
||||
artifacts.forEach(artifact => {
|
||||
core.info(`- ${artifact.name} (ID: ${artifact.id}, Size: ${artifact.size})`);
|
||||
core.info(`- ${artifact.name} (ID: ${artifact.id}, Size: ${artifact.size}, Expected Digest: ${artifact.digest})`);
|
||||
});
|
||||
}
|
||||
const downloadPromises = artifacts.map(artifact => artifact_1.default.downloadArtifact(artifact.id, Object.assign(Object.assign({}, options), { path: isSingleArtifactDownload || inputs.mergeMultiple
|
||||
? resolvedPath
|
||||
: path.join(resolvedPath, artifact.name) })));
|
||||
const downloadPromises = artifacts.map(artifact => ({
|
||||
name: artifact.name,
|
||||
promise: artifact_1.default.downloadArtifact(artifact.id, Object.assign(Object.assign({}, options), { path: isSingleArtifactDownload || inputs.mergeMultiple
|
||||
? resolvedPath
|
||||
: path.join(resolvedPath, artifact.name), expectedHash: artifact.digest }))
|
||||
}));
|
||||
const chunkedPromises = (0, exports.chunk)(downloadPromises, PARALLEL_DOWNLOADS);
|
||||
for (const chunk of chunkedPromises) {
|
||||
yield Promise.all(chunk);
|
||||
const chunkPromises = chunk.map(item => item.promise);
|
||||
const results = yield Promise.all(chunkPromises);
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
const outcome = results[i];
|
||||
const artifactName = chunk[i].name;
|
||||
if (outcome.digestMismatch) {
|
||||
core.warning(`Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
core.info(`Total of ${artifacts.length} artifact(s) downloaded`);
|
||||
core.setOutput(constants_1.Outputs.DownloadPath, resolvedPath);
|
||||
core.info('Download artifact has finished successfully');
|
||||
});
|
||||
}
|
||||
exports.run = run;
|
||||
run().catch(err => core.setFailed(`Unable to download artifact(s): ${err.message}`));
|
||||
|
||||
|
||||
@@ -130415,7 +128880,7 @@ module.exports = index;
|
||||
/***/ ((module) => {
|
||||
|
||||
"use strict";
|
||||
module.exports = JSON.parse('{"name":"@actions/artifact","version":"2.1.6","preview":true,"description":"Actions artifact lib","keywords":["github","actions","artifact"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/artifact","license":"MIT","main":"lib/artifact.js","types":"lib/artifact.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/artifact"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"cd ../../ && npm run test ./packages/artifact","bootstrap":"cd ../../ && npm run bootstrap","tsc-run":"tsc","tsc":"npm run bootstrap && npm run tsc-run","gen:docs":"typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^1.10.0","@actions/github":"^5.1.1","@actions/http-client":"^2.1.0","@azure/storage-blob":"^12.15.0","@octokit/core":"^3.5.1","@octokit/plugin-request-log":"^1.0.4","@octokit/plugin-retry":"^3.0.9","@octokit/request-error":"^5.0.0","@protobuf-ts/plugin":"^2.2.3-alpha.1","archiver":"^7.0.1","crypto":"^1.0.1","jwt-decode":"^3.1.2","twirp-ts":"^2.5.0","unzip-stream":"^0.3.1"},"devDependencies":{"@types/archiver":"^5.3.2","@types/unzip-stream":"^0.3.4","typedoc":"^0.25.4","typedoc-plugin-markdown":"^3.17.1","typescript":"^5.2.2"}}');
|
||||
module.exports = JSON.parse('{"name":"@actions/artifact","version":"2.3.2","preview":true,"description":"Actions artifact lib","keywords":["github","actions","artifact"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/artifact","license":"MIT","main":"lib/artifact.js","types":"lib/artifact.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/artifact"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"cd ../../ && npm run test ./packages/artifact","bootstrap":"cd ../../ && npm run bootstrap","tsc-run":"tsc","tsc":"npm run bootstrap && npm run tsc-run","gen:docs":"typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^1.10.0","@actions/github":"^5.1.1","@actions/http-client":"^2.1.0","@azure/storage-blob":"^12.15.0","@octokit/core":"^3.5.1","@octokit/plugin-request-log":"^1.0.4","@octokit/plugin-retry":"^3.0.9","@octokit/request-error":"^5.0.0","@protobuf-ts/plugin":"^2.2.3-alpha.1","archiver":"^7.0.1","jwt-decode":"^3.1.2","unzip-stream":"^0.3.1"},"devDependencies":{"@types/archiver":"^5.3.2","@types/unzip-stream":"^0.3.4","typedoc":"^0.25.4","typedoc-plugin-markdown":"^3.17.1","typescript":"^5.2.2"}}');
|
||||
|
||||
/***/ }),
|
||||
|
||||
@@ -130493,4 +128958,4 @@ module.exports = JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"]
|
||||
/******/ module.exports = __webpack_exports__;
|
||||
/******/
|
||||
/******/ })()
|
||||
;
|
||||
;
|
||||
|
||||
+47
-2
@@ -4,6 +4,7 @@
|
||||
- [Multiple uploads to the same named Artifact](#multiple-uploads-to-the-same-named-artifact)
|
||||
- [Overwriting an Artifact](#overwriting-an-artifact)
|
||||
- [Merging multiple artifacts](#merging-multiple-artifacts)
|
||||
- [Working with Immutable Artifacts](#working-with-immutable-artifacts)
|
||||
|
||||
Several behavioral differences exist between Artifact actions `v3` and below vs `v4`. This document outlines common scenarios in `v3`, and how they would be handled in `v4`.
|
||||
|
||||
@@ -189,7 +190,8 @@ jobs:
|
||||
- name: Create a File
|
||||
run: echo "hello from ${{ matrix.runs-on }}" > file-${{ matrix.runs-on }}.txt
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v3
|
||||
+ uses: actions/upload-artifact@v4
|
||||
with:
|
||||
- name: all-my-files
|
||||
+ name: my-artifact-${{ matrix.runs-on }}
|
||||
@@ -205,4 +207,47 @@ jobs:
|
||||
+ pattern: my-artifact-*
|
||||
```
|
||||
|
||||
Note that this will download all artifacts to a temporary directory and reupload them as a single artifact. For more information on inputs and other use cases for `actions/upload-artifact/merge@v4`, see [the action documentation](../merge/README.md).
|
||||
Note that this will download all artifacts to a temporary directory and reupload them as a single artifact. For more information on inputs and other use cases for `actions/upload-artifact/merge@v4`, see [the action documentation](https://github.com/actions/upload-artifact/blob/main/merge/README.md).
|
||||
|
||||
## Working with Immutable Artifacts
|
||||
|
||||
In `v4`, artifacts are immutable by default and each artifact gets a unique ID when uploaded. When an artifact with the same name is uploaded again (with or without `overwrite: true`), it gets a new artifact ID.
|
||||
|
||||
To take advantage of this immutability for security purposes (to avoid potential TOCTOU issues where an artifact might be replaced between upload and download), the new `artifact-ids` input allows you to download artifacts by their specific ID rather than by name:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Make the artifact ID available to the download job
|
||||
outputs:
|
||||
artifact-id: ${{ steps.upload-step.outputs.artifact-id }}
|
||||
|
||||
steps:
|
||||
- name: Create a file
|
||||
run: echo "hello world" > my-file.txt
|
||||
- name: Upload Artifact
|
||||
id: upload-step
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: my-artifact
|
||||
path: my-file.txt
|
||||
# The upload step outputs the artifact ID
|
||||
- name: Print Artifact ID
|
||||
run: echo "Artifact ID is ${{ steps.upload-step.outputs.artifact-id }}"
|
||||
|
||||
download:
|
||||
needs: upload
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download Artifact by ID
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
# Use the artifact ID directly, not the name, to ensure you get exactly the artifact you expect
|
||||
artifact-ids: ${{ needs.upload.outputs.artifact-id }}
|
||||
```
|
||||
|
||||
This approach provides stronger guarantees about which artifact version you're downloading compared to using just the artifact name.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
roots: ['<rootDir>'],
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.ts'],
|
||||
testRunner: 'jest-circus/runner',
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
},
|
||||
verbose: true
|
||||
}
|
||||
Generated
+8293
-422
File diff suppressed because it is too large
Load Diff
+8
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "download-artifact",
|
||||
"version": "4.1.6",
|
||||
"version": "4.3.0",
|
||||
"description": "Download an Actions Artifact from a workflow run",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
@@ -9,7 +9,8 @@
|
||||
"check-all": "concurrently \"npm:format-check\" \"npm:lint\" \"npm:build\"",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"lint": "eslint **/*.ts"
|
||||
"lint": "eslint **/*.ts",
|
||||
"test": "jest"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -28,12 +29,13 @@
|
||||
},
|
||||
"homepage": "https://github.com/actions/download-artifact#readme",
|
||||
"dependencies": {
|
||||
"@actions/artifact": "^2.1.6",
|
||||
"@actions/artifact": "^2.3.2",
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"minimatch": "^9.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^12.12.6",
|
||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
||||
"@vercel/ncc": "^0.33.4",
|
||||
@@ -41,7 +43,10 @@
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-plugin-github": "^4.10.1",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.1.1",
|
||||
"ts-jest": "^29.2.6",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@ export enum Inputs {
|
||||
Repository = 'repository',
|
||||
RunID = 'run-id',
|
||||
Pattern = 'pattern',
|
||||
MergeMultiple = 'merge-multiple'
|
||||
MergeMultiple = 'merge-multiple',
|
||||
ArtifactIds = 'artifact-ids'
|
||||
}
|
||||
|
||||
export enum Outputs {
|
||||
|
||||
+81
-10
@@ -15,7 +15,7 @@ export const chunk = <T>(arr: T[], n: number): T[][] =>
|
||||
return acc
|
||||
}, [] as T[][])
|
||||
|
||||
async function run(): Promise<void> {
|
||||
export async function run(): Promise<void> {
|
||||
const inputs = {
|
||||
name: core.getInput(Inputs.Name, {required: false}),
|
||||
path: core.getInput(Inputs.Path, {required: false}),
|
||||
@@ -23,7 +23,10 @@ async function run(): Promise<void> {
|
||||
repository: core.getInput(Inputs.Repository, {required: false}),
|
||||
runID: parseInt(core.getInput(Inputs.RunID, {required: false})),
|
||||
pattern: core.getInput(Inputs.Pattern, {required: false}),
|
||||
mergeMultiple: core.getBooleanInput(Inputs.MergeMultiple, {required: false})
|
||||
mergeMultiple: core.getBooleanInput(Inputs.MergeMultiple, {
|
||||
required: false
|
||||
}),
|
||||
artifactIds: core.getInput(Inputs.ArtifactIds, {required: false})
|
||||
}
|
||||
|
||||
if (!inputs.path) {
|
||||
@@ -34,7 +37,15 @@ async function run(): Promise<void> {
|
||||
inputs.path = inputs.path.replace('~', os.homedir())
|
||||
}
|
||||
|
||||
// Check for mutually exclusive inputs
|
||||
if (inputs.name && inputs.artifactIds) {
|
||||
throw new Error(
|
||||
`Inputs 'name' and 'artifact-ids' cannot be used together. Please specify only one.`
|
||||
)
|
||||
}
|
||||
|
||||
const isSingleArtifactDownload = !!inputs.name
|
||||
const isDownloadByIds = !!inputs.artifactIds
|
||||
const resolvedPath = path.resolve(inputs.path)
|
||||
core.debug(`Resolved path is ${resolvedPath}`)
|
||||
|
||||
@@ -56,6 +67,7 @@ async function run(): Promise<void> {
|
||||
}
|
||||
|
||||
let artifacts: Artifact[] = []
|
||||
let artifactIds: number[] = []
|
||||
|
||||
if (isSingleArtifactDownload) {
|
||||
core.info(`Downloading single artifact`)
|
||||
@@ -74,6 +86,52 @@ async function run(): Promise<void> {
|
||||
)
|
||||
|
||||
artifacts = [targetArtifact]
|
||||
} else if (isDownloadByIds) {
|
||||
core.info(`Downloading artifacts by ID`)
|
||||
|
||||
const artifactIdList = inputs.artifactIds
|
||||
.split(',')
|
||||
.map(id => id.trim())
|
||||
.filter(id => id !== '')
|
||||
|
||||
if (artifactIdList.length === 0) {
|
||||
throw new Error(`No valid artifact IDs provided in 'artifact-ids' input`)
|
||||
}
|
||||
|
||||
core.debug(`Parsed artifact IDs: ${JSON.stringify(artifactIdList)}`)
|
||||
|
||||
// Parse the artifact IDs
|
||||
artifactIds = artifactIdList.map(id => {
|
||||
const numericId = parseInt(id, 10)
|
||||
if (isNaN(numericId)) {
|
||||
throw new Error(`Invalid artifact ID: '${id}'. Must be a number.`)
|
||||
}
|
||||
return numericId
|
||||
})
|
||||
|
||||
// We need to fetch all artifacts to get metadata for the specified IDs
|
||||
const listArtifactResponse = await artifactClient.listArtifacts({
|
||||
latest: true,
|
||||
...options
|
||||
})
|
||||
|
||||
artifacts = listArtifactResponse.artifacts.filter(artifact =>
|
||||
artifactIds.includes(artifact.id)
|
||||
)
|
||||
|
||||
if (artifacts.length === 0) {
|
||||
throw new Error(`None of the provided artifact IDs were found`)
|
||||
}
|
||||
|
||||
if (artifacts.length < artifactIds.length) {
|
||||
const foundIds = artifacts.map(a => a.id)
|
||||
const missingIds = artifactIds.filter(id => !foundIds.includes(id))
|
||||
core.warning(
|
||||
`Could not find the following artifact IDs: ${missingIds.join(', ')}`
|
||||
)
|
||||
}
|
||||
|
||||
core.debug(`Found ${artifacts.length} artifacts by ID`)
|
||||
} else {
|
||||
const listArtifactResponse = await artifactClient.listArtifacts({
|
||||
latest: true,
|
||||
@@ -92,7 +150,7 @@ async function run(): Promise<void> {
|
||||
)
|
||||
} else {
|
||||
core.info(
|
||||
'No input name or pattern filtered specified, downloading all artifacts'
|
||||
'No input name, artifact-ids or pattern filtered specified, downloading all artifacts'
|
||||
)
|
||||
if (!inputs.mergeMultiple) {
|
||||
core.info(
|
||||
@@ -106,26 +164,39 @@ async function run(): Promise<void> {
|
||||
core.info(`Preparing to download the following artifacts:`)
|
||||
artifacts.forEach(artifact => {
|
||||
core.info(
|
||||
`- ${artifact.name} (ID: ${artifact.id}, Size: ${artifact.size})`
|
||||
`- ${artifact.name} (ID: ${artifact.id}, Size: ${artifact.size}, Expected Digest: ${artifact.digest})`
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const downloadPromises = artifacts.map(artifact =>
|
||||
artifactClient.downloadArtifact(artifact.id, {
|
||||
const downloadPromises = artifacts.map(artifact => ({
|
||||
name: artifact.name,
|
||||
promise: artifactClient.downloadArtifact(artifact.id, {
|
||||
...options,
|
||||
path:
|
||||
isSingleArtifactDownload || inputs.mergeMultiple
|
||||
? resolvedPath
|
||||
: path.join(resolvedPath, artifact.name)
|
||||
: path.join(resolvedPath, artifact.name),
|
||||
expectedHash: artifact.digest
|
||||
})
|
||||
)
|
||||
}))
|
||||
|
||||
const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS)
|
||||
for (const chunk of chunkedPromises) {
|
||||
await Promise.all(chunk)
|
||||
}
|
||||
const chunkPromises = chunk.map(item => item.promise)
|
||||
const results = await Promise.all(chunkPromises)
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
const outcome = results[i]
|
||||
const artifactName = chunk[i].name
|
||||
|
||||
if (outcome.digestMismatch) {
|
||||
core.warning(
|
||||
`Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
core.info(`Total of ${artifacts.length} artifact(s) downloaded`)
|
||||
core.setOutput(Outputs.DownloadPath, resolvedPath)
|
||||
core.info('Download artifact has finished successfully')
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
"exclude": ["node_modules", "**/*.test.ts", "jest.config.ts", "__tests__"]
|
||||
}
|
||||
Reference in New Issue
Block a user