feat: initial commit
This commit is contained in:
commit
a8410e6325
|
|
@ -0,0 +1,125 @@
|
||||||
|
name: register-skill-release
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
skill_slug:
|
||||||
|
description: Skill slug override (optional)
|
||||||
|
required: false
|
||||||
|
skill_subpath:
|
||||||
|
description: Skill folder path override (optional)
|
||||||
|
required: false
|
||||||
|
skill_doc_path:
|
||||||
|
description: Skill doc path override
|
||||||
|
required: false
|
||||||
|
default: SKILL.md
|
||||||
|
skill_version:
|
||||||
|
description: Version override (default tag name)
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
register-skill-version:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
API_BASE: ${{ vars.API_BASE || secrets.API_BASE }}
|
||||||
|
CLIENT_KEY: ${{ secrets.CLIENT_KEY }}
|
||||||
|
SKILL_VERSION: ${{ github.event.inputs.skill_version || github.ref_name }}
|
||||||
|
SKILL_SUBPATH: ${{ github.event.inputs.skill_subpath || vars.SKILL_SUBPATH || secrets.SKILL_SUBPATH }}
|
||||||
|
SKILL_DOC_PATH: ${{ github.event.inputs.skill_doc_path || vars.SKILL_DOC_PATH || secrets.SKILL_DOC_PATH || 'SKILL.md' }}
|
||||||
|
SKILL_SLUG: ${{ github.event.inputs.skill_slug || vars.SKILL_SLUG || secrets.SKILL_SLUG }}
|
||||||
|
RELEASE_NOTE: ${{ github.event.release.body }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Load skill doc content
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
DOC_ABS_PATH="${SKILL_SUBPATH:+$SKILL_SUBPATH/}${SKILL_DOC_PATH}"
|
||||||
|
if [ ! -f "$DOC_ABS_PATH" ]; then
|
||||||
|
if [ -f "${SKILL_SUBPATH:+$SKILL_SUBPATH/}README.md" ]; then
|
||||||
|
DOC_ABS_PATH="${SKILL_SUBPATH:+$SKILL_SUBPATH/}README.md"
|
||||||
|
export SKILL_DOC_PATH="README.md"
|
||||||
|
else
|
||||||
|
echo "skill doc not found: $DOC_ABS_PATH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq -Rs . < "$DOC_ABS_PATH" > /tmp/skill_doc.json
|
||||||
|
|
||||||
|
- name: Register version to business system
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ -z "${API_BASE:-}" ]; then
|
||||||
|
echo "API_BASE is required (global/repo var or secret)."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "${CLIENT_KEY:-}" ]; then
|
||||||
|
echo "CLIENT_KEY is required (secret)."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SKILL_BASE_DIR="${SKILL_SUBPATH:-.}"
|
||||||
|
|
||||||
|
if [ -z "${SKILL_SLUG:-}" ]; then
|
||||||
|
if [ -f "${SKILL_BASE_DIR}/package.json" ]; then
|
||||||
|
PKG_NAME=$(jq -r '.name // empty' "${SKILL_BASE_DIR}/package.json")
|
||||||
|
if [ -n "$PKG_NAME" ]; then
|
||||||
|
# Strip npm scope: @scope/skill-name -> skill-name
|
||||||
|
SKILL_SLUG="${PKG_NAME##*/}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${SKILL_SLUG:-}" ]; then
|
||||||
|
if [ -f "${SKILL_BASE_DIR}/pyproject.toml" ]; then
|
||||||
|
PYPROJECT_NAME=$(python3 -c "import sys,tomllib; p=sys.argv[1]; d=tomllib.load(open(p,'rb')); print((d.get('project',{}).get('name') or d.get('tool',{}).get('poetry',{}).get('name') or ''))" "${SKILL_BASE_DIR}/pyproject.toml" 2>/dev/null || true)
|
||||||
|
if [ -n "$PYPROJECT_NAME" ]; then
|
||||||
|
SKILL_SLUG="${PYPROJECT_NAME##*/}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${SKILL_SLUG:-}" ]; then
|
||||||
|
SKILL_SLUG="${GITHUB_REPOSITORY##*/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SESSION_RES=$(curl -sS -X POST "${API_BASE}/auth/skill-credit/session" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"clientKey\":\"${CLIENT_KEY}\"}")
|
||||||
|
ACCESS_TOKEN=$(printf '%s' "$SESSION_RES" | jq -r '.accessToken // empty')
|
||||||
|
if [ -z "$ACCESS_TOKEN" ]; then
|
||||||
|
echo "failed to exchange access token from client key"
|
||||||
|
echo "$SESSION_RES"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUNTIME_META=$(jq -nc --arg entry "${SKILL_SUBPATH:+$SKILL_SUBPATH/}scripts" '{entry_hint:$entry, provider:"forgejo"}')
|
||||||
|
|
||||||
|
cat > /tmp/register_payload.json <<JSON
|
||||||
|
{
|
||||||
|
"skill_slug": "${SKILL_SLUG}",
|
||||||
|
"version": "${SKILL_VERSION}",
|
||||||
|
"release_note": $(printf '%s' "${RELEASE_NOTE:-}" | jq -Rs .),
|
||||||
|
"source_type": "git_ci",
|
||||||
|
"repo_url": "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git",
|
||||||
|
"repo_subpath": "${SKILL_SUBPATH:-}",
|
||||||
|
"git_ref": "${GITHUB_REF_NAME}",
|
||||||
|
"commit_sha": "${GITHUB_SHA}",
|
||||||
|
"skill_doc_path": "${SKILL_DOC_PATH}",
|
||||||
|
"skill_doc_content": $(cat /tmp/skill_doc.json),
|
||||||
|
"runtime_meta": ${RUNTIME_META}
|
||||||
|
}
|
||||||
|
JSON
|
||||||
|
|
||||||
|
curl -sS -X POST "${API_BASE}/ecom/skills/register-by-slug" \
|
||||||
|
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d @/tmp/register_payload.json
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
.env.local
|
||||||
|
*.skill
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
# Email Content Compose
|
||||||
|
|
||||||
|
All-in-one skill: fetch leads, compose personalized outreach emails, export as EML and upload to R2.
|
||||||
|
|
||||||
|
## IMPORTANT — Execution Rules
|
||||||
|
|
||||||
|
- This skill uses **Bun + TypeScript**. Do NOT create Python scripts.
|
||||||
|
- Do NOT overwrite existing files in this skill directory.
|
||||||
|
- Use the existing CLI scripts below. Do NOT write your own upload/compose logic.
|
||||||
|
|
||||||
|
## Phases
|
||||||
|
|
||||||
|
### 1. Fetch (scripts/fetch.ts)
|
||||||
|
Retrieves the lead-dataset for a completed cold-outreach workflow.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/clawd/skills/email-content-compose
|
||||||
|
bun run fetch -- --workflow-id=<id>
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns: JSON with businesses (name, website, reviews, emails) and summary stats.
|
||||||
|
|
||||||
|
### 2. Compose (LLM)
|
||||||
|
The LLM agent reads fetch output and composes a personalized email per business.
|
||||||
|
Save drafts as a JSON array file. Each draft must have:
|
||||||
|
- `recipient_email` (string)
|
||||||
|
- `recipient_name` (string | null)
|
||||||
|
- `subject` (string, under 60 chars)
|
||||||
|
- `body_html` (string, professional HTML with inline styles)
|
||||||
|
- `body_text` (string, plain text fallback)
|
||||||
|
|
||||||
|
#### Email Composition Rules
|
||||||
|
- Reference the business name and specific review insights
|
||||||
|
- Mention pain points or strengths identified from reviews
|
||||||
|
- Tone: professional, consultative, not salesy
|
||||||
|
- Save the drafts array to a temp JSON file, e.g. `/tmp/drafts-<workflow-id>.json`
|
||||||
|
|
||||||
|
### 3. Export (scripts/export.ts)
|
||||||
|
Converts drafts to RFC 5322 EML files, uploads individual EMLs + ZIP bundle to R2.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/clawd/skills/email-content-compose
|
||||||
|
bun run export -- --drafts=/tmp/drafts-<workflow-id>.json --workflow-id=<id> [--from=<email>] [--dry-run]
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns: JSON with per-file R2 URLs and a bundle.zip URL.
|
||||||
|
|
||||||
|
## Full Pipeline Example
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/clawd/skills/email-content-compose
|
||||||
|
|
||||||
|
# 1. Fetch leads
|
||||||
|
bun run fetch -- --workflow-id=outreach-xxx > /tmp/leads.json
|
||||||
|
|
||||||
|
# 2. LLM composes drafts → saves to /tmp/drafts-outreach-xxx.json
|
||||||
|
|
||||||
|
# 3. Export EML + upload to R2
|
||||||
|
bun run export -- --drafts=/tmp/drafts-outreach-xxx.json --workflow-id=outreach-xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment (.env.local)
|
||||||
|
Already configured. Do NOT modify.
|
||||||
|
- AUTH_BASE, CLIENT_KEY: for lead-dataset API auth
|
||||||
|
- CLOUDFLARE_*: R2 upload credentials
|
||||||
|
- SENDER_EMAIL: From header in EML files
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
interface:
|
||||||
|
display_name: "Email Content Compose"
|
||||||
|
short_description: "Fetch leads, compose personalized emails, export EML to R2"
|
||||||
|
default_prompt: >
|
||||||
|
[skill:email-content-compose]
|
||||||
|
This skill uses Bun+TypeScript CLI scripts. Do NOT create Python scripts or custom upload logic.
|
||||||
|
|
||||||
|
Step 1: cd ~/clawd/skills/email-content-compose && bun run fetch -- --workflow-id=<WORKFLOW_ID>
|
||||||
|
Step 2: Read the fetch output. For each business with emails, compose a personalized EmailDraft (recipient_email, recipient_name, subject, body_html, body_text). Save all drafts as a JSON array to /tmp/drafts-<WORKFLOW_ID>.json
|
||||||
|
Step 3: bun run export -- --drafts=/tmp/drafts-<WORKFLOW_ID>.json --workflow-id=<WORKFLOW_ID>
|
||||||
|
|
||||||
|
Return the export result JSON (file URLs + bundle URL). Read SKILL.md for composition rules.
|
||||||
|
|
@ -0,0 +1,246 @@
|
||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"configVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "email-content-compose",
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-s3": "^3.1004.0",
|
||||||
|
"@clawd/auth-runtime": "file:../_shared/auth-runtime",
|
||||||
|
"@clawd/r2-upload": "file:../r2-upload",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"typescript": "^5.0.0",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
|
||||||
|
|
||||||
|
"@aws-crypto/crc32c": ["@aws-crypto/crc32c@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag=="],
|
||||||
|
|
||||||
|
"@aws-crypto/sha1-browser": ["@aws-crypto/sha1-browser@5.2.0", "", { "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg=="],
|
||||||
|
|
||||||
|
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
|
||||||
|
|
||||||
|
"@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
|
||||||
|
|
||||||
|
"@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="],
|
||||||
|
|
||||||
|
"@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
|
||||||
|
|
||||||
|
"@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.1004.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.18", "@aws-sdk/credential-provider-node": "^3.972.18", "@aws-sdk/middleware-bucket-endpoint": "^3.972.7", "@aws-sdk/middleware-expect-continue": "^3.972.7", "@aws-sdk/middleware-flexible-checksums": "^3.973.4", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-location-constraint": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-sdk-s3": "^3.972.18", "@aws-sdk/middleware-ssec": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.19", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/signature-v4-multi-region": "^3.996.6", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.4", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.8", "@smithy/eventstream-serde-browser": "^4.2.11", "@smithy/eventstream-serde-config-resolver": "^4.3.11", "@smithy/eventstream-serde-node": "^4.2.11", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-blob-browser": "^4.2.12", "@smithy/hash-node": "^4.2.11", "@smithy/hash-stream-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/md5-js": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.22", "@smithy/middleware-retry": "^4.4.39", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.38", "@smithy/util-defaults-mode-node": "^4.2.41", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "@smithy/util-waiter": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-m0zNfpsona9jQdX1cHtHArOiuvSGZPsgp/KRZS2YjJhKah96G2UN3UNGZQ6aVjXIQjCY6UanCJo0uW9Xf2U41w=="],
|
||||||
|
|
||||||
|
"@aws-sdk/core": ["@aws-sdk/core@3.973.18", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/xml-builder": "^3.972.10", "@smithy/core": "^3.23.8", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-GUIlegfcK2LO1J2Y98sCJy63rQSiLiDOgVw7HiHPRqfI2vb3XozTVqemwO0VSGXp54ngCnAQz0Lf0YPCBINNxA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/crc64-nvme": ["@aws-sdk/crc64-nvme@3.972.4", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-HKZIZLbRyvzo/bXZU7Zmk6XqU+1C9DjI56xd02vwuDIxedxBEqP17t9ExhbP9QFeNq/a3l9GOcyirFXxmbDhmw=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.16", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-HrdtnadvTGAQUr18sPzGlE5El3ICphnH6SU7UQOMOWFgRKbTRNN8msTxM4emzguUso9CzaHU2xy5ctSrmK5YNA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.18", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/node-http-handler": "^4.4.14", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/util-stream": "^4.5.17", "tslib": "^2.6.2" } }, "sha512-NyB6smuZAixND5jZumkpkunQ0voc4Mwgkd+SZ6cvAzIB7gK8HV8Zd4rS8Kn5MmoGgusyNfVGG+RLoYc4yFiw+A=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/credential-provider-env": "^3.972.16", "@aws-sdk/credential-provider-http": "^3.972.18", "@aws-sdk/credential-provider-login": "^3.972.17", "@aws-sdk/credential-provider-process": "^3.972.16", "@aws-sdk/credential-provider-sso": "^3.972.17", "@aws-sdk/credential-provider-web-identity": "^3.972.17", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/types": "^3.973.5", "@smithy/credential-provider-imds": "^4.2.11", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-dFqh7nfX43B8dO1aPQHOcjC0SnCJ83H3F+1LoCh3X1P7E7N09I+0/taID0asU6GCddfDExqnEvQtDdkuMe5tKQ=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-gf2E5b7LpKb+JX2oQsRIDxdRZjBFZt2olCGlWCdb3vBERbXIPgm2t1R5mEnwd4j0UEO/Tbg5zN2KJbHXttJqwA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.18", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.16", "@aws-sdk/credential-provider-http": "^3.972.18", "@aws-sdk/credential-provider-ini": "^3.972.17", "@aws-sdk/credential-provider-process": "^3.972.16", "@aws-sdk/credential-provider-sso": "^3.972.17", "@aws-sdk/credential-provider-web-identity": "^3.972.17", "@aws-sdk/types": "^3.973.5", "@smithy/credential-provider-imds": "^4.2.11", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-ZDJa2gd1xiPg/nBDGhUlat02O8obaDEnICBAVS8qieZ0+nDfaB0Z3ec6gjZj27OqFTjnB/Q5a0GwQwb7rMVViw=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.16", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-n89ibATwnLEg0ZdZmUds5bq8AfBAdoYEDpqP3uzPLaRuGelsKlIvCYSNNvfgGLi8NaHPNNhs1HjJZYbqkW9b+g=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/token-providers": "3.1004.0", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-wGtte+48xnhnhHMl/MsxzacBPs5A+7JJedjiP452IkHY7vsbYKcvQBqFye8LwdTJVeHtBHv+JFeTscnwepoWGg=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.17", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-8aiVJh6fTdl8gcyL+sVNcNwTtWpmoFa1Sh7xlj6Z7L/cZ/tYMEBHq44wTYG8Kt0z/PpGNopD89nbj3FHl9QmTA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-arn-parser": "^3.972.3", "@smithy/node-config-provider": "^4.3.11", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-goX+axlJ6PQlRnzE2bQisZ8wVrlm6dXJfBzMJhd8LhAIBan/w1Kl73fJnalM/S+18VnpzIHumyV6DtgmvqG5IA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-mvWqvm61bmZUKmmrtl2uWbokqpenY3Mc3Jf4nXB/Hse6gWxLPaCQThmhPBDzsPSV8/Odn8V6ovWt3pZ7vy4BFQ=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.973.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "^3.973.18", "@aws-sdk/crc64-nvme": "^3.972.4", "@aws-sdk/types": "^3.973.5", "@smithy/is-array-buffer": "^4.2.2", "@smithy/node-config-provider": "^4.3.11", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-middleware": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-7CH2jcGmkvkHc5Buz9IGbdjq1729AAlgYJiAvGq7qhCHqYleCsriWdSnmsqWTwdAfXHMT+pkxX3w6v5tJNcSug=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-vdK1LJfffBp87Lj0Bw3WdK1rJk9OLDYdQpqoKgmpIZPe+4+HawZ6THTbvjhJt4C4MNnRrHTKHQjkwBiIpDBoig=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.972.18", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-arn-parser": "^3.972.3", "@smithy/core": "^3.23.8", "@smithy/node-config-provider": "^4.3.11", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-5E3XxaElrdyk6ZJ0TjH7Qm6ios4b/qQCiLr6oQ8NK7e4Kn6JBTJCaYioQCQ65BpZ1+l1mK5wTAac2+pEz0Smpw=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-G9clGVuAml7d8DYzY6DnRi7TIIDRvZ3YpqJPz/8wnWS5fYx/FNWNmkO6iJVlVkQg9BfeMzd+bVPtPJOvC4B+nQ=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.19", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@smithy/core": "^3.23.8", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-retry": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-Km90fcXt3W/iqujHzuM6IaDkYCj73gsYufcuWXApWdzoTy6KGk8fnchAjePMARU0xegIR3K4N3yIo1vy7OVe8A=="],
|
||||||
|
|
||||||
|
"@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.7", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.18", "@aws-sdk/middleware-host-header": "^3.972.7", "@aws-sdk/middleware-logger": "^3.972.7", "@aws-sdk/middleware-recursion-detection": "^3.972.7", "@aws-sdk/middleware-user-agent": "^3.972.19", "@aws-sdk/region-config-resolver": "^3.972.7", "@aws-sdk/types": "^3.973.5", "@aws-sdk/util-endpoints": "^3.996.4", "@aws-sdk/util-user-agent-browser": "^3.972.7", "@aws-sdk/util-user-agent-node": "^3.973.4", "@smithy/config-resolver": "^4.4.10", "@smithy/core": "^3.23.8", "@smithy/fetch-http-handler": "^5.3.13", "@smithy/hash-node": "^4.2.11", "@smithy/invalid-dependency": "^4.2.11", "@smithy/middleware-content-length": "^4.2.11", "@smithy/middleware-endpoint": "^4.4.22", "@smithy/middleware-retry": "^4.4.39", "@smithy/middleware-serde": "^4.2.12", "@smithy/middleware-stack": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/node-http-handler": "^4.4.14", "@smithy/protocol-http": "^5.3.11", "@smithy/smithy-client": "^4.12.2", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.38", "@smithy/util-defaults-mode-node": "^4.2.41", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-MlGWA8uPaOs5AiTZ5JLM4uuWDm9EEAnm9cqwvqQIc6kEgel/8s1BaOWm9QgUcfc9K8qd7KkC3n43yDbeXOA2tg=="],
|
||||||
|
|
||||||
|
"@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/config-resolver": "^4.4.10", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.6", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "^3.972.18", "@aws-sdk/types": "^3.973.5", "@smithy/protocol-http": "^5.3.11", "@smithy/signature-v4": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-NnsOQsVmJXy4+IdPFUjRCWPn9qNH1TzS/f7MiWgXeoHs903tJpAWQWQtoFvLccyPoBgomKP9L89RRr2YsT/L0g=="],
|
||||||
|
|
||||||
|
"@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1004.0", "", { "dependencies": { "@aws-sdk/core": "^3.973.18", "@aws-sdk/nested-clients": "^3.996.7", "@aws-sdk/types": "^3.973.5", "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-j9BwZZId9sFp+4GPhf6KrwO8Tben2sXibZA8D1vv2I1zBdvkUHcBA2g4pkqIpTRalMTLC0NPkBPX0gERxfy/iA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/types": ["@aws-sdk/types@3.973.5", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ=="],
|
||||||
|
|
||||||
|
"@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.972.3", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.4", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-endpoints": "^3.3.2", "tslib": "^2.6.2" } }, "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.5", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ=="],
|
||||||
|
|
||||||
|
"@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.7", "", { "dependencies": { "@aws-sdk/types": "^3.973.5", "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw=="],
|
||||||
|
|
||||||
|
"@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.4", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.19", "@aws-sdk/types": "^3.973.5", "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-uqKeLqZ9D3nQjH7HGIERNXK9qnSpUK08l4MlJ5/NZqSSdeJsVANYp437EM9sEzwU28c2xfj2V6qlkqzsgtKs6Q=="],
|
||||||
|
|
||||||
|
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="],
|
||||||
|
|
||||||
|
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.3", "", {}, "sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw=="],
|
||||||
|
|
||||||
|
"@clawd/auth-runtime": ["@clawd/auth-runtime@file:../_shared/auth-runtime", { "devDependencies": { "@types/node": "^25.3.3", "typescript": "^5.9.3" } }],
|
||||||
|
|
||||||
|
"@clawd/r2-upload": ["@clawd/r2-upload@file:../r2-upload", { "dependencies": { "@aws-sdk/client-s3": "^3.705.0" }, "devDependencies": { "@types/bun": "latest", "typescript": "^5.0.0" } }],
|
||||||
|
|
||||||
|
"@smithy/abort-controller": ["@smithy/abort-controller@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-Hj4WoYWMJnSpM6/kchsm4bUNTL9XiSyhvoMb2KIq4VJzyDt7JpGHUZHkVNPZVC7YE1tf8tPeVauxpFBKGW4/KQ=="],
|
||||||
|
|
||||||
|
"@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw=="],
|
||||||
|
|
||||||
|
"@smithy/chunked-blob-reader-native": ["@smithy/chunked-blob-reader-native@4.2.3", "", { "dependencies": { "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-jA5k5Udn7Y5717L86h4EIv06wIr3xn8GM1qHRi/Nf31annXcXHJjBKvgztnbn2TxH3xWrPBfgwHsOwZf0UmQWw=="],
|
||||||
|
|
||||||
|
"@smithy/config-resolver": ["@smithy/config-resolver@4.4.10", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-endpoints": "^3.3.2", "@smithy/util-middleware": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-IRTkd6ps0ru+lTWnfnsbXzW80A8Od8p3pYiZnW98K2Hb20rqfsX7VTlfUwhrcOeSSy68Gn9WBofwPuw3e5CCsg=="],
|
||||||
|
|
||||||
|
"@smithy/core": ["@smithy/core@3.23.9", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.12", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-1Vcut4LEL9HZsdpI0vFiRYIsaoPwZLjAxnVQDUMQK8beMS+EYPLDQCXtbzfxmM5GzSgjfe2Q9M7WaXwIMQllyQ=="],
|
||||||
|
|
||||||
|
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.11", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-lBXrS6ku0kTj3xLmsJW0WwqWbGQ6ueooYyp/1L9lkyT0M02C+DWwYwc5aTyXFbRaK38ojALxNixg+LxKSHZc0g=="],
|
||||||
|
|
||||||
|
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.11", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.13.0", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-Sf39Ml0iVX+ba/bgMPxaXWAAFmHqYLTmbjAPfLPLY8CrYkRDEqZdUsKC1OwVMCdJXfAt0v4j49GIJ8DoSYAe6w=="],
|
||||||
|
|
||||||
|
"@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.11", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-3rEpo3G6f/nRS7fQDsZmxw/ius6rnlIpz4UX6FlALEzz8JoSxFmdBt0SZnthis+km7sQo6q5/3e+UJcuQivoXA=="],
|
||||||
|
|
||||||
|
"@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-XeNIA8tcP/GDWnnKkO7qEm/bg0B/bP9lvIXZBXcGZwZ+VYM8h8k9wuDvUODtdQ2Wcp2RcBkPTCSMmaniVHrMlA=="],
|
||||||
|
|
||||||
|
"@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.11", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-fzbCh18rscBDTQSCrsp1fGcclLNF//nJyhjldsEl/5wCYmgpHblv5JSppQAyQI24lClsFT0wV06N1Porn0IsEw=="],
|
||||||
|
|
||||||
|
"@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.11", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-MJ7HcI+jEkqoWT5vp+uoVaAjBrmxBtKhZTeynDRG/seEjJfqyg3SiqMMqyPnAMzmIfLaeJ/uiuSDP/l9AnMy/Q=="],
|
||||||
|
|
||||||
|
"@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.13", "", { "dependencies": { "@smithy/protocol-http": "^5.3.11", "@smithy/querystring-builder": "^4.2.11", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-U2Hcfl2s3XaYjikN9cT4mPu8ybDbImV3baXR0PkVlC0TTx808bRP3FaPGAzPtB8OByI+JqJ1kyS+7GEgae7+qQ=="],
|
||||||
|
|
||||||
|
"@smithy/hash-blob-browser": ["@smithy/hash-blob-browser@4.2.12", "", { "dependencies": { "@smithy/chunked-blob-reader": "^5.2.2", "@smithy/chunked-blob-reader-native": "^4.2.3", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-1wQE33DsxkM/waftAhCH9VtJbUGyt1PJ9YRDpOu+q9FUi73LLFUZ2fD8A61g2mT1UY9k7b99+V1xZ41Rz4SHRQ=="],
|
||||||
|
|
||||||
|
"@smithy/hash-node": ["@smithy/hash-node@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-T+p1pNynRkydpdL015ruIoyPSRw9e/SQOWmSAMmmprfswMrd5Ow5igOWNVlvyVFZlxXqGmyH3NQwfwy8r5Jx0A=="],
|
||||||
|
|
||||||
|
"@smithy/hash-stream-node": ["@smithy/hash-stream-node@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-hQsTjwPCRY8w9GK07w1RqJi3e+myh0UaOWBBhZ1UMSDgofH/Q1fEYzU1teaX6HkpX/eWDdm7tAGR0jBPlz9QEQ=="],
|
||||||
|
|
||||||
|
"@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-cGNMrgykRmddrNhYy1yBdrp5GwIgEkniS7k9O1VLB38yxQtlvrxpZtUVvo6T4cKpeZsriukBuuxfJcdZQc/f/g=="],
|
||||||
|
|
||||||
|
"@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow=="],
|
||||||
|
|
||||||
|
"@smithy/md5-js": ["@smithy/md5-js@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-350X4kGIrty0Snx2OWv7rPM6p6vM7RzryvFs6B/56Cux3w3sChOb3bymo5oidXJlPcP9fIRxGUCk7GqpiSOtng=="],
|
||||||
|
|
||||||
|
"@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.11", "", { "dependencies": { "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-UvIfKYAKhCzr4p6jFevPlKhQwyQwlJ6IeKLDhmV1PlYfcW3RL4ROjNEDtSik4NYMi9kDkH7eSwyTP3vNJ/u/Dw=="],
|
||||||
|
|
||||||
|
"@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.23", "", { "dependencies": { "@smithy/core": "^3.23.9", "@smithy/middleware-serde": "^4.2.12", "@smithy/node-config-provider": "^4.3.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "@smithy/util-middleware": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-UEFIejZy54T1EJn2aWJ45voB7RP2T+IRzUqocIdM6GFFa5ClZncakYJfcYnoXt3UsQrZZ9ZRauGm77l9UCbBLw=="],
|
||||||
|
|
||||||
|
"@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.40", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/protocol-http": "^5.3.11", "@smithy/service-error-classification": "^4.2.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "@smithy/util-middleware": "^4.2.11", "@smithy/util-retry": "^4.2.11", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-YhEMakG1Ae57FajERdHNZ4ShOPIY7DsgV+ZoAxo/5BT0KIe+f6DDU2rtIymNNFIj22NJfeeI6LWIifrwM0f+rA=="],
|
||||||
|
|
||||||
|
"@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-W9g1bOLui7Xn5FABRVS0o3rXL0gfN37d/8I/W7i0N7oxjx9QecUmXEMSUMADTODwdtka9cN43t5BI2CodLJpng=="],
|
||||||
|
|
||||||
|
"@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-s+eenEPW6RgliDk2IhjD2hWOxIx1NKrOHxEwNUaUXxYBxIyCcDfNULZ2Mu15E3kwcJWBedTET/kEASPV1A1Akg=="],
|
||||||
|
|
||||||
|
"@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.11", "", { "dependencies": { "@smithy/property-provider": "^4.2.11", "@smithy/shared-ini-file-loader": "^4.4.6", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-xD17eE7kaLgBBGf5CZQ58hh2YmwK1Z0O8YhffwB/De2jsL0U3JklmhVYJ9Uf37OtUDLF2gsW40Xwwag9U869Gg=="],
|
||||||
|
|
||||||
|
"@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.14", "", { "dependencies": { "@smithy/abort-controller": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/querystring-builder": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-DamSqaU8nuk0xTJDrYnRzZndHwwRnyj/n/+RqGGCcBKB4qrQem0mSDiWdupaNWdwxzyMU91qxDmHOCazfhtO3A=="],
|
||||||
|
|
||||||
|
"@smithy/property-provider": ["@smithy/property-provider@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg=="],
|
||||||
|
|
||||||
|
"@smithy/protocol-http": ["@smithy/protocol-http@5.3.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hI+barOVDJBkNt4y0L2mu3Ugc0w7+BpJ2CZuLwXtSltGAAwCb3IvnalGlbDV/UCS6a9ZuT3+exd1WxNdLb5IlQ=="],
|
||||||
|
|
||||||
|
"@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA=="],
|
||||||
|
|
||||||
|
"@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-nE3IRNjDltvGcoThD2abTozI1dkSy8aX+a2N1Rs55en5UsdyyIXgGEmevUL3okZFoJC77JgRGe99xYohhsjivQ=="],
|
||||||
|
|
||||||
|
"@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0" } }, "sha512-HkMFJZJUhzU3HvND1+Yw/kYWXp4RPDLBWLcK1n+Vqw8xn4y2YiBhdww8IxhkQjP/QlZun5bwm3vcHc8AqIU3zw=="],
|
||||||
|
|
||||||
|
"@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.6", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-IB/M5I8G0EeXZTHsAxpx51tMQ5R719F3aq+fjEB6VtNcCHDc0ajFDIGDZw+FW9GxtEkgTduiPpjveJdA/CX7sw=="],
|
||||||
|
|
||||||
|
"@smithy/signature-v4": ["@smithy/signature-v4@5.3.11", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-V1L6N9aKOBAN4wEHLyqjLBnAz13mtILU0SeDrjOaIZEeN6IFa6DxwRt1NNpOdmSpQUfkBj0qeD3m6P77uzMhgQ=="],
|
||||||
|
|
||||||
|
"@smithy/smithy-client": ["@smithy/smithy-client@4.12.3", "", { "dependencies": { "@smithy/core": "^3.23.9", "@smithy/middleware-endpoint": "^4.4.23", "@smithy/middleware-stack": "^4.2.11", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-stream": "^4.5.17", "tslib": "^2.6.2" } }, "sha512-7k4UxjSpHmPN2AxVhvIazRSzFQjWnud3sOsXcFStzagww17j1cFQYqTSiQ8xuYK3vKLR1Ni8FzuT3VlKr3xCNw=="],
|
||||||
|
|
||||||
|
"@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
|
||||||
|
|
||||||
|
"@smithy/url-parser": ["@smithy/url-parser@4.2.11", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-oTAGGHo8ZYc5VZsBREzuf5lf2pAurJQsccMusVZ85wDkX66ojEc/XauiGjzCj50A61ObFTPe6d7Pyt6UBYaing=="],
|
||||||
|
|
||||||
|
"@smithy/util-base64": ["@smithy/util-base64@4.3.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ=="],
|
||||||
|
|
||||||
|
"@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ=="],
|
||||||
|
|
||||||
|
"@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.3", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g=="],
|
||||||
|
|
||||||
|
"@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.2", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q=="],
|
||||||
|
|
||||||
|
"@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ=="],
|
||||||
|
|
||||||
|
"@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.39", "", { "dependencies": { "@smithy/property-provider": "^4.2.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-ui7/Ho/+VHqS7Km2wBw4/Ab4RktoiSshgcgpJzC4keFPs6tLJS4IQwbeahxQS3E/w98uq6E1mirCH/id9xIXeQ=="],
|
||||||
|
|
||||||
|
"@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.42", "", { "dependencies": { "@smithy/config-resolver": "^4.4.10", "@smithy/credential-provider-imds": "^4.2.11", "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/smithy-client": "^4.12.3", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-QDA84CWNe8Akpj15ofLO+1N3Rfg8qa2K5uX0y6HnOp4AnRYRgWrKx/xzbYNbVF9ZsyJUYOfcoaN3y93wA/QJ2A=="],
|
||||||
|
|
||||||
|
"@smithy/util-endpoints": ["@smithy/util-endpoints@3.3.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-+4HFLpE5u29AbFlTdlKIT7jfOzZ8PDYZKTb3e+AgLz986OYwqTourQ5H+jg79/66DB69Un1+qKecLnkZdAsYcA=="],
|
||||||
|
|
||||||
|
"@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg=="],
|
||||||
|
|
||||||
|
"@smithy/util-middleware": ["@smithy/util-middleware@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-r3dtF9F+TpSZUxpOVVtPfk09Rlo4lT6ORBqEvX3IBT6SkQAdDSVKR5GcfmZbtl7WKhKnmb3wbDTQ6ibR2XHClw=="],
|
||||||
|
|
||||||
|
"@smithy/util-retry": ["@smithy/util-retry@4.2.11", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-XSZULmL5x6aCTTii59wJqKsY1l3eMIAomRAccW7Tzh9r8s7T/7rdo03oektuH5jeYRlJMPcNP92EuRDvk9aXbw=="],
|
||||||
|
|
||||||
|
"@smithy/util-stream": ["@smithy/util-stream@4.5.17", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.13", "@smithy/node-http-handler": "^4.4.14", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-793BYZ4h2JAQkNHcEnyFxDTcZbm9bVybD0UV/LEWmZ5bkTms7JqjfrLMi2Qy0E5WFcCzLwCAPgcvcvxoeALbAQ=="],
|
||||||
|
|
||||||
|
"@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw=="],
|
||||||
|
|
||||||
|
"@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
|
"@smithy/util-waiter": ["@smithy/util-waiter@4.2.11", "", { "dependencies": { "@smithy/abort-controller": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-x7Rh2azQPs3XxbvCzcttRErKKvLnbZfqRf/gOjw2pb+ZscX88e5UkRPCB67bVnsFHxayvMvmePfKTqsRb+is1A=="],
|
||||||
|
|
||||||
|
"@smithy/uuid": ["@smithy/uuid@1.1.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g=="],
|
||||||
|
|
||||||
|
"@types/bun": ["@types/bun@1.3.10", "", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@25.3.5", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA=="],
|
||||||
|
|
||||||
|
"bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.3.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg=="],
|
||||||
|
|
||||||
|
"fast-xml-builder": ["fast-xml-builder@1.0.0", "", {}, "sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ=="],
|
||||||
|
|
||||||
|
"fast-xml-parser": ["fast-xml-parser@5.4.1", "", { "dependencies": { "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A=="],
|
||||||
|
|
||||||
|
"strnum": ["strnum@2.2.0", "", {}, "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg=="],
|
||||||
|
|
||||||
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
||||||
|
|
||||||
|
"@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||||
|
|
||||||
|
"@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||||
|
|
||||||
|
"@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||||
|
|
||||||
|
"@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
||||||
|
|
||||||
|
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
||||||
|
|
||||||
|
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
||||||
|
|
||||||
|
"@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
||||||
|
|
||||||
|
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
||||||
|
|
||||||
|
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"status": { "type": "string", "enum": ["success", "failed"] },
|
||||||
|
"error": { "type": ["string", "null"] },
|
||||||
|
"workflowId": { "type": "string" },
|
||||||
|
"workflowStatus": { "type": "string" },
|
||||||
|
"query": { "type": "string" },
|
||||||
|
"country": { "type": "string" },
|
||||||
|
"productKeywords": { "type": ["string", "null"] },
|
||||||
|
"completedAt": { "type": ["string", "null"] },
|
||||||
|
"summary": {
|
||||||
|
"type": ["object", "null"],
|
||||||
|
"properties": {
|
||||||
|
"businesses_count": { "type": "number" },
|
||||||
|
"contacts_count": { "type": "number" },
|
||||||
|
"businesses_with_reviews": { "type": "number" },
|
||||||
|
"businesses_with_email": { "type": "number" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"businesses": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": { "type": "string" },
|
||||||
|
"domain": { "type": ["string", "null"] },
|
||||||
|
"emails": { "type": "array", "items": { "type": "string" } },
|
||||||
|
"reviews_data": { "type": ["string", "null"] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["status", "error", "workflowId", "workflowStatus", "businesses"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "email-content-compose",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"description": "Fetch lead-dataset, compose personalized outreach emails, export as EML and upload to R2",
|
||||||
|
"type": "module",
|
||||||
|
"main": "src/index.ts",
|
||||||
|
"scripts": {
|
||||||
|
"fetch": "bun run scripts/fetch.ts",
|
||||||
|
"export": "bun run scripts/export.ts",
|
||||||
|
"test": "bun run scripts/test.ts"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"typescript": "^5.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-s3": "^3.1004.0",
|
||||||
|
"@clawd/auth-runtime": "git+http://192.168.0.108:3030/agent-skills/auth-runtime.git",
|
||||||
|
"@clawd/r2-upload": "git+http://192.168.0.108:3030/agent-skills/r2-upload.git"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||||
|
|
||||||
|
import { readDraftsFile, exportDrafts } from "../src/index.js";
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const draftsFile = args.find(a => a.startsWith("--drafts="))?.split("=")[1];
|
||||||
|
const workflowId = args.find(a => a.startsWith("--workflow-id="))?.split("=")[1] || "unknown";
|
||||||
|
const from = args.find(a => a.startsWith("--from="))?.split("=")[1];
|
||||||
|
const dryRun = args.includes("--dry-run");
|
||||||
|
|
||||||
|
if (!draftsFile) {
|
||||||
|
console.error("Usage: bun run export -- --drafts=<path.json> --workflow-id=<id> [--from=<email>] [--dry-run]");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const drafts = await readDraftsFile(draftsFile);
|
||||||
|
console.log(`Exporting ${drafts.length} drafts...`);
|
||||||
|
|
||||||
|
const result = await exportDrafts(drafts, workflowId, { from, dryRun });
|
||||||
|
console.log(JSON.stringify(result, null, 2));
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { existsSync, readFileSync } from "fs";
|
||||||
|
import { join, dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import { fetchLeads } from "../src/index.js";
|
||||||
|
|
||||||
|
function loadEnvLocal(): void {
|
||||||
|
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const envPath = join(scriptDir, "../.env.local");
|
||||||
|
if (!existsSync(envPath)) return;
|
||||||
|
for (const line of readFileSync(envPath, "utf-8").split("\n")) {
|
||||||
|
const trimmed = line.trim();
|
||||||
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
||||||
|
const eq = trimmed.indexOf("=");
|
||||||
|
if (eq <= 0) continue;
|
||||||
|
const key = trimmed.slice(0, eq).trim();
|
||||||
|
let val = trimmed.slice(eq + 1).trim();
|
||||||
|
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
|
||||||
|
val = val.slice(1, -1);
|
||||||
|
}
|
||||||
|
if (!process.env[key]) process.env[key] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseArgs(args: string[]): { workflowId: string; dryRun: boolean } {
|
||||||
|
let dryRun = false;
|
||||||
|
let workflowId = "";
|
||||||
|
|
||||||
|
for (const arg of args) {
|
||||||
|
if (arg === "--dry-run") { dryRun = true; continue; }
|
||||||
|
if (arg === "-h" || arg === "--help") {
|
||||||
|
console.error("Usage: bun run fetch -- --workflow-id=<outreach-xxx> [--dry-run]");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
if (arg.startsWith("--workflow-id=")) { workflowId = arg.slice("--workflow-id=".length).trim(); continue; }
|
||||||
|
if (!workflowId) workflowId = arg;
|
||||||
|
}
|
||||||
|
return { workflowId, dryRun };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main(): Promise<void> {
|
||||||
|
loadEnvLocal();
|
||||||
|
const args = parseArgs(process.argv.slice(2));
|
||||||
|
const result = await fetchLeads(args.workflowId, args.dryRun);
|
||||||
|
console.log(JSON.stringify(result, null, 2));
|
||||||
|
if (result.status === "failed") process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error(JSON.stringify({ status: "failed", error: err instanceof Error ? err.message : String(err) }));
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { fetchLeads } from "../src/index.js";
|
||||||
|
|
||||||
|
const workflowId = process.argv[2] || "outreach-test-123";
|
||||||
|
const mode = process.argv[3] || "--dry-run";
|
||||||
|
const clientKey = process.argv[4] || "";
|
||||||
|
|
||||||
|
if (mode === "--live" && clientKey) {
|
||||||
|
process.env.CLIENT_KEY = clientKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("=== Email Content Compose - Test ===");
|
||||||
|
console.log(`Workflow: ${workflowId} Mode: ${mode}\n`);
|
||||||
|
|
||||||
|
const isDryRun = mode !== "--live";
|
||||||
|
const result = await fetchLeads(workflowId, isDryRun);
|
||||||
|
console.log(JSON.stringify(result, null, 2));
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
import type { EmailDraft } from "./types.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a draft to RFC 5322 EML format with MIME multipart/alternative.
|
||||||
|
*/
|
||||||
|
export function draftToEml(draft: EmailDraft, from: string): string {
|
||||||
|
const boundary = `----=_Part_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
||||||
|
const date = new Date().toUTCString();
|
||||||
|
const messageId = `<${Date.now()}.${Math.random().toString(36).slice(2)}@outreach.local>`;
|
||||||
|
|
||||||
|
const toHeader = draft.recipient_name
|
||||||
|
? `"${draft.recipient_name}" <${draft.recipient_email}>`
|
||||||
|
: draft.recipient_email;
|
||||||
|
|
||||||
|
const headers = [
|
||||||
|
`From: ${from}`,
|
||||||
|
`To: ${toHeader}`,
|
||||||
|
`Subject: ${encodeSubject(draft.subject)}`,
|
||||||
|
`Date: ${date}`,
|
||||||
|
`Message-ID: ${messageId}`,
|
||||||
|
`MIME-Version: 1.0`,
|
||||||
|
`Content-Type: multipart/alternative; boundary="${boundary}"`,
|
||||||
|
`X-Mailer: email-export-skill`,
|
||||||
|
];
|
||||||
|
|
||||||
|
const textPart = [
|
||||||
|
`--${boundary}`,
|
||||||
|
`Content-Type: text/plain; charset="utf-8"`,
|
||||||
|
`Content-Transfer-Encoding: quoted-printable`,
|
||||||
|
``,
|
||||||
|
quotedPrintableEncode(draft.body_text),
|
||||||
|
].join("\r\n");
|
||||||
|
|
||||||
|
const htmlPart = [
|
||||||
|
`--${boundary}`,
|
||||||
|
`Content-Type: text/html; charset="utf-8"`,
|
||||||
|
`Content-Transfer-Encoding: quoted-printable`,
|
||||||
|
``,
|
||||||
|
quotedPrintableEncode(draft.body_html),
|
||||||
|
].join("\r\n");
|
||||||
|
|
||||||
|
return [
|
||||||
|
headers.join("\r\n"),
|
||||||
|
``,
|
||||||
|
textPart,
|
||||||
|
``,
|
||||||
|
htmlPart,
|
||||||
|
``,
|
||||||
|
`--${boundary}--`,
|
||||||
|
``,
|
||||||
|
].join("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** RFC 2047 encoded-word for non-ASCII subjects */
|
||||||
|
function encodeSubject(subject: string): string {
|
||||||
|
if (/^[\x20-\x7E]*$/.test(subject)) return subject;
|
||||||
|
const encoded = Buffer.from(subject, "utf-8").toString("base64");
|
||||||
|
return `=?UTF-8?B?${encoded}?=`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Simple quoted-printable encoding */
|
||||||
|
function quotedPrintableEncode(text: string): string {
|
||||||
|
const lines: string[] = [];
|
||||||
|
let current = "";
|
||||||
|
|
||||||
|
for (const char of text) {
|
||||||
|
const code = char.charCodeAt(0);
|
||||||
|
let encoded: string;
|
||||||
|
|
||||||
|
if (char === "\r" || char === "\n") {
|
||||||
|
lines.push(current);
|
||||||
|
current = "";
|
||||||
|
continue;
|
||||||
|
} else if (code === 9 || (code >= 32 && code <= 126 && char !== "=")) {
|
||||||
|
encoded = char;
|
||||||
|
} else {
|
||||||
|
const buf = Buffer.from(char, "utf-8");
|
||||||
|
encoded = Array.from(buf).map(b => `=${b.toString(16).toUpperCase().padStart(2, "0")}`).join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current.length + encoded.length > 75) {
|
||||||
|
lines.push(current + "=");
|
||||||
|
current = encoded;
|
||||||
|
} else {
|
||||||
|
current += encoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (current) lines.push(current);
|
||||||
|
return lines.join("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Generate a safe filename from draft */
|
||||||
|
export function emlFilename(draft: EmailDraft, index: number): string {
|
||||||
|
const domain = draft.recipient_email.split("@")[1] || "unknown";
|
||||||
|
const safe = domain.replace(/[^a-zA-Z0-9.-]/g, "_");
|
||||||
|
return `${String(index + 1).padStart(3, "0")}_${safe}.eml`;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
import type { EmailDraft, ExportResult, ExportedFile, FetchResult } from './types.js';
|
||||||
|
import { createEnvConfig as createBaseEnvConfig, getAccessToken } from '@clawd/auth-runtime';
|
||||||
|
import { fetchLeadDataset } from './lead-dataset.js';
|
||||||
|
import { draftToEml, emlFilename } from './eml.js';
|
||||||
|
import { loadR2Config, uploadToR2 } from '@clawd/r2-upload';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch lead-dataset from completed workflow.
|
||||||
|
* Returns businesses with emails and reviews for LLM to compose emails.
|
||||||
|
*/
|
||||||
|
export async function fetchLeads(
|
||||||
|
workflowId: string,
|
||||||
|
dryRun: boolean = false,
|
||||||
|
): Promise<FetchResult> {
|
||||||
|
if (!workflowId) {
|
||||||
|
return failedFetch('', 'missing workflow-id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun) {
|
||||||
|
return {
|
||||||
|
status: 'success',
|
||||||
|
error: null,
|
||||||
|
workflowId,
|
||||||
|
workflowStatus: 'dry_run',
|
||||||
|
query: 'dry-run-query',
|
||||||
|
country: 'us',
|
||||||
|
productKeywords: null,
|
||||||
|
completedAt: null,
|
||||||
|
summary: { businesses_count: 3, contacts_count: 5, businesses_with_reviews: 2, businesses_with_email: 3 },
|
||||||
|
businesses: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = createBaseEnvConfig();
|
||||||
|
|
||||||
|
let accessToken: string;
|
||||||
|
try {
|
||||||
|
accessToken = await getAccessToken(false, config);
|
||||||
|
} catch (err) {
|
||||||
|
return failedFetch(workflowId, err instanceof Error ? err.message : 'failed to exchange token');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data, error } = await fetchLeadDataset(config, accessToken, workflowId, false);
|
||||||
|
if (!data) {
|
||||||
|
return failedFetch(workflowId, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 'success',
|
||||||
|
error: null,
|
||||||
|
workflowId: data.workflow_id,
|
||||||
|
workflowStatus: data.status,
|
||||||
|
query: data.query,
|
||||||
|
country: data.country,
|
||||||
|
productKeywords: data.product_keywords,
|
||||||
|
completedAt: data.completed_at,
|
||||||
|
summary: data.summary,
|
||||||
|
businesses: data.businesses,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export drafts: convert to EML, upload to R2, return URLs.
|
||||||
|
*/
|
||||||
|
export async function exportDrafts(
|
||||||
|
drafts: EmailDraft[],
|
||||||
|
workflowId: string,
|
||||||
|
options: {
|
||||||
|
from?: string;
|
||||||
|
prefix?: string;
|
||||||
|
dryRun?: boolean;
|
||||||
|
} = {},
|
||||||
|
): Promise<ExportResult> {
|
||||||
|
const from = options.from || process.env.SENDER_EMAIL || 'outreach@company.com';
|
||||||
|
const prefix = options.prefix || `outreach/eml/${workflowId}/${Date.now()}`;
|
||||||
|
|
||||||
|
if (!drafts.length) {
|
||||||
|
return { status: 'failed', error: 'no drafts to export', workflowId, totalDrafts: 0, exportedCount: 0, bundleUrl: null, files: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert all drafts to EML
|
||||||
|
const emlFiles: { filename: string; content: string; draft: EmailDraft }[] = [];
|
||||||
|
for (let i = 0; i < drafts.length; i++) {
|
||||||
|
const draft = drafts[i];
|
||||||
|
const filename = emlFilename(draft, i);
|
||||||
|
const content = draftToEml(draft, from);
|
||||||
|
emlFiles.push({ filename, content, draft });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.dryRun) {
|
||||||
|
const files: ExportedFile[] = emlFiles.map(f => ({
|
||||||
|
filename: f.filename,
|
||||||
|
url: `(dry-run) ${prefix}/${f.filename}`,
|
||||||
|
recipient: f.draft.recipient_email,
|
||||||
|
subject: f.draft.subject,
|
||||||
|
}));
|
||||||
|
return { status: 'success', error: null, workflowId, totalDrafts: drafts.length, exportedCount: files.length, bundleUrl: `(dry-run) ${prefix}/bundle.zip`, files };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload to R2
|
||||||
|
const r2Config = loadR2Config();
|
||||||
|
const files: ExportedFile[] = [];
|
||||||
|
|
||||||
|
for (const eml of emlFiles) {
|
||||||
|
const key = `${prefix}/${eml.filename}`;
|
||||||
|
const url = await uploadToR2(r2Config, key, eml.content, 'message/rfc822');
|
||||||
|
files.push({
|
||||||
|
filename: eml.filename,
|
||||||
|
url,
|
||||||
|
recipient: eml.draft.recipient_email,
|
||||||
|
subject: eml.draft.subject,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and upload zip bundle
|
||||||
|
let bundleUrl: string | null = null;
|
||||||
|
try {
|
||||||
|
const { createZipBundle } = await import('./zip.js');
|
||||||
|
const zipBuffer = await createZipBundle(emlFiles.map(f => ({ name: f.filename, content: f.content })));
|
||||||
|
bundleUrl = await uploadToR2(r2Config, `${prefix}/bundle.zip`, zipBuffer, 'application/zip');
|
||||||
|
} catch {
|
||||||
|
// zip is optional
|
||||||
|
}
|
||||||
|
|
||||||
|
return { status: 'success', error: null, workflowId, totalDrafts: drafts.length, exportedCount: files.length, bundleUrl, files };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read drafts from a JSON file.
|
||||||
|
*/
|
||||||
|
export async function readDraftsFile(path: string): Promise<EmailDraft[]> {
|
||||||
|
const file = Bun.file(path);
|
||||||
|
if (!await file.exists()) {
|
||||||
|
throw new Error(`file not found: ${path}`);
|
||||||
|
}
|
||||||
|
const raw = await file.json();
|
||||||
|
return Array.isArray(raw) ? raw : (raw?.drafts ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function failedFetch(workflowId: string, error: string): FetchResult {
|
||||||
|
return {
|
||||||
|
status: 'failed', error, workflowId, workflowStatus: '', query: '', country: '',
|
||||||
|
productKeywords: null, completedAt: null, summary: null, businesses: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
import type { LeadDatasetResponse } from './types.js';
|
||||||
|
import { requestApiWithAutoRefresh } from '@clawd/auth-runtime';
|
||||||
|
import type { EnvConfig } from '@clawd/auth-runtime';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch lead-dataset from a completed cold-outreach workflow.
|
||||||
|
*/
|
||||||
|
export async function fetchLeadDataset(
|
||||||
|
config: EnvConfig,
|
||||||
|
accessToken: string,
|
||||||
|
workflowId: string,
|
||||||
|
dryRun: boolean,
|
||||||
|
): Promise<{ data: LeadDatasetResponse | null; error: string }> {
|
||||||
|
const url = `${config.authBase}/ecom/cold-outreach/${workflowId}/lead-dataset`;
|
||||||
|
const result = await requestApiWithAutoRefresh(
|
||||||
|
'GET',
|
||||||
|
url,
|
||||||
|
dryRun,
|
||||||
|
config,
|
||||||
|
undefined,
|
||||||
|
accessToken,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.status < 200 || result.status >= 300) {
|
||||||
|
const msg = parseError(result.body);
|
||||||
|
return {
|
||||||
|
data: null,
|
||||||
|
error: msg || `lead-dataset fetch failed: HTTP ${result.status}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(result.body) as LeadDatasetResponse;
|
||||||
|
if (!data.success) {
|
||||||
|
return { data: null, error: data.message || 'lead-dataset returned success=false' };
|
||||||
|
}
|
||||||
|
return { data, error: '' };
|
||||||
|
} catch {
|
||||||
|
return { data: null, error: 'failed to parse lead-dataset response' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseError(body: string): string {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(body);
|
||||||
|
return data.message || data.error || '';
|
||||||
|
} catch {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
export interface Business {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
website: string | null;
|
||||||
|
domain: string | null;
|
||||||
|
address: string | null;
|
||||||
|
phone: string | null;
|
||||||
|
rating: number | null;
|
||||||
|
reviews_count: number | null;
|
||||||
|
category: string | null;
|
||||||
|
reviews_data: string | null;
|
||||||
|
emails: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LeadSummary {
|
||||||
|
businesses_count: number;
|
||||||
|
contacts_count: number;
|
||||||
|
businesses_with_reviews: number;
|
||||||
|
businesses_with_email: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LeadDatasetResponse {
|
||||||
|
success: boolean;
|
||||||
|
workflow_id: string;
|
||||||
|
status: string;
|
||||||
|
query: string;
|
||||||
|
country: string;
|
||||||
|
product_keywords: string | null;
|
||||||
|
completed_at: string | null;
|
||||||
|
summary: LeadSummary;
|
||||||
|
businesses: Business[];
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EmailDraft {
|
||||||
|
recipient_email: string;
|
||||||
|
recipient_name: string | null;
|
||||||
|
subject: string;
|
||||||
|
body_html: string;
|
||||||
|
body_text: string;
|
||||||
|
personalization_context?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExportedFile {
|
||||||
|
filename: string;
|
||||||
|
url: string;
|
||||||
|
recipient: string;
|
||||||
|
subject: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FetchResult {
|
||||||
|
status: "success" | "failed";
|
||||||
|
error: string | null;
|
||||||
|
workflowId: string;
|
||||||
|
workflowStatus: string;
|
||||||
|
query: string;
|
||||||
|
country: string;
|
||||||
|
productKeywords: string | null;
|
||||||
|
completedAt: string | null;
|
||||||
|
summary: LeadSummary | null;
|
||||||
|
businesses: Business[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExportResult {
|
||||||
|
status: "success" | "failed";
|
||||||
|
error: string | null;
|
||||||
|
workflowId: string;
|
||||||
|
totalDrafts: number;
|
||||||
|
exportedCount: number;
|
||||||
|
bundleUrl: string | null;
|
||||||
|
files: ExportedFile[];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
/**
|
||||||
|
* Create a zip buffer from named text files.
|
||||||
|
* Uses Bun built-in zlib for deflate.
|
||||||
|
*/
|
||||||
|
export async function createZipBundle(
|
||||||
|
files: { name: string; content: string }[],
|
||||||
|
): Promise<Buffer> {
|
||||||
|
// Minimal ZIP format implementation (store method, no compression for simplicity)
|
||||||
|
const entries: { name: Buffer; data: Buffer; offset: number }[] = [];
|
||||||
|
const parts: Buffer[] = [];
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const name = Buffer.from(file.name, "utf-8");
|
||||||
|
const data = Buffer.from(file.content, "utf-8");
|
||||||
|
|
||||||
|
// Local file header (30 bytes + name + data)
|
||||||
|
const localHeader = Buffer.alloc(30);
|
||||||
|
localHeader.writeUInt32LE(0x04034b50, 0); // signature
|
||||||
|
localHeader.writeUInt16LE(20, 4); // version needed
|
||||||
|
localHeader.writeUInt16LE(0, 6); // flags
|
||||||
|
localHeader.writeUInt16LE(0, 8); // compression (store)
|
||||||
|
localHeader.writeUInt16LE(0, 10); // mod time
|
||||||
|
localHeader.writeUInt16LE(0, 12); // mod date
|
||||||
|
localHeader.writeUInt32LE(crc32(data), 14); // crc-32
|
||||||
|
localHeader.writeUInt32LE(data.length, 18); // compressed size
|
||||||
|
localHeader.writeUInt32LE(data.length, 22); // uncompressed size
|
||||||
|
localHeader.writeUInt16LE(name.length, 26); // filename length
|
||||||
|
localHeader.writeUInt16LE(0, 28); // extra field length
|
||||||
|
|
||||||
|
entries.push({ name, data, offset });
|
||||||
|
parts.push(localHeader, name, data);
|
||||||
|
offset += 30 + name.length + data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Central directory
|
||||||
|
const cdStart = offset;
|
||||||
|
for (const entry of entries) {
|
||||||
|
const cdHeader = Buffer.alloc(46);
|
||||||
|
cdHeader.writeUInt32LE(0x02014b50, 0); // signature
|
||||||
|
cdHeader.writeUInt16LE(20, 4); // version made by
|
||||||
|
cdHeader.writeUInt16LE(20, 6); // version needed
|
||||||
|
cdHeader.writeUInt16LE(0, 8); // flags
|
||||||
|
cdHeader.writeUInt16LE(0, 10); // compression
|
||||||
|
cdHeader.writeUInt16LE(0, 12); // mod time
|
||||||
|
cdHeader.writeUInt16LE(0, 14); // mod date
|
||||||
|
cdHeader.writeUInt32LE(crc32(entry.data), 16); // crc-32
|
||||||
|
cdHeader.writeUInt32LE(entry.data.length, 20); // compressed size
|
||||||
|
cdHeader.writeUInt32LE(entry.data.length, 24); // uncompressed size
|
||||||
|
cdHeader.writeUInt16LE(entry.name.length, 28); // filename length
|
||||||
|
cdHeader.writeUInt16LE(0, 30); // extra field length
|
||||||
|
cdHeader.writeUInt16LE(0, 32); // comment length
|
||||||
|
cdHeader.writeUInt16LE(0, 34); // disk number start
|
||||||
|
cdHeader.writeUInt16LE(0, 36); // internal attrs
|
||||||
|
cdHeader.writeUInt32LE(0, 38); // external attrs
|
||||||
|
cdHeader.writeUInt32LE(entry.offset, 42); // local header offset
|
||||||
|
|
||||||
|
parts.push(cdHeader, entry.name);
|
||||||
|
offset += 46 + entry.name.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cdSize = offset - cdStart;
|
||||||
|
|
||||||
|
// End of central directory
|
||||||
|
const eocd = Buffer.alloc(22);
|
||||||
|
eocd.writeUInt32LE(0x06054b50, 0); // signature
|
||||||
|
eocd.writeUInt16LE(0, 4); // disk number
|
||||||
|
eocd.writeUInt16LE(0, 6); // cd disk number
|
||||||
|
eocd.writeUInt16LE(entries.length, 8); // entries on disk
|
||||||
|
eocd.writeUInt16LE(entries.length, 10); // total entries
|
||||||
|
eocd.writeUInt32LE(cdSize, 12); // cd size
|
||||||
|
eocd.writeUInt32LE(cdStart, 16); // cd offset
|
||||||
|
eocd.writeUInt16LE(0, 20); // comment length
|
||||||
|
parts.push(eocd);
|
||||||
|
|
||||||
|
return Buffer.concat(parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** CRC-32 lookup table */
|
||||||
|
const crcTable: Uint32Array = (() => {
|
||||||
|
const table = new Uint32Array(256);
|
||||||
|
for (let i = 0; i < 256; i++) {
|
||||||
|
let c = i;
|
||||||
|
for (let j = 0; j < 8; j++) {
|
||||||
|
c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
|
||||||
|
}
|
||||||
|
table[i] = c;
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
})();
|
||||||
|
|
||||||
|
function crc32(buf: Buffer): number {
|
||||||
|
let crc = 0xFFFFFFFF;
|
||||||
|
for (let i = 0; i < buf.length; i++) {
|
||||||
|
crc = crcTable[(crc ^ buf[i]) & 0xFF] ^ (crc >>> 8);
|
||||||
|
}
|
||||||
|
return (crc ^ 0xFFFFFFFF) >>> 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue