@paklo/core 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/azure/index.d.mts +930 -116
- package/dist/azure/index.mjs +412 -229
- package/dist/azure/index.mjs.map +1 -1
- package/dist/dependabot/index.d.mts +3 -3
- package/dist/dependabot/index.mjs +3 -4
- package/dist/{dependabot-E0nM5Xbb.mjs → dependabot-rtPO9HdD.mjs} +6 -13
- package/dist/dependabot-rtPO9HdD.mjs.map +1 -0
- package/dist/github/index.d.mts +1 -1
- package/dist/github/index.mjs +1 -1
- package/dist/{index-BWftXTYB.d.mts → index-BfwWezjJ.d.mts} +1 -1
- package/dist/{index-bwD11mTZ.d.mts → index-Byxjhvfz.d.mts} +16 -17
- package/dist/{job-DanO84YW.mjs → job-BxOZ-hqF.mjs} +1 -1
- package/dist/{job-DanO84YW.mjs.map → job-BxOZ-hqF.mjs.map} +1 -1
- package/dist/{logger-BqvUa-Ue.mjs → logger-5PEqZVLr.mjs} +10 -3
- package/dist/{logger-BqvUa-Ue.mjs.map → logger-5PEqZVLr.mjs.map} +1 -1
- package/dist/logger.mjs +1 -1
- package/dist/usage.mjs +1 -1
- package/package.json +3 -6
- package/dist/dependabot-E0nM5Xbb.mjs.map +0 -1
- package/dist/http/index.d.mts +0 -121
- package/dist/http/index.mjs +0 -3
- package/dist/http-D2wwAKQ-.mjs +0 -241
- package/dist/http-D2wwAKQ-.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger-
|
|
1
|
+
{"version":3,"file":"logger-5PEqZVLr.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import pino, { type DestinationStream, type Level } from 'pino';\nimport pretty from 'pino-pretty';\n\nexport type LoggerCreateOptions = {\n /**\n * Log level\n * Only set this if you must override the default log level logic from env variables\n */\n level?: Level;\n\n /**\n * Whether to include time stamps in log entries\n * @default false\n */\n timestamp?: boolean;\n\n /** Options for pretty printing */\n pretty?: {\n /**\n * Whether to enable pretty printing\n * @default true\n */\n enable?: boolean;\n\n /**\n * Whether to colorize the pretty printed output\n * @default true\n */\n colorize?: boolean;\n\n /**\n * Whether to include the log level in pretty printed output\n * @default false\n */\n includeLevel?: boolean;\n };\n\n /**\n * Additional streams, if any, to write logs to.\n * This is in addition to any pretty printing stream configured.\n * Useful for adding things like OpenTelemetry streams.\n */\n streams?: DestinationStream[];\n};\n\n/**\n * Creates a new logger with the given options.\n * @param options - Logger creation options\n * @returns A logger instance\n */\nexport function create(options: LoggerCreateOptions = {}) {\n const {\n level,\n timestamp = false,\n pretty: {\n // options for pretty printing\n enable: prettyEnable = true,\n colorize: prettyColorize = true,\n includeLevel: prettyIncludeLevel = false,\n } = {},\n streams = [],\n } = options;\n\n // configure pretty printing stream, if enabled\n const prettyStream = prettyEnable\n ? pretty({\n colorize: prettyColorize,\n ignore: 'pid,hostname',\n customPrettifiers: prettyIncludeLevel ? undefined : { level: () => '' },\n // these colors only apply to the log level which we may be hiding above\n // support for custom colors in the message itself is not yet supported\n // https://github.com/pinojs/pino-pretty/issues/430\n // https://github.com/pinojs/pino-pretty/issues/524\n // https://github.com/pinojs/pino-pretty/pull/611\n customColors: {\n trace: 'grey',\n debug: 'grey',\n info: 'white',\n warn: 'yellow',\n error: 'red',\n fatal: 'magenta',\n } satisfies Record<Level, string>,\n })\n : undefined;\n\n // create and return the logger\n const resolvedLevel = level || process.env.LOG_LEVEL || (process.env.NODE_ENV === 'production' ? 'warn' : 'debug');\n return pino(\n {\n level: resolvedLevel,\n timestamp,\n },\n pino.multistream([\n // add streams conditionally\n // without setting the level on each stream, some logs seem to be skipped\n ...(prettyStream ? [{ level: resolvedLevel, stream: prettyStream }] : []),\n ...streams.map((stream) => ({ level: resolvedLevel, stream })),\n ]),\n );\n}\n\n/** Default logger instance */\nexport const logger = create();\n"],"mappings":";;;;;;;;;AAkDA,SAAgB,OAAO,UAA+B,EAAE,EAAE;CACxD,MAAM,EACJ,OACA,YAAY,OACZ,QAAQ,EAEN,QAAQ,eAAe,MACvB,UAAU,iBAAiB,MAC3B,cAAc,qBAAqB,UACjC,EAAE,EACN,UAAU,EAAE,KACV;CAGJ,MAAM,eAAe,eACjB,OAAO;EACL,UAAU;EACV,QAAQ;EACR,mBAAmB,qBAAqB,SAAY,EAAE,aAAa,IAAI;EAMvE,cAAc;GACZ,OAAO;GACP,OAAO;GACP,MAAM;GACN,MAAM;GACN,OAAO;GACP,OAAO;GACR;EACF,CAAC,GACF;CAGJ,MAAM,gBAAgB,SAAS,QAAQ,IAAI,cAAc,QAAQ,IAAI,aAAa,eAAe,SAAS;AAC1G,QAAO,KACL;EACE,OAAO;EACP;EACD,EACD,KAAK,YAAY,CAGf,GAAI,eAAe,CAAC;EAAE,OAAO;EAAe,QAAQ;EAAc,CAAC,GAAG,EAAE,EACxE,GAAG,QAAQ,KAAK,YAAY;EAAE,OAAO;EAAe;EAAQ,EAAE,CAC/D,CAAC,CACH;;;AAIH,MAAa,SAAS,QAAQ"}
|
package/dist/logger.mjs
CHANGED
package/dist/usage.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as DependabotSourceProviderSchema, h as DependabotPackageManagerSchema } from "./job-
|
|
1
|
+
import { b as DependabotSourceProviderSchema, h as DependabotPackageManagerSchema } from "./job-BxOZ-hqF.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
//#region src/usage.ts
|
package/package.json
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paklo/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "mburumaxwell",
|
|
7
7
|
"license": "AGPL-3.0-later",
|
|
8
8
|
"exports": {
|
|
9
|
-
"./http": {
|
|
10
|
-
"types": "./dist/http/index.d.mts",
|
|
11
|
-
"import": "./dist/http/index.mjs"
|
|
12
|
-
},
|
|
13
9
|
"./hono": {
|
|
14
10
|
"types": "./dist/hono.d.mts",
|
|
15
11
|
"import": "./dist/hono.mjs"
|
|
@@ -62,6 +58,7 @@
|
|
|
62
58
|
"@hono/zod-validator": "0.7.5",
|
|
63
59
|
"hono": "4.10.7",
|
|
64
60
|
"js-yaml": "4.1.1",
|
|
61
|
+
"ky": "1.14.1",
|
|
65
62
|
"octokit": "5.0.5",
|
|
66
63
|
"pino": "10.1.0",
|
|
67
64
|
"pino-pretty": "13.1.3",
|
|
@@ -72,7 +69,7 @@
|
|
|
72
69
|
"@types/js-yaml": "4.0.9",
|
|
73
70
|
"@types/node": "24.10.1",
|
|
74
71
|
"@types/semver": "7.7.1",
|
|
75
|
-
"tsdown": "0.
|
|
72
|
+
"tsdown": "0.17.1"
|
|
76
73
|
},
|
|
77
74
|
"publishConfig": {
|
|
78
75
|
"access": "public"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dependabot-E0nM5Xbb.mjs","names":["branchName: string","crypto","DEFAULT_EXPERIMENTS: DependabotExperiments","updatingPullRequest: boolean","updateDependencyGroupName: string | null","updateDependencyNames: string[] | null","vulnerabilities: SecurityVulnerability[] | undefined","success: boolean"],"sources":["../src/dependabot/author.ts","../src/dependabot/branch-name.ts","../src/dependabot/experiments.ts","../src/dependabot/job-builder.ts","../src/dependabot/update.ts","../src/dependabot/server.ts"],"sourcesContent":["export type GitAuthor = {\n name: string;\n email: string;\n};\n\nexport const DEPENDABOT_DEFAULT_AUTHOR_EMAIL = 'noreply@github.com';\nexport const DEPENDABOT_DEFAULT_AUTHOR_NAME = 'dependabot[bot]';\n","import * as crypto from 'node:crypto';\nimport type { PackageEcosystem } from './config';\nimport type { DependabotExistingPR } from './job';\n\n// TODO: figure out how to handle IDENTIFIER field (in a group) in branch naming\n// Docs: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#groups--\n// -> An identifier for a group is used in branch names and pull request titles.\n\nexport function getBranchNameForUpdate(\n packageEcosystem: PackageEcosystem,\n targetBranchName: string | undefined,\n directory: string | undefined,\n dependencyGroupName: string | undefined,\n dependencies: DependabotExistingPR[],\n separator: string = '/',\n): string {\n // Based on dependabot-core implementation:\n // https://github.com/dependabot/dependabot-core/blob/main/common/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb\n // https://github.com/dependabot/dependabot-core/blob/main/common/lib/dependabot/pull_request_creator/branch_namer/dependency_group_strategy.rb\n let branchName: string;\n const branchNameMightBeTooLong = dependencyGroupName || dependencies.length > 1;\n if (branchNameMightBeTooLong) {\n // Group/multi dependency update\n // e.g. dependabot/nuget/main/microsoft-3b49c54d9e\n const dependencyDigest = crypto\n .createHash('md5')\n .update(dependencies.map((d) => `${d['dependency-name']}-${d['dependency-version']}`).join(','))\n .digest('hex')\n .substring(0, 10);\n branchName = `${dependencyGroupName || 'multi'}-${dependencyDigest}`;\n } else {\n // Single dependency update\n // e.g. dependabot/nuget/main/Microsoft.Extensions.Logging-1.0.0\n const dependencyNames = dependencies\n .map((d) => d['dependency-name'])\n .join('-and-')\n .replace(/[:[]]/g, '-') // Replace `:` and `[]` with `-`\n .replace(/@/g, ''); // Remove `@`\n const versionSuffix = dependencies[0]?.removed ? 'removed' : dependencies[0]?.['dependency-version'];\n branchName = `${dependencyNames}-${versionSuffix}`;\n }\n\n return sanitizeRef(\n [\n 'dependabot',\n packageEcosystem,\n targetBranchName,\n // normalize directory to remove leading/trailing slashes and replace remaining ones with the separator\n directory\n ? directory\n .split('/')\n .filter((part) => part.length > 0)\n .join(separator)\n : undefined,\n branchName,\n ],\n separator,\n );\n}\n\nexport function sanitizeRef(refParts: (string | undefined)[], separator: string): string {\n // Based on dependabot-core implementation:\n // https://github.com/dependabot/dependabot-core/blob/fc31ae64f492dc977cfe6773ab13fb6373aabec4/common/lib/dependabot/pull_request_creator/branch_namer/base.rb#L99\n\n // This isn't a complete implementation of git's ref validation, but it\n // covers most cases that crop up. Its list of allowed characters is a\n // bit stricter than git's, but that's for cosmetic reasons.\n return (\n refParts\n // Join the parts with the separator, ignore empty parts\n .filter((p) => p && p.trim().length > 0)\n .join(separator)\n // Remove forbidden characters (those not already replaced elsewhere)\n .replace(/[^A-Za-z0-9/\\-_.(){}]/g, '')\n // Slashes can't be followed by periods\n .replace(/\\/\\./g, '/dot-')\n // Squeeze out consecutive periods and slashes\n .replace(/\\.+/g, '.')\n .replace(/\\/+/g, '/')\n // Trailing periods are forbidden\n .replace(/\\.$/, '')\n );\n}\n","import type { DependabotExperiments } from './job';\n\n// The default experiments known to be used by the GitHub Dependabot service.\n// This changes often, update as needed by extracting them from a Dependabot GitHub Action run.\n// e.g. https://github.com/mburumaxwell/dependabot-azure-devops/actions/workflows/dependabot/dependabot-updates\nexport const DEFAULT_EXPERIMENTS: DependabotExperiments = {\n 'record-ecosystem-versions': true,\n 'record-update-job-unknown-error': true,\n 'proxy-cached': true,\n 'dependency-change-validation': true,\n 'enable-file-parser-python-local': true,\n 'npm-fallback-version-above-v6': true,\n 'enable-record-ecosystem-meta': true,\n 'enable-corepack-for-npm-and-yarn': true,\n 'enable-shared-helpers-command-timeout': true,\n 'enable-dependabot-setting-up-cronjob': true,\n 'enable-engine-version-detection': true,\n 'avoid-duplicate-updates-package-json': true,\n 'allow-refresh-for-existing-pr-dependencies': true,\n 'allow-refresh-group-with-all-dependencies': true,\n 'exclude-local-composer-packages': true,\n 'enable-enhanced-error-details-for-updater': true,\n 'gradle-lockfile-updater': true,\n 'enable-exclude-paths-subdirectory-manifest-files': true,\n 'group-membership-enforcement': true,\n 'deprecate-close-command': true,\n 'deprecate-reopen-command': true,\n 'deprecate-merge-command': true,\n 'deprecate-cancel-merge-command': true,\n 'deprecate-squash-merge-command': true,\n};\n\n/**\n * Parses a comma-separated list of key=value pairs representing experiments.\n * @param raw A comma-separated list of key=value pairs representing experiments.\n * @returns A map of experiment names to their values.\n */\nexport function parseExperiments(raw?: string): DependabotExperiments | undefined {\n return raw\n ?.split(',')\n .filter((entry) => entry.trim() !== '') // <-- filter out empty entries\n .reduce((acc, cur) => {\n const [key, value] = cur.split('=', 2);\n acc[key!] = value || true;\n return acc;\n }, {} as DependabotExperiments);\n}\n\n/**\n * Set experiment in the given experiments map.\n * If the experiments map is undefined, a new map will be created.\n * @param experiments The experiments map to set the experiment in.\n * @param name The name of the experiment to set.\n * @param value The value of the experiment to set. Defaults to true.\n * @returns The updated experiments map.\n */\nexport function setExperiment(\n experiments: DependabotExperiments | undefined,\n name: string,\n value: boolean | string = true,\n): DependabotExperiments {\n return {\n ...(experiments || {}),\n // always add the experiment, even if the value is false or an empty string\n // this allows explicit disabling of experiments\n [name]: value,\n };\n}\n","import type { SecurityVulnerability } from '@/github';\nimport type {\n DependabotAllowCondition,\n DependabotConfig,\n DependabotGroup,\n DependabotIgnoreCondition,\n DependabotRegistry,\n DependabotUpdate,\n PackageEcosystem,\n VersioningStrategy,\n} from './config';\nimport { setExperiment } from './experiments';\nimport type {\n DependabotAllowed,\n DependabotCondition,\n DependabotCredential,\n DependabotExistingGroupPR,\n DependabotExistingPR,\n DependabotExperiments,\n DependabotGroupJob,\n DependabotJobConfig,\n DependabotPackageManager,\n DependabotSecurityAdvisory,\n DependabotSource,\n DependabotSourceProvider,\n} from './job';\n\nexport type DependabotSourceInfo = {\n provider: DependabotSourceProvider;\n hostname: string;\n 'api-endpoint': string;\n 'repository-slug': string;\n};\n\nexport type DependabotJobBuilderOutput = {\n job: DependabotJobConfig;\n credentials: DependabotCredential[];\n};\n\n/**\n * Class for building dependabot job objects\n */\nexport class DependabotJobBuilder {\n private readonly config: DependabotConfig;\n private readonly update: DependabotUpdate;\n private readonly experiments: DependabotExperiments;\n private readonly debug: boolean;\n\n private readonly packageManager: DependabotPackageManager;\n private readonly source: DependabotSource;\n private readonly credentials: DependabotCredential[];\n\n constructor({\n source,\n config,\n update,\n systemAccessUser,\n systemAccessToken,\n githubToken,\n experiments,\n debug,\n }: {\n source: DependabotSourceInfo;\n config: DependabotConfig;\n update: DependabotUpdate;\n experiments: DependabotExperiments;\n systemAccessUser?: string;\n systemAccessToken?: string;\n githubToken?: string;\n /** Determines if verbose log messages are logged */\n debug: boolean;\n }) {\n this.config = config;\n this.update = update;\n this.debug = debug;\n\n this.experiments = setExperiment(experiments, 'enable_beta_ecosystems', config['enable-beta-ecosystems']);\n\n this.packageManager = mapPackageEcosystemToPackageManager(update['package-ecosystem']);\n this.source = mapSourceFromDependabotConfigToJobConfig(source, update);\n this.credentials = mapCredentials({\n sourceHostname: source.hostname,\n systemAccessUser,\n systemAccessToken,\n githubToken,\n registries: config.registries,\n });\n }\n\n /**\n * Create a dependabot update job that updates nothing, but will discover the dependency list for a package ecosystem\n */\n public forDependenciesList({\n id,\n command,\n }: {\n id?: string;\n command: DependabotJobConfig['command'];\n }): DependabotJobBuilderOutput {\n id ??= makeRandomJobId();\n return {\n job: {\n id: id,\n command: command,\n 'package-manager': this.packageManager,\n 'updating-a-pull-request': false,\n dependencies: null,\n 'allowed-updates': [{ 'dependency-type': 'direct', 'update-type': 'all' }],\n 'ignore-conditions': [{ 'dependency-name': '*' }],\n 'security-updates-only': false,\n 'security-advisories': [],\n source: this.source,\n 'update-subdependencies': false,\n 'existing-pull-requests': [],\n 'existing-group-pull-requests': [],\n experiments: this.experiments,\n 'requirements-update-strategy': null,\n 'lockfile-only': false,\n 'commit-message-options': {\n prefix: null,\n 'prefix-development': null,\n 'include-scope': null,\n },\n 'vendor-dependencies': false,\n 'repo-private': true,\n debug: this.debug,\n },\n credentials: this.credentials,\n };\n }\n\n /**\n * Create a dependabot update job that updates all dependencies for a package ecosystem\n */\n public forUpdate({\n id,\n command,\n dependencyNamesToUpdate,\n existingPullRequests,\n pullRequestToUpdate,\n securityVulnerabilities,\n }: {\n id?: string;\n command: DependabotJobConfig['command'];\n dependencyNamesToUpdate?: string[];\n existingPullRequests: (DependabotExistingPR[] | DependabotExistingGroupPR)[];\n pullRequestToUpdate?: DependabotExistingPR[] | DependabotExistingGroupPR;\n securityVulnerabilities?: SecurityVulnerability[];\n }): DependabotJobBuilderOutput {\n id ??= makeRandomJobId();\n const securityOnlyUpdate = this.update['open-pull-requests-limit'] === 0;\n\n let updatingPullRequest: boolean;\n let updateDependencyGroupName: string | null = null;\n let updateDependencyNames: string[] | null;\n let vulnerabilities: SecurityVulnerability[] | undefined;\n\n if (pullRequestToUpdate) {\n updatingPullRequest = true;\n updateDependencyGroupName = Array.isArray(pullRequestToUpdate)\n ? null\n : pullRequestToUpdate['dependency-group-name'];\n updateDependencyNames = (\n Array.isArray(pullRequestToUpdate) ? pullRequestToUpdate : pullRequestToUpdate.dependencies\n )?.map((d) => d['dependency-name']);\n vulnerabilities = securityVulnerabilities?.filter((v) => updateDependencyNames?.includes(v.package.name));\n } else {\n updatingPullRequest = false;\n const names = dependencyNamesToUpdate?.length ? dependencyNamesToUpdate : null;\n updateDependencyNames =\n securityOnlyUpdate && names\n ? names?.filter((d) => securityVulnerabilities?.find((v) => v.package.name === d))\n : names;\n vulnerabilities = securityVulnerabilities;\n }\n\n return {\n job: {\n id: id,\n command: command,\n 'package-manager': this.packageManager,\n 'updating-a-pull-request': updatingPullRequest || false,\n 'dependency-group-to-refresh': updateDependencyGroupName,\n 'dependency-groups': mapGroupsFromDependabotConfigToJobConfig(this.update.groups),\n dependencies: updateDependencyNames,\n 'allowed-updates': mapAllowedUpdatesFromDependabotConfigToJobConfig(this.update.allow, securityOnlyUpdate),\n 'ignore-conditions': mapIgnoreConditionsFromDependabotConfigToJobConfig(this.update.ignore),\n 'security-updates-only': securityOnlyUpdate,\n 'security-advisories': mapSecurityAdvisories(vulnerabilities),\n source: this.source,\n 'update-subdependencies': false,\n 'existing-pull-requests': existingPullRequests.filter((pr) => Array.isArray(pr)),\n 'existing-group-pull-requests': existingPullRequests.filter(\n (pr): pr is DependabotExistingGroupPR => !Array.isArray(pr),\n ),\n 'commit-message-options': {\n prefix: this.update['commit-message']?.prefix ?? null,\n 'prefix-development': this.update['commit-message']?.['prefix-development'] ?? null,\n 'include-scope':\n this.update['commit-message']?.include?.toLocaleLowerCase()?.trim() === 'scope' ? true : null,\n },\n cooldown: this.update.cooldown,\n experiments: mapExperiments(this.experiments),\n 'reject-external-code':\n this.update['insecure-external-code-execution']?.toLocaleLowerCase()?.trim() === 'allow',\n 'requirements-update-strategy': mapVersionStrategyToRequirementsUpdateStrategy(\n this.update['versioning-strategy'],\n ),\n 'lockfile-only': this.update['versioning-strategy'] === 'lockfile-only',\n 'vendor-dependencies': this.update.vendor ?? false,\n 'repo-private': true,\n debug: this.debug,\n 'proxy-log-response-body-on-auth-failure': true,\n 'max-updater-run-time': 2700,\n 'enable-beta-ecosystems': this.config['enable-beta-ecosystems'] || false,\n // Updates across ecosystems is still in development\n // See https://github.com/dependabot/dependabot-core/issues/8126\n // https://github.com/dependabot/dependabot-core/pull/12339\n // It needs to merged in the core repo first before we support it\n // However, to match current job configs and to prevent surprises, we disable it\n 'multi-ecosystem-update': false,\n 'exclude-paths': this.update['exclude-paths'],\n },\n credentials: this.credentials,\n };\n }\n}\n\nexport function mapPackageEcosystemToPackageManager(ecosystem: PackageEcosystem): DependabotPackageManager {\n // Map the dependabot config \"package ecosystem\" to the equivalent dependabot-core/cli \"package manager\".\n // Config values: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#package-ecosystem-\n // Core/CLI values: https://github.com/dependabot/dependabot-core/blob/main/common/lib/dependabot/config/file.rb#L60-L81\n switch (ecosystem) {\n case 'docker-compose':\n return 'docker_compose';\n case 'dotnet-sdk':\n return 'dotnet_sdk';\n case 'github-actions':\n return 'github_actions';\n case 'gitsubmodule':\n return 'submodules';\n case 'gomod':\n return 'go_modules';\n case 'mix':\n return 'hex';\n case 'npm':\n return 'npm_and_yarn';\n // Additional aliases, sometimes used for convenience\n case 'pipenv':\n return 'pip';\n case 'pip-compile':\n return 'pip';\n case 'poetry':\n return 'pip';\n case 'pnpm':\n return 'npm_and_yarn';\n case 'rust-toolchain':\n return 'rust_toolchain';\n case 'yarn':\n return 'npm_and_yarn';\n default:\n return ecosystem;\n }\n}\n\nexport function mapSourceFromDependabotConfigToJobConfig(\n source: DependabotSourceInfo,\n update: DependabotUpdate,\n): DependabotSource {\n return {\n provider: source.provider,\n 'api-endpoint': source['api-endpoint'],\n hostname: source.hostname,\n repo: source['repository-slug'],\n branch: update['target-branch'],\n commit: null, // use latest commit of target branch\n directory: update.directory,\n directories: update.directories,\n };\n}\n\nexport function mapVersionStrategyToRequirementsUpdateStrategy(strategy?: VersioningStrategy): string | null {\n if (!strategy) return null;\n switch (strategy) {\n case 'auto':\n return null;\n case 'increase':\n return 'bump_versions';\n case 'increase-if-necessary':\n return 'bump_versions_if_necessary';\n case 'lockfile-only':\n return 'lockfile_only';\n case 'widen':\n return 'widen_ranges';\n default:\n throw new Error(`Invalid dependabot.yaml versioning strategy option '${strategy}'`);\n }\n}\n\nexport function mapGroupsFromDependabotConfigToJobConfig(\n dependencyGroups?: Record<string, DependabotGroup | null>,\n): DependabotGroupJob[] {\n if (!dependencyGroups || !Object.keys(dependencyGroups).length) return [];\n return Object.keys(dependencyGroups)\n .filter((name) => dependencyGroups[name])\n .map((name) => {\n const group = dependencyGroups[name]!;\n return {\n name: name,\n 'applies-to': group['applies-to'],\n rules: {\n patterns: group.patterns?.length ? group.patterns : ['*'],\n 'exclude-patterns': group['exclude-patterns'],\n 'dependency-type': group['dependency-type'],\n 'update-types': group['update-types'],\n },\n } satisfies DependabotGroupJob;\n });\n}\n\nexport function mapAllowedUpdatesFromDependabotConfigToJobConfig(\n allowedUpdates?: DependabotAllowCondition[],\n securityOnlyUpdate?: boolean,\n): DependabotAllowed[] {\n // If no allow conditions are specified, update direct dependencies by default; This is what GitHub does.\n // NOTE: 'update-type' appears to be a deprecated config, but still appears in the dependabot-core model and GitHub Dependabot job logs.\n // See: https://github.com/dependabot/dependabot-core/blob/b3a0c1f86c20729494097ebc695067099f5b4ada/updater/lib/dependabot/job.rb#L253C1-L257C78\n if (!allowedUpdates) {\n return [\n {\n 'dependency-type': 'direct',\n 'update-type': securityOnlyUpdate ? 'security' : 'all',\n },\n ];\n }\n return allowedUpdates.map((allow) => {\n return {\n 'dependency-name': allow['dependency-name'],\n 'dependency-type': allow['dependency-type'],\n 'update-type': allow['update-type'],\n };\n });\n}\n\nexport function mapIgnoreConditionsFromDependabotConfigToJobConfig(\n ignoreConditions?: DependabotIgnoreCondition[],\n): DependabotCondition[] {\n if (!ignoreConditions) return [];\n return ignoreConditions.map((ignore) => {\n return {\n source: ignore.source,\n 'updated-at': ignore['updated-at'],\n 'dependency-name': ignore['dependency-name'] ?? '*',\n 'update-types': ignore['update-types'],\n\n // The dependabot.yml config docs are not very clear about acceptable values; after scanning dependabot-core and dependabot-cli,\n // this could either be a single version string (e.g. '>1.0.0'), or multiple version strings separated by commas (e.g. '>1.0.0, <2.0.0')\n 'version-requirement': Array.isArray(ignore.versions) ? (<string[]>ignore.versions)?.join(', ') : ignore.versions,\n } satisfies DependabotCondition;\n });\n}\n\nexport function mapExperiments(experiments?: DependabotExperiments): DependabotExperiments {\n experiments ??= {};\n return Object.keys(experiments).reduce((acc, key) => {\n // Experiment values are known to be either 'true', 'false', or a string value.\n // If the value is 'true' or 'false', convert it to a boolean type so that dependabot-core handles it correctly.\n const value = experiments[key];\n if (typeof value === 'string' && value?.toLocaleLowerCase() === 'true') {\n acc[key] = true;\n } else if (typeof value === 'string' && value?.toLocaleLowerCase() === 'false') {\n acc[key] = false;\n } else {\n if (typeof value === 'string' || typeof value === 'boolean') acc[key] = value;\n }\n return acc;\n }, {} as DependabotExperiments);\n}\n\nexport function mapSecurityAdvisories(securityVulnerabilities?: SecurityVulnerability[]): DependabotSecurityAdvisory[] {\n if (!securityVulnerabilities) return [];\n\n // A single security advisory can cause a vulnerability in multiple versions of a package.\n // We need to map each unique security advisory to a list of affected-versions and patched-versions.\n const vulnerabilitiesGroupedByPackageNameAndAdvisoryId = new Map<string, SecurityVulnerability[]>();\n for (const vuln of securityVulnerabilities) {\n const key = `${vuln.package.name}/${vuln.advisory.identifiers.map((i) => `${i.type}:${i.value}`).join('/')}`;\n if (!vulnerabilitiesGroupedByPackageNameAndAdvisoryId.has(key)) {\n vulnerabilitiesGroupedByPackageNameAndAdvisoryId.set(key, []);\n }\n vulnerabilitiesGroupedByPackageNameAndAdvisoryId.get(key)!.push(vuln);\n }\n return Array.from(vulnerabilitiesGroupedByPackageNameAndAdvisoryId.values()).map((vulns) => {\n return {\n 'dependency-name': vulns[0]!.package.name,\n 'affected-versions': vulns.map((v) => v.vulnerableVersionRange).filter((v) => v && v.length > 0),\n 'patched-versions': vulns\n .map((v) => v.firstPatchedVersion?.identifier)\n .filter((v) => v && v.length > 0)\n .map((v) => v!),\n 'unaffected-versions': [],\n } satisfies DependabotSecurityAdvisory;\n });\n}\n\nexport function mapCredentials({\n sourceHostname,\n systemAccessUser,\n systemAccessToken,\n githubToken,\n registries,\n}: {\n sourceHostname: string;\n systemAccessUser?: string;\n systemAccessToken?: string;\n githubToken?: string;\n registries?: Record<string, DependabotRegistry>;\n}): DependabotCredential[] {\n const credentials = [];\n\n // Required to authenticate with the git repository when cloning the source code\n if (systemAccessToken) {\n credentials.push({\n type: 'git_source',\n host: sourceHostname,\n username: (systemAccessUser ?? '').trim()?.length > 0 ? systemAccessUser : 'x-access-token',\n password: systemAccessToken,\n });\n }\n\n // Required to avoid rate-limiting errors when generating pull request descriptions (e.g. fetching release notes, commit messages, etc)\n if (githubToken) {\n credentials.push({\n type: 'git_source',\n host: 'github.com',\n username: 'x-access-token',\n password: githubToken,\n });\n }\n if (registries) {\n // TODO: only registries for the current update should be set\n // Required to authenticate with private package feeds when finding the latest version of dependencies.\n // The registries have already been worked on (see parseRegistries) so there is no need to do anything else.\n credentials.push(...Object.values(registries));\n }\n\n return credentials;\n}\n\nexport function makeRandomJobId(): string {\n const array = new Uint32Array(1);\n crypto.getRandomValues(array);\n return `${array[0]! % 10000000000}`; // Limit to 10 digits to match GitHub's job IDs\n}\n","import { z } from 'zod';\nimport { DependabotDependencySchema, DependabotPackageManagerSchema } from './job';\n\n// we use nullish() because it does optional() and allows the value to be set to null\n\nexport const DependabotDependencyFileSchema = z.object({\n // https://github.com/dependabot/dependabot-core/blob/5e2711f9913cc387acb7cb0d29d51fb52d235ef2/common/lib/dependabot/dependency_file.rb#L14-L15\n content: z.string().nullish(),\n content_encoding: z\n .enum([\n 'utf-8',\n 'base64',\n // for some reason, some files (e.g. txt in gomod) are marked as empty string encoding\n '',\n ])\n .nullish(),\n deleted: z.boolean().nullish(),\n directory: z.string(),\n name: z.string(),\n operation: z.enum(['update', 'create', 'delete']),\n support_file: z.boolean().nullish(),\n vendored_file: z.boolean().nullish(),\n symlink_target: z.string().nullish(),\n type: z.string().nullish(),\n mode: z\n .enum({\n executable: '100755',\n file: '100644',\n directory: '040000',\n submodule: '160000',\n symlink: '120000',\n })\n .or(z.string())\n .nullish(),\n});\nexport type DependabotDependencyFile = z.infer<typeof DependabotDependencyFileSchema>;\n\nexport const DependabotUpdateDependencyListSchema = z.object({\n dependencies: DependabotDependencySchema.array(),\n dependency_files: z.string().array().nullish(),\n});\nexport type DependabotUpdateDependencyList = z.infer<typeof DependabotUpdateDependencyListSchema>;\n\nexport const DependabotDependencySubmissionSchema = z.object({\n version: z.number(),\n sha: z.string(),\n ref: z.string(),\n job: z.object({\n correlator: z.string(),\n id: z.string(),\n }),\n detector: z.object({\n name: z.string(),\n version: z.string(),\n url: z.string(),\n }),\n manifests: z.object({\n name: z.string().nullish(),\n file: z.object({ source_location: z.string() }).nullish(),\n metadata: z.object({ ecosystem: DependabotPackageManagerSchema }).nullish(),\n resolved: z\n .object({\n package_url: z.string(),\n relationship: z.enum(['direct', 'indirect']),\n scope: z.enum(['runtime', 'development']),\n dependencies: DependabotDependencySchema.array(),\n })\n .nullish(),\n }),\n});\nexport type DependabotDependencySubmission = z.infer<typeof DependabotDependencySubmissionSchema>;\n\nexport const DependabotCreatePullRequestSchema = z.object({\n 'base-commit-sha': z.string(),\n dependencies: DependabotDependencySchema.array(),\n 'updated-dependency-files': DependabotDependencyFileSchema.array(),\n 'pr-title': z.string(),\n 'pr-body': z.string().nullish(),\n 'commit-message': z.string(),\n 'dependency-group': z.record(z.string(), z.any()).nullish(),\n});\nexport type DependabotCreatePullRequest = z.infer<typeof DependabotCreatePullRequestSchema>;\n\nexport const DependabotUpdatePullRequestSchema = z.object({\n 'base-commit-sha': z.string(),\n 'dependency-names': z.string().array(),\n 'updated-dependency-files': DependabotDependencyFileSchema.array(),\n 'pr-title': z.string().nullish(), // this is usually excluded when working with dependabot-cli and an empty string if the API\n 'pr-body': z.string().nullish(), // this is usually excluded when working with dependabot-cli and an empty string if the API\n 'commit-message': z.string().nullish(), // this is usually excluded when working with dependabot-cli and an empty string if the API\n 'dependency-group': z.record(z.string(), z.any()).nullish(),\n});\nexport type DependabotUpdatePullRequest = z.infer<typeof DependabotUpdatePullRequestSchema>;\n\nexport const DependabotClosePullRequestReasonEnum = z.enum([\n 'dependencies_changed',\n 'dependency_group_empty',\n 'dependency_removed',\n 'up_to_date',\n 'update_no_longer_possible',\n]);\nexport type DependabotClosePullRequestReason = z.infer<typeof DependabotClosePullRequestReasonEnum>;\nexport const DependabotClosePullRequestSchema = z.object({\n 'dependency-names': z.string().array(),\n reason: DependabotClosePullRequestReasonEnum.nullish(),\n});\nexport type DependabotClosePullRequest = z.infer<typeof DependabotClosePullRequestSchema>;\n\nexport const DependabotMarkAsProcessedSchema = z.object({\n 'base-commit-sha': z.string().nullish(),\n});\nexport type DependabotMarkAsProcessed = z.infer<typeof DependabotMarkAsProcessedSchema>;\n\nexport const DependabotRecordUpdateJobErrorSchema = z.object({\n 'error-type': z.string(),\n 'error-details': z.record(z.string(), z.any()).nullish(),\n});\nexport type DependabotRecordUpdateJobError = z.infer<typeof DependabotRecordUpdateJobErrorSchema>;\n\nexport const DependabotRecordUpdateJobWarningSchema = z.object({\n 'warn-type': z.string(),\n 'warn-title': z.string(),\n 'warn-description': z.string(),\n});\nexport type DependabotRecordUpdateJobWarning = z.infer<typeof DependabotRecordUpdateJobWarningSchema>;\n\nexport const DependabotRecordUpdateJobUnknownErrorSchema = z.object({\n 'error-type': z.string(),\n 'error-details': z.record(z.string(), z.any()).nullish(),\n});\nexport type DependabotRecordUpdateJobUnknownError = z.infer<typeof DependabotRecordUpdateJobUnknownErrorSchema>;\n\nexport const DependabotRecordEcosystemVersionsSchema = z.object({\n ecosystem_versions: z.record(z.string(), z.any()).nullish(),\n});\nexport type DependabotRecordEcosystemVersions = z.infer<typeof DependabotRecordEcosystemVersionsSchema>;\n\nexport const DependabotEcosystemVersionManagerSchema = z.object({\n name: z.string(),\n version: z.string(),\n raw_version: z.string(),\n requirement: z.record(z.string(), z.any()).nullish(),\n});\nexport type DependabotEcosystemVersionManager = z.infer<typeof DependabotEcosystemVersionManagerSchema>;\n\nexport const DependabotEcosystemMetaSchema = z.object({\n name: z.string(),\n package_manager: DependabotEcosystemVersionManagerSchema.nullish(),\n language: DependabotEcosystemVersionManagerSchema.nullish(),\n version: DependabotEcosystemVersionManagerSchema.nullish(),\n});\nexport type DependabotEcosystemMeta = z.infer<typeof DependabotEcosystemMetaSchema>;\n\nexport const DependabotRecordEcosystemMetaSchema = z.object({\n ecosystem: DependabotEcosystemMetaSchema,\n});\nexport type DependabotRecordEcosystemMeta = z.infer<typeof DependabotRecordEcosystemMetaSchema>;\n\nexport const DependabotRecordCooldownMetaSchema = z.object({\n cooldown: z.object({\n ecosystem_name: DependabotPackageManagerSchema,\n config: z.object({\n default_days: z.number(),\n semver_major_days: z.number(),\n semver_minor_days: z.number(),\n semver_patch_days: z.number(),\n }),\n }),\n});\nexport type DependabotRecordCooldownMeta = z.infer<typeof DependabotRecordCooldownMetaSchema>;\n\nexport const DependabotIncrementMetricSchema = z.object({\n metric: z.string(),\n tags: z.record(z.string(), z.any()).nullish(),\n});\nexport type DependabotIncrementMetric = z.infer<typeof DependabotIncrementMetricSchema>;\n\nexport const DependabotMetricSchema = z.object({\n metric: z.string(),\n type: z.enum(['increment', 'gauge', 'distribution', 'histogram']),\n value: z.number().nullish(),\n values: z.number().array().nullish(),\n tags: z.record(z.string(), z.string()).nullish(),\n});\nexport type DependabotMetric = z.infer<typeof DependabotMetricSchema>;\n","import { zValidator } from '@hono/zod-validator';\nimport { Hono } from 'hono';\nimport { type ZodType, z } from 'zod';\nimport { logger } from '@/logger';\nimport type { DependabotCredential, DependabotJobConfig } from './job';\nimport {\n DependabotClosePullRequestSchema,\n DependabotCreatePullRequestSchema,\n DependabotDependencySubmissionSchema,\n DependabotIncrementMetricSchema,\n DependabotMarkAsProcessedSchema,\n DependabotMetricSchema,\n DependabotRecordCooldownMetaSchema,\n DependabotRecordEcosystemMetaSchema,\n DependabotRecordEcosystemVersionsSchema,\n DependabotRecordUpdateJobErrorSchema,\n DependabotRecordUpdateJobUnknownErrorSchema,\n DependabotRecordUpdateJobWarningSchema,\n DependabotUpdateDependencyListSchema,\n DependabotUpdatePullRequestSchema,\n} from './update';\n\nexport const DependabotRequestTypeSchema = z.enum([\n 'create_pull_request',\n 'update_pull_request',\n 'close_pull_request',\n 'record_update_job_error',\n 'record_update_job_warning',\n 'record_update_job_unknown_error',\n 'mark_as_processed',\n 'update_dependency_list',\n 'create_dependency_submission',\n 'record_ecosystem_versions',\n 'increment_metric',\n 'record_ecosystem_meta',\n 'record_cooldown_meta',\n 'record_metrics', // from the runner\n]);\nexport type DependabotRequestType = z.infer<typeof DependabotRequestTypeSchema>;\n\nexport const DependabotRequestSchema = z.discriminatedUnion('type', [\n z.object({ type: z.literal('create_pull_request'), data: DependabotCreatePullRequestSchema }),\n z.object({ type: z.literal('update_pull_request'), data: DependabotUpdatePullRequestSchema }),\n z.object({ type: z.literal('close_pull_request'), data: DependabotClosePullRequestSchema }),\n z.object({ type: z.literal('record_update_job_error'), data: DependabotRecordUpdateJobErrorSchema }),\n z.object({ type: z.literal('record_update_job_warning'), data: DependabotRecordUpdateJobWarningSchema }),\n z.object({ type: z.literal('record_update_job_unknown_error'), data: DependabotRecordUpdateJobUnknownErrorSchema }),\n z.object({ type: z.literal('mark_as_processed'), data: DependabotMarkAsProcessedSchema }),\n z.object({ type: z.literal('update_dependency_list'), data: DependabotUpdateDependencyListSchema }),\n z.object({ type: z.literal('create_dependency_submission'), data: DependabotDependencySubmissionSchema }),\n z.object({ type: z.literal('record_ecosystem_versions'), data: DependabotRecordEcosystemVersionsSchema }),\n z.object({ type: z.literal('record_ecosystem_meta'), data: DependabotRecordEcosystemMetaSchema.array() }),\n z.object({ type: z.literal('record_cooldown_meta'), data: DependabotRecordCooldownMetaSchema.array() }),\n z.object({ type: z.literal('increment_metric'), data: DependabotIncrementMetricSchema }),\n z.object({ type: z.literal('record_metrics'), data: DependabotMetricSchema.array() }), // from the runner\n]);\nexport type DependabotRequest = z.infer<typeof DependabotRequestSchema>;\n\nexport type DependabotTokenType = 'job' | 'credentials';\n\n/**\n * Function type for authenticating requests.\n * @param type - The type of authentication ('job' or 'credentials').\n * @param id - The ID of the dependabot job.\n * @param value - The authentication value (e.g., API key).\n * @returns A promise that resolves to a boolean indicating whether the authentication was successful.\n */\ntype AuthenticatorFunc = (type: DependabotTokenType, id: string, value: string) => Promise<boolean>;\n\n/**\n * Handler function for processing dependabot requests.\n * @param id - The ID of the dependabot job.\n * @param request - The dependabot request to handle.\n * @returns A promise that resolves to the result of handling the request.\n */\ntype HandlerFunc = (id: string, request: DependabotRequest) => Promise<boolean>;\n\n/**\n * Function for inspecting raw dependabot requests.\n * @param id - The ID of the dependabot job.\n * @param type - The type of dependabot request.\n * @param raw - The raw JSON data of the request.\n * @returns A promise that resolves when the operation is complete.\n */\ntype InspectRequestFunc = (id: string, type: DependabotRequestType, raw: unknown) => Promise<void>;\n\n/**\n * Function for getting a dependabot job config by ID.\n * @param id - The ID of the dependabot job.\n * @returns A promise that resolves to the dependabot job config, or undefined if not found.\n */\ntype GetJobFunc = (id: string) => Promise<DependabotJobConfig | undefined>;\n\n/**\n * Function for getting dependabot credentials by job ID.\n * @param id - The ID of the dependabot job.\n * @returns A promise that resolves to an array of dependabot credentials, or undefined if not found.\n */\ntype GetCredentialsFunc = (id: string) => Promise<DependabotCredential[] | undefined>;\n\nexport type CreateApiServerAppOptions = {\n /**\n * Base path for the endpoints.\n * @default `/api/update_jobs`\n */\n basePath?: string;\n\n /** Handler function for authenticating requests. */\n authenticate: AuthenticatorFunc;\n\n /** Function for getting a dependabot job by ID. */\n getJob: GetJobFunc;\n\n /** Function for getting dependabot credentials by job ID. */\n getCredentials: GetCredentialsFunc;\n\n /**\n * Optional function for inspecting raw dependabot requests.\n * Should only be used for troubleshooting.\n * */\n inspect?: InspectRequestFunc;\n\n /** Handler function for processing the operations. */\n handle: HandlerFunc;\n};\n\n/**\n * Creates an API server application for handling dependabot update jobs.\n * The endpoints in the server application have paths in the format: `/api/update_jobs/:id/{operation}`,\n * where `:id` is the job ID and `{operation}` is one of the defined operations e.g. `create_pull_request`.\n *\n * You should set the job endpoint URL in the job container to\n * `http://<host>:<port>/api/update_jobs/:id` where `<host>` and `<port>` are the host and port\n *\n * These endpoints are protected using the provided API key.\n * @param params - The parameters for creating the API server application.\n * @returns The created API server application.\n */\nexport function createApiServerApp({\n basePath = `/api/update_jobs`,\n authenticate,\n getJob,\n getCredentials,\n inspect,\n handle,\n}: CreateApiServerAppOptions): Hono {\n // Setup app with base path and middleware\n const app = new Hono().basePath(basePath);\n\n // Handle endpoints:\n // - POST request to /create_pull_request\n // - POST request to /update_pull_request\n // - POST request to /close_pull_request\n // - POST request to /record_update_job_error\n // - POST request to /record_update_job_warning\n // - POST request to /record_update_job_unknown_error\n // - PATCH request to /mark_as_processed\n // - POST request to /update_dependency_list\n // - POST request to /create_dependency_submission\n // - POST request to /record_ecosystem_versions\n // - POST request to /record_ecosystem_meta\n // - POST request to /increment_metric\n\n function operation<T extends ZodType>(type: DependabotRequestType, schema: T, method?: string) {\n app.on(\n method || 'post',\n `/:id/${type}`,\n zValidator('param', z.object({ id: z.string() })),\n async (context, next) => {\n /**\n * Do not authenticate in scenarios where the server is not using HTTPS because the\n * dependabot proxy will not send the job token over HTTP, yet trying to get HTTPS to work\n * with localhost (self-signed certs) against docker (host.docker.internal) is complicated.\n */\n const url = new URL(context.req.url);\n const isHTTPS = url.protocol === 'https:';\n const { id } = context.req.valid('param');\n if (isHTTPS) {\n const value = context.req.header('Authorization');\n if (!value) return context.body(null, 401);\n const valid = await authenticate('job', id, value);\n if (!valid) return context.body(null, 403);\n } else {\n logger.trace(`Skipping authentication because it is not secure ${context.req.url}`);\n }\n\n // if inspection is provided, call it with the raw request data\n if (inspect) {\n await inspect(id, type, await context.req.json());\n }\n\n await next();\n },\n zValidator('json', z.object({ data: schema })),\n async (context) => {\n const { id } = context.req.valid('param');\n const { data } = context.req.valid('json') as { data: z.infer<typeof schema> };\n // biome-ignore lint/suspicious/noExplicitAny: generic\n const success: boolean = await handle(id, { type, data: data as any });\n return context.body(null, success ? 204 : 400);\n },\n );\n }\n\n operation('create_pull_request', DependabotCreatePullRequestSchema);\n operation('update_pull_request', DependabotUpdatePullRequestSchema);\n operation('close_pull_request', DependabotClosePullRequestSchema);\n operation('record_update_job_error', DependabotRecordUpdateJobErrorSchema);\n operation('record_update_job_warning', DependabotRecordUpdateJobWarningSchema);\n operation('record_update_job_unknown_error', DependabotRecordUpdateJobUnknownErrorSchema);\n operation('mark_as_processed', DependabotMarkAsProcessedSchema, 'patch');\n operation('update_dependency_list', DependabotUpdateDependencyListSchema);\n operation('create_dependency_submission', DependabotDependencySubmissionSchema);\n operation('record_ecosystem_versions', DependabotRecordEcosystemVersionsSchema);\n operation('record_ecosystem_meta', DependabotRecordEcosystemMetaSchema.array());\n operation('record_cooldown_meta', DependabotRecordCooldownMetaSchema.array());\n operation('increment_metric', DependabotIncrementMetricSchema);\n operation('record_metrics', DependabotMetricSchema.array()); // from the runner\n\n // Handle endpoints:\n // - GET request to /details\n // - GET request to /credentials\n app.on(\n 'get',\n '/:id/details',\n zValidator('param', z.object({ id: z.string() })),\n async (context, next) => {\n const { id } = context.req.valid('param');\n const value = context.req.header('Authorization');\n if (!value) return context.body(null, 401);\n const valid = await authenticate('job', id, value);\n if (!valid) return context.body(null, 403);\n await next();\n },\n async (context) => {\n const { id } = context.req.valid('param');\n const job = await getJob(id);\n if (!job) return context.body(null, 204);\n return context.json(job);\n },\n );\n app.on(\n 'get',\n '/:id/credentials',\n zValidator('param', z.object({ id: z.string() })),\n async (context, next) => {\n const { id } = context.req.valid('param');\n const value = context.req.header('Authorization');\n if (!value) return context.body(null, 401);\n const valid = await authenticate('credentials', id, value);\n if (!valid) return context.body(null, 403);\n await next();\n },\n async (context) => {\n const { id } = context.req.valid('param');\n const credentials = await getCredentials(id);\n if (!credentials) return context.body(null, 204);\n return context.json(credentials);\n },\n );\n\n return app;\n}\n"],"mappings":"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"}
|
package/dist/http/index.d.mts
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { ZodType } from "zod";
|
|
2
|
-
|
|
3
|
-
//#region src/http/headers.d.ts
|
|
4
|
-
declare const HEADER_NAME_CONTENT_DISPOSITION = "Content-Disposition";
|
|
5
|
-
declare const HEADER_NAME_CONTENT_TYPE = "Content-Type";
|
|
6
|
-
declare const HEADER_NAME_ACCEPT = "Accept";
|
|
7
|
-
declare const HEADER_NAME_USER_AGENT = "User-Agent";
|
|
8
|
-
declare const HEADER_NAME_AUTHORIZATION = "Authorization";
|
|
9
|
-
//#endregion
|
|
10
|
-
//#region src/http/multipart.d.ts
|
|
11
|
-
declare class MultipartFormDataBody {
|
|
12
|
-
private type;
|
|
13
|
-
private boundary;
|
|
14
|
-
private parts;
|
|
15
|
-
encode(): Promise<Buffer>;
|
|
16
|
-
getBoundary(): string;
|
|
17
|
-
getContentType(): string;
|
|
18
|
-
add(name: string, value: string): void;
|
|
19
|
-
addFile(name: string, file: File): void;
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region src/http/problem.d.ts
|
|
23
|
-
interface ProblemDetails {
|
|
24
|
-
type?: string;
|
|
25
|
-
/** The name/title of the error.*/
|
|
26
|
-
title: string;
|
|
27
|
-
/** A brief explanation/definition into the nature of the error. */
|
|
28
|
-
detail?: string | null;
|
|
29
|
-
/** Any additional error arguments passed to the client. */
|
|
30
|
-
extras?: unknown;
|
|
31
|
-
/** The HTTP status code */
|
|
32
|
-
status?: number;
|
|
33
|
-
statusText?: string;
|
|
34
|
-
errors?: Record<string, string[] | undefined>;
|
|
35
|
-
traceId?: string;
|
|
36
|
-
}
|
|
37
|
-
//#endregion
|
|
38
|
-
//#region src/http/inner.d.ts
|
|
39
|
-
type CreateInnerApiClientOptions = {
|
|
40
|
-
/**
|
|
41
|
-
* The base URL to use for the API.
|
|
42
|
-
* @example 'https://www.paklo.app/api'
|
|
43
|
-
*/
|
|
44
|
-
baseUrl: string;
|
|
45
|
-
/** The token to use for authentication. This can be a JWT or specialized key. */
|
|
46
|
-
token?: string;
|
|
47
|
-
};
|
|
48
|
-
type RequestOptions = {
|
|
49
|
-
/**
|
|
50
|
-
* Value for the `User-Agent` header.
|
|
51
|
-
* This prepends the default value (e.g. `paklo/ab26320`)
|
|
52
|
-
* which is important when we need to propagate the browser information to the server.
|
|
53
|
-
*/
|
|
54
|
-
userAgent?: string;
|
|
55
|
-
};
|
|
56
|
-
type ResourceResponse<T = Record<string, unknown>> = {
|
|
57
|
-
/** The headers of the response. */
|
|
58
|
-
headers: Headers;
|
|
59
|
-
/** Whether the request was successful. */
|
|
60
|
-
successful: boolean;
|
|
61
|
-
/** The status code of the response. */
|
|
62
|
-
status: number;
|
|
63
|
-
/** The status text of the response. */
|
|
64
|
-
statusText: string;
|
|
65
|
-
/** The data of the response. */
|
|
66
|
-
data?: T;
|
|
67
|
-
/** The error of the response. */
|
|
68
|
-
error?: ProblemDetails;
|
|
69
|
-
};
|
|
70
|
-
type InnerRequestOptions<T> = RequestOptions & {
|
|
71
|
-
/**
|
|
72
|
-
* The base URL to use for the request.
|
|
73
|
-
* This overrides the default base URL.
|
|
74
|
-
* @example 'https://www.paklo.app/api'
|
|
75
|
-
*/
|
|
76
|
-
baseUrl?: string;
|
|
77
|
-
/** Additional headers to use for the request. */
|
|
78
|
-
headers?: HeadersInit;
|
|
79
|
-
/** The payload to use for the request. */
|
|
80
|
-
payload?: Record<string, unknown> | MultipartFormDataBody | ReadableStream | XMLHttpRequestBodyInit;
|
|
81
|
-
/** The schema to use when parsing the response. */
|
|
82
|
-
schema?: ZodType<T>;
|
|
83
|
-
};
|
|
84
|
-
type InnerRequestOptionsComplete<T> = InnerRequestOptions<T> & {
|
|
85
|
-
/** The method to use for the request. */
|
|
86
|
-
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
87
|
-
/** The URL to use for the request. */
|
|
88
|
-
url: string;
|
|
89
|
-
};
|
|
90
|
-
declare class InnerApiClient {
|
|
91
|
-
private readonly baseUrl;
|
|
92
|
-
private readonly headers;
|
|
93
|
-
private readonly token?;
|
|
94
|
-
/**
|
|
95
|
-
* Create a new API client.
|
|
96
|
-
* @param options The options to use for the client.
|
|
97
|
-
*/
|
|
98
|
-
constructor({
|
|
99
|
-
baseUrl,
|
|
100
|
-
token
|
|
101
|
-
}: CreateInnerApiClientOptions);
|
|
102
|
-
get<T>(url: string, options?: InnerRequestOptions<T>): Promise<ResourceResponse<T>>;
|
|
103
|
-
post<T>(url: string, options?: InnerRequestOptions<T>): Promise<ResourceResponse<T>>;
|
|
104
|
-
put<T>(url: string, options?: InnerRequestOptions<T>): Promise<ResourceResponse<T>>;
|
|
105
|
-
patch<T>(url: string, options?: InnerRequestOptions<T>): Promise<ResourceResponse<T>>;
|
|
106
|
-
delete<T>(url: string, options?: InnerRequestOptions<T>): Promise<ResourceResponse<T>>;
|
|
107
|
-
request<T>(options: InnerRequestOptionsComplete<T>): Promise<ResourceResponse<T>>;
|
|
108
|
-
private makeUrl;
|
|
109
|
-
}
|
|
110
|
-
/** Http request error */
|
|
111
|
-
declare class HttpRequestError extends Error {
|
|
112
|
-
code: number;
|
|
113
|
-
constructor(message: string, code: number);
|
|
114
|
-
}
|
|
115
|
-
declare function isErrorTemporaryFailure(e?: {
|
|
116
|
-
code?: string | number;
|
|
117
|
-
message?: string;
|
|
118
|
-
} | null): boolean;
|
|
119
|
-
//#endregion
|
|
120
|
-
export { CreateInnerApiClientOptions, HEADER_NAME_ACCEPT, HEADER_NAME_AUTHORIZATION, HEADER_NAME_CONTENT_DISPOSITION, HEADER_NAME_CONTENT_TYPE, HEADER_NAME_USER_AGENT, HttpRequestError, InnerApiClient, InnerRequestOptions, ProblemDetails, RequestOptions, ResourceResponse, isErrorTemporaryFailure };
|
|
121
|
-
//# sourceMappingURL=index.d.mts.map
|
package/dist/http/index.mjs
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { a as HEADER_NAME_AUTHORIZATION, c as HEADER_NAME_USER_AGENT, i as HEADER_NAME_ACCEPT, n as InnerApiClient, o as HEADER_NAME_CONTENT_DISPOSITION, r as isErrorTemporaryFailure, s as HEADER_NAME_CONTENT_TYPE, t as HttpRequestError } from "../http-D2wwAKQ-.mjs";
|
|
2
|
-
|
|
3
|
-
export { HEADER_NAME_ACCEPT, HEADER_NAME_AUTHORIZATION, HEADER_NAME_CONTENT_DISPOSITION, HEADER_NAME_CONTENT_TYPE, HEADER_NAME_USER_AGENT, HttpRequestError, InnerApiClient, isErrorTemporaryFailure };
|
package/dist/http-D2wwAKQ-.mjs
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
//#region src/http/headers.ts
|
|
2
|
-
const HEADER_NAME_CONTENT_DISPOSITION = "Content-Disposition";
|
|
3
|
-
const HEADER_NAME_CONTENT_TYPE = "Content-Type";
|
|
4
|
-
const HEADER_NAME_ACCEPT = "Accept";
|
|
5
|
-
const HEADER_NAME_USER_AGENT = "User-Agent";
|
|
6
|
-
const HEADER_NAME_AUTHORIZATION = "Authorization";
|
|
7
|
-
|
|
8
|
-
//#endregion
|
|
9
|
-
//#region src/http/multipart.ts
|
|
10
|
-
var MultipartFormDataBody = class {
|
|
11
|
-
type = "multipart/form-data";
|
|
12
|
-
boundary = `${Math.random().toString(36).substring(2)}`;
|
|
13
|
-
parts = [];
|
|
14
|
-
async encode() {
|
|
15
|
-
if (this.parts.length === 0) throw new Error("MultipartFormDataBody must have at least one part");
|
|
16
|
-
const data = [];
|
|
17
|
-
for (const part of this.parts) {
|
|
18
|
-
data.push(`--${this.boundary}\r\n`);
|
|
19
|
-
for (const [key, value] of Object.entries(part.headers)) data.push(`${key}: ${value}\r\n`);
|
|
20
|
-
data.push("\r\n");
|
|
21
|
-
data.push(part.body);
|
|
22
|
-
data.push("\r\n");
|
|
23
|
-
}
|
|
24
|
-
data.push(`--${this.boundary}--\r\n`);
|
|
25
|
-
const list = [];
|
|
26
|
-
for (const item of data) if (item instanceof File) list.push(Buffer.from(await item.arrayBuffer()));
|
|
27
|
-
else if (typeof item === "string") list.push(Buffer.from(item, "utf8"));
|
|
28
|
-
else list.push(item);
|
|
29
|
-
return Buffer.concat(list);
|
|
30
|
-
}
|
|
31
|
-
getBoundary() {
|
|
32
|
-
return this.boundary;
|
|
33
|
-
}
|
|
34
|
-
getContentType() {
|
|
35
|
-
return `${this.type}; boundary=${this.boundary}`;
|
|
36
|
-
}
|
|
37
|
-
add(name, value) {
|
|
38
|
-
const part = createPart(name, value);
|
|
39
|
-
this.parts.push(part);
|
|
40
|
-
}
|
|
41
|
-
addFile(name, file) {
|
|
42
|
-
const part = createPart(name, file, file.name, file.type);
|
|
43
|
-
this.parts.push(part);
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
function createPart(name, body, filename, contentType) {
|
|
47
|
-
const headers = {};
|
|
48
|
-
headers[HEADER_NAME_CONTENT_DISPOSITION] = `form-data; name="${name}"${filename ? `; filename="${filename}"` : ""}`;
|
|
49
|
-
if (contentType) headers[HEADER_NAME_CONTENT_TYPE] = contentType;
|
|
50
|
-
return {
|
|
51
|
-
name,
|
|
52
|
-
headers,
|
|
53
|
-
body
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
//#endregion
|
|
58
|
-
//#region src/http/inner.ts
|
|
59
|
-
var InnerApiClient = class {
|
|
60
|
-
baseUrl;
|
|
61
|
-
headers;
|
|
62
|
-
token;
|
|
63
|
-
/**
|
|
64
|
-
* Create a new API client.
|
|
65
|
-
* @param options The options to use for the client.
|
|
66
|
-
*/
|
|
67
|
-
constructor({ baseUrl, token }) {
|
|
68
|
-
this.baseUrl = baseUrl;
|
|
69
|
-
this.headers = new Headers({ [HEADER_NAME_ACCEPT]: "application/json" });
|
|
70
|
-
this.token = token;
|
|
71
|
-
}
|
|
72
|
-
async get(url, options) {
|
|
73
|
-
return this.request({
|
|
74
|
-
url: this.makeUrl(url, options),
|
|
75
|
-
method: "GET",
|
|
76
|
-
...options
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
async post(url, options) {
|
|
80
|
-
return this.request({
|
|
81
|
-
method: "POST",
|
|
82
|
-
url: this.makeUrl(url, options),
|
|
83
|
-
...options
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
async put(url, options) {
|
|
87
|
-
return this.request({
|
|
88
|
-
method: "PUT",
|
|
89
|
-
url: this.makeUrl(url, options),
|
|
90
|
-
...options
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
async patch(url, options) {
|
|
94
|
-
return this.request({
|
|
95
|
-
method: "PATCH",
|
|
96
|
-
url: this.makeUrl(url, options),
|
|
97
|
-
...options
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
async delete(url, options) {
|
|
101
|
-
return this.request({
|
|
102
|
-
method: "DELETE",
|
|
103
|
-
url: this.makeUrl(url, options),
|
|
104
|
-
...options
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
async request(options) {
|
|
108
|
-
const { method, url, payload, userAgent, headers: additionalHeaders, schema } = options;
|
|
109
|
-
const headers = new Headers(this.headers);
|
|
110
|
-
if (userAgent) headers.set(HEADER_NAME_USER_AGENT, userAgent);
|
|
111
|
-
if (this.token) headers.set(HEADER_NAME_AUTHORIZATION, `Bearer ${this.token}`);
|
|
112
|
-
if (additionalHeaders) if (additionalHeaders instanceof Headers) additionalHeaders.forEach((value, key) => headers.set(key, value));
|
|
113
|
-
else if (Array.isArray(additionalHeaders)) additionalHeaders.forEach(([key, value]) => headers.set(key, value));
|
|
114
|
-
else Object.entries(additionalHeaders).forEach(([key, value]) => headers.set(key, value));
|
|
115
|
-
let body;
|
|
116
|
-
if (skipSerialization(payload)) body = payload;
|
|
117
|
-
else if (payload instanceof MultipartFormDataBody) {
|
|
118
|
-
body = new Uint8Array(await payload.encode());
|
|
119
|
-
headers.set(HEADER_NAME_CONTENT_TYPE, payload.getContentType());
|
|
120
|
-
} else {
|
|
121
|
-
body = JSON.stringify(payload);
|
|
122
|
-
headers.set(HEADER_NAME_CONTENT_TYPE, "application/json");
|
|
123
|
-
}
|
|
124
|
-
try {
|
|
125
|
-
const response = await fetch(url, {
|
|
126
|
-
method,
|
|
127
|
-
headers,
|
|
128
|
-
body
|
|
129
|
-
});
|
|
130
|
-
const { ok: successful, status, statusText } = response;
|
|
131
|
-
if (!successful) try {
|
|
132
|
-
const rawError = await response.text();
|
|
133
|
-
return {
|
|
134
|
-
headers: response.headers,
|
|
135
|
-
successful,
|
|
136
|
-
status,
|
|
137
|
-
statusText,
|
|
138
|
-
error: JSON.parse(rawError)
|
|
139
|
-
};
|
|
140
|
-
} catch (err) {
|
|
141
|
-
if (err instanceof SyntaxError) return {
|
|
142
|
-
headers: response.headers,
|
|
143
|
-
successful,
|
|
144
|
-
status,
|
|
145
|
-
statusText,
|
|
146
|
-
error: {
|
|
147
|
-
title: "Unknown error",
|
|
148
|
-
status,
|
|
149
|
-
statusText: response.statusText
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
const error = {
|
|
153
|
-
title: (err instanceof Error ? err.message : void 0) ?? "Unknown error",
|
|
154
|
-
status: response.status,
|
|
155
|
-
statusText: response.statusText
|
|
156
|
-
};
|
|
157
|
-
return {
|
|
158
|
-
headers: response.headers,
|
|
159
|
-
successful,
|
|
160
|
-
status,
|
|
161
|
-
statusText,
|
|
162
|
-
error
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
const contentLength = response.headers.get("content-length");
|
|
166
|
-
let data = contentLength && contentLength !== "0" ? await response.json() : void 0;
|
|
167
|
-
if (data && schema) {
|
|
168
|
-
const result = await schema.safeParseAsync(data);
|
|
169
|
-
if (!result.success) return {
|
|
170
|
-
headers: response.headers,
|
|
171
|
-
successful: false,
|
|
172
|
-
status,
|
|
173
|
-
statusText,
|
|
174
|
-
data,
|
|
175
|
-
error: {
|
|
176
|
-
title: "application_error",
|
|
177
|
-
detail: "Schema validation error",
|
|
178
|
-
errors: result.error.flatten().fieldErrors,
|
|
179
|
-
status: response.status,
|
|
180
|
-
statusText: response.statusText
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
data = result.data;
|
|
184
|
-
}
|
|
185
|
-
return {
|
|
186
|
-
headers: response.headers,
|
|
187
|
-
data,
|
|
188
|
-
successful,
|
|
189
|
-
status,
|
|
190
|
-
statusText
|
|
191
|
-
};
|
|
192
|
-
} catch (err) {
|
|
193
|
-
return {
|
|
194
|
-
headers: new Headers(),
|
|
195
|
-
successful: false,
|
|
196
|
-
status: -1,
|
|
197
|
-
statusText: "Application Error",
|
|
198
|
-
error: {
|
|
199
|
-
title: "application_error",
|
|
200
|
-
detail: `Unable to fetch data. The request could not be resolved. ${err}`
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
makeUrl(url, options) {
|
|
206
|
-
if (url.startsWith("http://") || url.startsWith("https://")) return url;
|
|
207
|
-
return `${options?.baseUrl ?? this.baseUrl}${url}`;
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
/**
|
|
211
|
-
* Whether to skip serialization of the payload.
|
|
212
|
-
* @param payload The payload to check.
|
|
213
|
-
* @returns true if the payload should not be serialized; otherwise, false.
|
|
214
|
-
*/
|
|
215
|
-
function skipSerialization(payload) {
|
|
216
|
-
return payload instanceof FormData || payload instanceof URLSearchParams || payload instanceof ReadableStream || payload instanceof Blob || payload instanceof ArrayBuffer || payload instanceof Buffer || typeof payload === "string" || !payload;
|
|
217
|
-
}
|
|
218
|
-
/** Http request error */
|
|
219
|
-
var HttpRequestError = class extends Error {
|
|
220
|
-
constructor(message, code) {
|
|
221
|
-
super(message);
|
|
222
|
-
this.code = code;
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
function isErrorTemporaryFailure(e) {
|
|
226
|
-
if (e instanceof HttpRequestError) switch (e.code) {
|
|
227
|
-
case 502: return true;
|
|
228
|
-
case 503: return true;
|
|
229
|
-
case 504: return true;
|
|
230
|
-
default: return false;
|
|
231
|
-
}
|
|
232
|
-
else if (e?.code) switch (e.code) {
|
|
233
|
-
case "ETIMEDOUT": return true;
|
|
234
|
-
default: return false;
|
|
235
|
-
}
|
|
236
|
-
else return false;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
//#endregion
|
|
240
|
-
export { HEADER_NAME_AUTHORIZATION as a, HEADER_NAME_USER_AGENT as c, HEADER_NAME_ACCEPT as i, InnerApiClient as n, HEADER_NAME_CONTENT_DISPOSITION as o, isErrorTemporaryFailure as r, HEADER_NAME_CONTENT_TYPE as s, HttpRequestError as t };
|
|
241
|
-
//# sourceMappingURL=http-D2wwAKQ-.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http-D2wwAKQ-.mjs","names":["data: Array<MultipartFormDataBodyPart['body']>","list: Buffer[]","headers: Record<string, string>","body: BodyInit | undefined","error: ProblemDetails","code: number"],"sources":["../src/http/headers.ts","../src/http/multipart.ts","../src/http/inner.ts"],"sourcesContent":["export const HEADER_NAME_CONTENT_DISPOSITION = 'Content-Disposition';\nexport const HEADER_NAME_CONTENT_TYPE = 'Content-Type';\nexport const HEADER_NAME_ACCEPT = 'Accept';\nexport const HEADER_NAME_USER_AGENT = 'User-Agent';\nexport const HEADER_NAME_AUTHORIZATION = 'Authorization';\n","import { HEADER_NAME_CONTENT_DISPOSITION, HEADER_NAME_CONTENT_TYPE } from './headers';\n\nexport class MultipartFormDataBody {\n private type = 'multipart/form-data';\n private boundary: string = `${Math.random().toString(36).substring(2)}`;\n private parts: Array<MultipartFormDataBodyPart> = [];\n\n public async encode(): Promise<Buffer> {\n if (this.parts.length === 0) {\n throw new Error('MultipartFormDataBody must have at least one part');\n }\n\n const data: Array<MultipartFormDataBodyPart['body']> = [];\n\n for (const part of this.parts) {\n // write boundary\n data.push(`--${this.boundary}\\r\\n`);\n\n // write headers\n for (const [key, value] of Object.entries(part.headers)) {\n data.push(`${key}: ${value}\\r\\n`);\n }\n data.push('\\r\\n');\n\n // write body\n data.push(part.body);\n data.push('\\r\\n');\n }\n\n data.push(`--${this.boundary}--\\r\\n`);\n\n const list: Buffer[] = [];\n for (const item of data) {\n if (item instanceof File) list.push(Buffer.from(await item.arrayBuffer()));\n else if (typeof item === 'string') list.push(Buffer.from(item, 'utf8'));\n else list.push(item);\n }\n return Buffer.concat(list);\n }\n\n public getBoundary(): string {\n return this.boundary;\n }\n\n public getContentType(): string {\n return `${this.type}; boundary=${this.boundary}`;\n }\n\n public add(name: string, value: string) {\n const part = createPart(name, value);\n this.parts.push(part);\n }\n\n public addFile(name: string, file: File) {\n const part = createPart(name, file, file.name, file.type);\n this.parts.push(part);\n }\n}\n\ntype MultipartFormDataBodyPart = {\n name: string;\n headers: Record<string, string>;\n body: Buffer | File | string;\n};\n\nfunction createPart(\n name: string,\n body: MultipartFormDataBodyPart['body'],\n filename?: string,\n contentType?: string,\n): MultipartFormDataBodyPart {\n const headers: Record<string, string> = {};\n headers[HEADER_NAME_CONTENT_DISPOSITION] = `form-data; name=\"${name}\"${filename ? `; filename=\"${filename}\"` : ''}`;\n if (contentType) headers[HEADER_NAME_CONTENT_TYPE] = contentType;\n return { name, headers, body };\n}\n","import type { ZodType } from 'zod';\n\nimport {\n HEADER_NAME_ACCEPT,\n HEADER_NAME_AUTHORIZATION,\n HEADER_NAME_CONTENT_TYPE,\n HEADER_NAME_USER_AGENT,\n} from './headers';\nimport { MultipartFormDataBody } from './multipart';\nimport type { ProblemDetails } from './problem';\n\nexport type CreateInnerApiClientOptions = {\n /**\n * The base URL to use for the API.\n * @example 'https://www.paklo.app/api'\n */\n baseUrl: string;\n\n /** The token to use for authentication. This can be a JWT or specialized key. */\n token?: string;\n};\n\nexport type RequestOptions = {\n /**\n * Value for the `User-Agent` header.\n * This prepends the default value (e.g. `paklo/ab26320`)\n * which is important when we need to propagate the browser information to the server.\n */\n userAgent?: string;\n};\n\nexport type ResourceResponse<T = Record<string, unknown>> = {\n /** The headers of the response. */\n headers: Headers;\n\n /** Whether the request was successful. */\n successful: boolean;\n\n /** The status code of the response. */\n status: number;\n\n /** The status text of the response. */\n statusText: string;\n\n /** The data of the response. */\n data?: T;\n\n /** The error of the response. */\n error?: ProblemDetails;\n};\n\nexport type InnerRequestOptions<T> = RequestOptions & {\n /**\n * The base URL to use for the request.\n * This overrides the default base URL.\n * @example 'https://www.paklo.app/api'\n */\n baseUrl?: string;\n\n /** Additional headers to use for the request. */\n headers?: HeadersInit;\n\n /** The payload to use for the request. */\n payload?: Record<string, unknown> | MultipartFormDataBody | ReadableStream | XMLHttpRequestBodyInit;\n\n /** The schema to use when parsing the response. */\n schema?: ZodType<T>;\n};\n\ntype InnerRequestOptionsComplete<T> = InnerRequestOptions<T> & {\n /** The method to use for the request. */\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n\n /** The URL to use for the request. */\n url: string;\n};\n\nexport class InnerApiClient {\n private readonly baseUrl: string;\n private readonly headers: Headers;\n private readonly token?: string;\n\n /**\n * Create a new API client.\n * @param options The options to use for the client.\n */\n constructor({ baseUrl, token }: CreateInnerApiClientOptions) {\n this.baseUrl = baseUrl;\n\n this.headers = new Headers({\n [HEADER_NAME_ACCEPT]: 'application/json',\n });\n\n this.token = token;\n }\n\n async get<T>(url: string, options?: InnerRequestOptions<T>) {\n return this.request<T>({\n url: this.makeUrl(url, options),\n method: 'GET',\n ...options,\n });\n }\n\n async post<T>(url: string, options?: InnerRequestOptions<T>) {\n return this.request<T>({\n method: 'POST',\n url: this.makeUrl(url, options),\n ...options,\n });\n }\n\n async put<T>(url: string, options?: InnerRequestOptions<T>) {\n return this.request<T>({\n method: 'PUT',\n url: this.makeUrl(url, options),\n ...options,\n });\n }\n\n async patch<T>(url: string, options?: InnerRequestOptions<T>) {\n return this.request<T>({\n method: 'PATCH',\n url: this.makeUrl(url, options),\n ...options,\n });\n }\n\n async delete<T>(url: string, options?: InnerRequestOptions<T>) {\n return this.request<T>({\n method: 'DELETE',\n url: this.makeUrl(url, options),\n ...options,\n });\n }\n\n async request<T>(options: InnerRequestOptionsComplete<T>): Promise<ResourceResponse<T>> {\n const { method, url, payload, userAgent, headers: additionalHeaders, schema } = options;\n\n // create headers for the request\n const headers = new Headers(this.headers);\n if (userAgent) {\n headers.set(HEADER_NAME_USER_AGENT, userAgent);\n }\n\n // populate authorization header\n if (this.token) {\n headers.set(HEADER_NAME_AUTHORIZATION, `Bearer ${this.token}`);\n }\n\n // populate additional headers\n // biome-ignore-start lint/suspicious/useIterableCallbackReturn: not used\n if (additionalHeaders) {\n if (additionalHeaders instanceof Headers) {\n additionalHeaders.forEach((value, key) => headers.set(key, value as string));\n } else if (Array.isArray(additionalHeaders)) {\n additionalHeaders.forEach(([key, value]) => headers.set(key, value));\n } else {\n Object.entries(additionalHeaders).forEach(([key, value]) => headers.set(key, value as string));\n }\n }\n // biome-ignore-end lint/suspicious/useIterableCallbackReturn: not used\n\n // prepare body\n let body: BodyInit | undefined;\n if (skipSerialization(payload)) body = payload;\n else if (payload instanceof MultipartFormDataBody) {\n body = new Uint8Array(await payload.encode());\n headers.set(HEADER_NAME_CONTENT_TYPE, payload.getContentType());\n } else {\n body = JSON.stringify(payload);\n headers.set(HEADER_NAME_CONTENT_TYPE, 'application/json');\n }\n\n // make request\n try {\n const response = await fetch(url, { method, headers, body });\n const { ok: successful, status, statusText } = response;\n\n if (!successful) {\n try {\n const rawError = await response.text();\n return { headers: response.headers, successful, status, statusText, error: JSON.parse(rawError) };\n } catch (err) {\n if (err instanceof SyntaxError) {\n return {\n headers: response.headers,\n successful,\n status,\n statusText,\n error: {\n title: 'Unknown error',\n status,\n statusText: response.statusText,\n },\n };\n }\n\n const error: ProblemDetails = {\n title: (err instanceof Error ? err.message : undefined) ?? 'Unknown error',\n status: response.status,\n statusText: response.statusText,\n };\n\n return { headers: response.headers, successful, status, statusText, error };\n }\n }\n\n const contentLength = response.headers.get('content-length');\n let data = contentLength && contentLength !== '0' ? ((await response.json()) as T) : undefined;\n if (data && schema) {\n const result = await schema.safeParseAsync(data);\n if (!result.success) {\n return {\n headers: response.headers,\n successful: false,\n status,\n statusText,\n data,\n error: {\n title: 'application_error',\n detail: 'Schema validation error',\n errors: result.error.flatten().fieldErrors,\n status: response.status,\n statusText: response.statusText,\n },\n };\n }\n data = result.data;\n }\n\n return { headers: response.headers, data, successful, status, statusText };\n } catch (err) {\n return {\n headers: new Headers(),\n successful: false,\n status: -1,\n statusText: 'Application Error',\n error: {\n title: 'application_error',\n detail: `Unable to fetch data. The request could not be resolved. ${err}`,\n },\n };\n }\n }\n\n private makeUrl<T>(url: string, options?: InnerRequestOptions<T>): string {\n if (url.startsWith('http://') || url.startsWith('https://')) return url;\n const baseUrl = options?.baseUrl ?? this.baseUrl;\n return `${baseUrl}${url}`;\n }\n}\n\n/**\n * Whether to skip serialization of the payload.\n * @param payload The payload to check.\n * @returns true if the payload should not be serialized; otherwise, false.\n */\nfunction skipSerialization(\n payload: InnerRequestOptions<never>['payload'],\n): payload is FormData | URLSearchParams | ReadableStream | Blob | ArrayBuffer | string | undefined {\n return (\n payload instanceof FormData ||\n payload instanceof URLSearchParams ||\n payload instanceof ReadableStream ||\n payload instanceof Blob ||\n payload instanceof ArrayBuffer ||\n payload instanceof Buffer ||\n typeof payload === 'string' ||\n !payload\n );\n}\n\n/** Http request error */\nexport class HttpRequestError extends Error {\n constructor(\n message: string,\n public code: number,\n ) {\n super(message);\n }\n}\n\nexport function isErrorTemporaryFailure(e?: { code?: string | number; message?: string } | null): boolean {\n if (e instanceof HttpRequestError) {\n // Check for common HTTP status codes that indicate a temporary failure\n // See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status\n switch (e.code) {\n case 502:\n return true; // 502 Bad Gateway\n case 503:\n return true; // 503 Service Unavailable\n case 504:\n return true; // 504 Gateway Timeout\n default:\n return false;\n }\n } else if (e?.code) {\n // Check for Node.js system errors that indicate a temporary failure\n // See: https://nodejs.org/api/errors.html#errors_common_system_errors\n switch (e.code) {\n case 'ETIMEDOUT':\n return true; // Operation timed out\n default:\n return false;\n }\n } else {\n return false;\n }\n}\n"],"mappings":"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"}
|