test: tsgo
This commit is contained in:
239
.github/workflows/sdk-publish.yml
vendored
Normal file
239
.github/workflows/sdk-publish.yml
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
name: SDK Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'packages/autumn-js/**'
|
||||
- 'packages/openapi/**'
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry-run:
|
||||
description: 'Dry run (no actual publish)'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: choice
|
||||
options:
|
||||
- 'true'
|
||||
- 'false'
|
||||
test-package:
|
||||
description: 'Publish to @useautumn/js-test instead'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: choice
|
||||
options:
|
||||
- 'true'
|
||||
- 'false'
|
||||
version-bump:
|
||||
description: 'Version bump type (for manual triggers)'
|
||||
required: false
|
||||
default: 'patch'
|
||||
type: choice
|
||||
options:
|
||||
- 'patch'
|
||||
- 'minor'
|
||||
- 'major'
|
||||
|
||||
env:
|
||||
PACKAGE_DIR: packages/autumn-js
|
||||
REAL_PACKAGE_NAME: autumn-js
|
||||
TEST_PACKAGE_NAME: '@useautumn/js-test'
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Build and Publish
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Set up Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.2
|
||||
|
||||
- name: Set up Node.js (for npm OIDC)
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22.14.0'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Determine version bump type
|
||||
id: version-type
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
# Manual trigger - use input
|
||||
echo "bump=${{ github.event.inputs.version-bump }}" >> $GITHUB_OUTPUT
|
||||
echo "Using manual version bump: ${{ github.event.inputs.version-bump }}"
|
||||
else
|
||||
# Auto trigger - parse commit message
|
||||
COMMIT_MSG=$(git log -1 --pretty=%B)
|
||||
echo "Commit message: $COMMIT_MSG"
|
||||
|
||||
if echo "$COMMIT_MSG" | grep -qE "^major:|BREAKING CHANGE"; then
|
||||
echo "bump=major" >> $GITHUB_OUTPUT
|
||||
echo "Detected major version bump"
|
||||
elif echo "$COMMIT_MSG" | grep -qE "^minor:|^feat:"; then
|
||||
echo "bump=minor" >> $GITHUB_OUTPUT
|
||||
echo "Detected minor version bump"
|
||||
elif echo "$COMMIT_MSG" | grep -qE "^fix:|^patch:"; then
|
||||
echo "bump=patch" >> $GITHUB_OUTPUT
|
||||
echo "Detected patch version bump"
|
||||
else
|
||||
echo "bump=skip" >> $GITHUB_OUTPUT
|
||||
echo "No version bump pattern detected, skipping publish"
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Get current version from tags
|
||||
if: steps.version-type.outputs.bump != 'skip'
|
||||
id: current-version
|
||||
run: |
|
||||
# Get the latest tag for autumn-js
|
||||
LATEST_TAG=$(git tag -l "autumn-js-v*" --sort=-v:refname | head -n 1)
|
||||
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
# No tags yet, start at 1.0.0
|
||||
echo "current=1.0.0" >> $GITHUB_OUTPUT
|
||||
echo "No existing tags found, starting at 1.0.0"
|
||||
else
|
||||
# Extract version from tag (autumn-js-v1.2.3 -> 1.2.3)
|
||||
VERSION=${LATEST_TAG#autumn-js-v}
|
||||
echo "current=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Current version from tag: $VERSION"
|
||||
fi
|
||||
|
||||
- name: Calculate next version
|
||||
if: steps.version-type.outputs.bump != 'skip'
|
||||
id: next-version
|
||||
run: |
|
||||
CURRENT="${{ steps.current-version.outputs.current }}"
|
||||
BUMP="${{ steps.version-type.outputs.bump }}"
|
||||
|
||||
# Parse semver
|
||||
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
|
||||
|
||||
case "$BUMP" in
|
||||
major)
|
||||
MAJOR=$((MAJOR + 1))
|
||||
MINOR=0
|
||||
PATCH=0
|
||||
;;
|
||||
minor)
|
||||
MINOR=$((MINOR + 1))
|
||||
PATCH=0
|
||||
;;
|
||||
patch)
|
||||
PATCH=$((PATCH + 1))
|
||||
;;
|
||||
esac
|
||||
|
||||
NEXT_VERSION="${MAJOR}.${MINOR}.${PATCH}"
|
||||
echo "version=$NEXT_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Next version: $NEXT_VERSION"
|
||||
|
||||
- name: Determine package name
|
||||
if: steps.version-type.outputs.bump != 'skip'
|
||||
id: package
|
||||
run: |
|
||||
if [ "${{ github.event.inputs.test-package }}" = "true" ]; then
|
||||
echo "name=${{ env.TEST_PACKAGE_NAME }}" >> $GITHUB_OUTPUT
|
||||
echo "Publishing to test package: ${{ env.TEST_PACKAGE_NAME }}"
|
||||
else
|
||||
echo "name=${{ env.REAL_PACKAGE_NAME }}" >> $GITHUB_OUTPUT
|
||||
echo "Publishing to real package: ${{ env.REAL_PACKAGE_NAME }}"
|
||||
fi
|
||||
|
||||
- name: Update package.json version and name
|
||||
if: steps.version-type.outputs.bump != 'skip'
|
||||
run: |
|
||||
cd ${{ env.PACKAGE_DIR }}
|
||||
|
||||
# Update version
|
||||
jq --arg version "${{ steps.next-version.outputs.version }}" \
|
||||
'.version = $version' package.json > package.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
|
||||
# Update package name if using test package
|
||||
if [ "${{ github.event.inputs.test-package }}" = "true" ]; then
|
||||
jq --arg name "${{ env.TEST_PACKAGE_NAME }}" \
|
||||
'.name = $name' package.json > package.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
fi
|
||||
|
||||
echo "Updated package.json:"
|
||||
cat package.json | head -20
|
||||
|
||||
- name: Regenerate SDK from OpenAPI
|
||||
if: steps.version-type.outputs.bump != 'skip'
|
||||
env:
|
||||
SPEAKEASY_API_KEY: ${{ secrets.SPEAKEASY_API_KEY }}
|
||||
run: bun api
|
||||
|
||||
- name: Build SDK and autumn-js
|
||||
if: steps.version-type.outputs.bump != 'skip'
|
||||
run: bun js:build
|
||||
|
||||
- name: TypeScript check
|
||||
if: steps.version-type.outputs.bump != 'skip'
|
||||
run: bun js:ts
|
||||
|
||||
- name: Publish (dry-run)
|
||||
if: steps.version-type.outputs.bump != 'skip' && github.event.inputs.dry-run == 'true'
|
||||
run: |
|
||||
cd ${{ env.PACKAGE_DIR }}
|
||||
npm publish --dry-run --provenance --access public
|
||||
echo "✅ Dry run completed successfully"
|
||||
|
||||
- name: Publish to npm
|
||||
if: steps.version-type.outputs.bump != 'skip' && github.event.inputs.dry-run != 'true'
|
||||
run: |
|
||||
cd ${{ env.PACKAGE_DIR }}
|
||||
npm publish --provenance --access public
|
||||
echo "✅ Published ${{ steps.package.outputs.name }}@${{ steps.next-version.outputs.version }}"
|
||||
|
||||
- name: Create git tag
|
||||
if: steps.version-type.outputs.bump != 'skip' && github.event.inputs.dry-run != 'true' && github.event.inputs.test-package != 'true'
|
||||
run: |
|
||||
TAG_NAME="autumn-js-v${{ steps.next-version.outputs.version }}"
|
||||
git tag "$TAG_NAME"
|
||||
git push origin "$TAG_NAME"
|
||||
echo "✅ Created and pushed tag: $TAG_NAME"
|
||||
|
||||
- name: Summary
|
||||
if: steps.version-type.outputs.bump != 'skip'
|
||||
run: |
|
||||
echo "## SDK Publish Summary" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Package | ${{ steps.package.outputs.name }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Version | ${{ steps.next-version.outputs.version }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Bump Type | ${{ steps.version-type.outputs.bump }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Dry Run | ${{ github.event.inputs.dry-run || 'false' }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Trigger | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Skip notice
|
||||
if: steps.version-type.outputs.bump == 'skip'
|
||||
run: |
|
||||
echo "## SDK Publish Skipped" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "No version bump pattern detected in commit message." >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "To trigger a publish, use one of these commit message prefixes:" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- \`fix:\` or \`patch:\` for patch version" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- \`feat:\` or \`minor:\` for minor version" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- \`major:\` or \`BREAKING CHANGE\` for major version" >> $GITHUB_STEP_SUMMARY
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -31,7 +31,7 @@
|
||||
"files.exclude": {
|
||||
// "**/.claude": true,
|
||||
"**/.cursor": true,
|
||||
"**/.github": true,
|
||||
// "**/.github": true,
|
||||
"**/.superset": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ COPY shared/package.json ./shared/package.json
|
||||
COPY vite/package.json ./vite/package.json
|
||||
COPY scripts/package.json ./scripts/package.json
|
||||
COPY apps/checkout/package.json ./apps/checkout/package.json
|
||||
COPY packages/autumn-js/package.json ./packages/autumn-js/package.json
|
||||
COPY packages/openapi/package.json ./packages/openapi/package.json
|
||||
COPY packages/sdk/package.json ./packages/sdk/package.json
|
||||
|
||||
# Install dependencies
|
||||
RUN bun install --ignore-scripts
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"stripe": "19.3.0-beta.1",
|
||||
"drizzle-orm": "0.43.1",
|
||||
"drizzle-kit": "^0.31.1",
|
||||
"tsgo": "npm:@typescript/native-preview@7.0.0-dev.20260218.1",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260220.1",
|
||||
"@sentry/bun": "10.38.0",
|
||||
"@clickhouse/client": "1.11.2",
|
||||
"@date-fns/utc": "2.1.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "autumn-js",
|
||||
"description": "Autumn JS Library",
|
||||
"version": "1.0.0-beta.1",
|
||||
"version": "0.0.1",
|
||||
"repository": "github:useautumn/autumn-js",
|
||||
"homepage": "https://docs.useautumn.com",
|
||||
"main": "./dist/sdk/index.js",
|
||||
@@ -13,7 +13,7 @@
|
||||
"LICENSE.md"
|
||||
],
|
||||
"scripts": {
|
||||
"ts": "bunx tsgo --noEmit --skipLibCheck",
|
||||
"ts": "tsgo --noEmit --skipLibCheck",
|
||||
"build": "rm -rf dist && tsup",
|
||||
"prepublishOnly": "bun run build"
|
||||
},
|
||||
@@ -75,6 +75,9 @@
|
||||
],
|
||||
"author": "John Yeo",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"query-string": "^9.2.2",
|
||||
"rou3": "^0.6.1",
|
||||
@@ -90,8 +93,8 @@
|
||||
"next": "^15.2.3",
|
||||
"react-dom": "^19.1.0",
|
||||
"tsup": "^8.4.0",
|
||||
"tsgo": "catalog:",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.8.3",
|
||||
"@typescript/native-preview": "catalog:"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tanstack/react-query": "^5.0.0",
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"@types/node": "^24.0.3",
|
||||
"tsgo": "catalog:"
|
||||
"@typescript/native-preview": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ generation:
|
||||
schemas:
|
||||
allOfMergeStrategy: shallowMerge
|
||||
requestBodyFieldName: body
|
||||
versioningStrategy: automatic
|
||||
versioningStrategy: none
|
||||
persistentEdits: {}
|
||||
tests:
|
||||
generateTests: false
|
||||
|
||||
@@ -4,14 +4,14 @@ source "$(dirname "$0")/config.sh"
|
||||
export TEST_FILE_CONCURRENCY=2
|
||||
|
||||
BUN_PARALLEL_V2 \
|
||||
'integration/billing/update-subscription' \
|
||||
'integration/billing/migrations' \
|
||||
'integration/crud/customers' \
|
||||
'integration/billing/stripe-webhooks' \
|
||||
'integration/billing/autumn-webhooks' \
|
||||
'integration/cron' \
|
||||
'integration/crud/plans' \
|
||||
# 'integration/billing/update-subscription' \
|
||||
# 'integration/billing/attach' \
|
||||
# 'integration/billing/migrations' \
|
||||
# 'integration/crud/customers' \
|
||||
# 'integration/billing/stripe-webhooks' \
|
||||
# 'integration/billing/autumn-webhooks' \
|
||||
# 'integration/cron' \
|
||||
# 'integration/crud/plans' \
|
||||
|
||||
|
||||
# 'integration/billing/attach' \
|
||||
|
||||
@@ -72,7 +72,13 @@ interface IndividualTest {
|
||||
|
||||
interface TestFileResult {
|
||||
file: string;
|
||||
status: "pending" | "running" | "passed" | "failed" | "retrying";
|
||||
status:
|
||||
| "pending"
|
||||
| "running"
|
||||
| "passed"
|
||||
| "failed"
|
||||
| "retry_queued"
|
||||
| "retrying";
|
||||
tests: IndividualTest[];
|
||||
currentTest?: string;
|
||||
duration: number;
|
||||
@@ -451,9 +457,10 @@ function RunningFile({ result }: RunningFileProps) {
|
||||
|
||||
interface RetryingFileProps {
|
||||
result: TestFileResult;
|
||||
queuedCount: number;
|
||||
}
|
||||
|
||||
function RetryingFile({ result }: RetryingFileProps) {
|
||||
function RetryingFile({ result, queuedCount }: RetryingFileProps) {
|
||||
const fileName = basename(result.file);
|
||||
return (
|
||||
<Box>
|
||||
@@ -461,6 +468,7 @@ function RetryingFile({ result }: RetryingFileProps) {
|
||||
<Spinner />
|
||||
<Text color="yellow"> {fileName} </Text>
|
||||
<Text color="yellow">(retrying...)</Text>
|
||||
{queuedCount > 0 && <Text dimColor> ({queuedCount} more queued)</Text>}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -564,31 +572,33 @@ function TestRunnerApp({ testFiles, maxParallel }: TestRunnerAppProps) {
|
||||
);
|
||||
|
||||
if (failedFiles.length > 0) {
|
||||
// Mark files as retrying
|
||||
// Mark all failed files as queued for retry
|
||||
for (const result of failedFiles) {
|
||||
const queuedResult: TestFileResult = {
|
||||
...result,
|
||||
status: "retry_queued",
|
||||
};
|
||||
pendingRef.current.set(result.file, queuedResult);
|
||||
}
|
||||
dirtyRef.current = true;
|
||||
|
||||
// Run retries sequentially to avoid resource contention
|
||||
for (const result of failedFiles) {
|
||||
// Mark this specific file as actively retrying
|
||||
const retryingResult: TestFileResult = {
|
||||
...result,
|
||||
status: "retrying",
|
||||
};
|
||||
pendingRef.current.set(result.file, retryingResult);
|
||||
}
|
||||
dirtyRef.current = true;
|
||||
dirtyRef.current = true;
|
||||
|
||||
// Run retries sequentially to avoid resource contention
|
||||
const retryLimit = pLimit(1);
|
||||
const retryPromises = failedFiles.map((result) =>
|
||||
retryLimit(async () => {
|
||||
const retryResult = await runTestFile(result.file, updateResult, 2);
|
||||
// If passed on retry, mark it
|
||||
if (retryResult.status === "passed") {
|
||||
retryResult.passedOnRetry = true;
|
||||
pendingRef.current.set(result.file, retryResult);
|
||||
dirtyRef.current = true;
|
||||
}
|
||||
return retryResult;
|
||||
}),
|
||||
);
|
||||
await Promise.all(retryPromises);
|
||||
const retryResult = await runTestFile(result.file, updateResult, 2);
|
||||
if (retryResult.status === "passed") {
|
||||
retryResult.passedOnRetry = true;
|
||||
pendingRef.current.set(result.file, retryResult);
|
||||
dirtyRef.current = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark retry phase as complete so failed files can be emitted to static
|
||||
@@ -639,6 +649,9 @@ function TestRunnerApp({ testFiles, maxParallel }: TestRunnerAppProps) {
|
||||
const allResults = Array.from(results.values());
|
||||
const runningFiles = allResults.filter((r) => r.status === "running");
|
||||
const retryingFiles = allResults.filter((r) => r.status === "retrying");
|
||||
const retryQueuedFiles = allResults.filter(
|
||||
(r) => r.status === "retry_queued",
|
||||
);
|
||||
|
||||
const completedFiles = allResults.filter(
|
||||
(r) => r.status === "passed" || r.status === "failed",
|
||||
@@ -675,11 +688,15 @@ function TestRunnerApp({ testFiles, maxParallel }: TestRunnerAppProps) {
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Retrying files */}
|
||||
{/* Retrying file (only 1 at a time, show queued count) */}
|
||||
{retryingFiles.length > 0 && (
|
||||
<Box flexDirection="column">
|
||||
{retryingFiles.map((r) => (
|
||||
<RetryingFile key={r.file} result={r} />
|
||||
<RetryingFile
|
||||
key={r.file}
|
||||
result={r}
|
||||
queuedCount={retryQueuedFiles.length}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
@@ -701,7 +718,10 @@ function TestRunnerApp({ testFiles, maxParallel }: TestRunnerAppProps) {
|
||||
<Text dimColor> | {runningFiles.length} running</Text>
|
||||
)}
|
||||
{retryingFiles.length > 0 && (
|
||||
<Text color="yellow"> | {retryingFiles.length} retrying</Text>
|
||||
<Text color="yellow"> | 1 retrying</Text>
|
||||
)}
|
||||
{retryQueuedFiles.length > 0 && (
|
||||
<Text dimColor> | {retryQueuedFiles.length} queued</Text>
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
@@ -28,6 +28,7 @@ cusRouter.post("/clear_cache", ...handleClearCustomerCache);
|
||||
|
||||
cusRouter.get("/:customer_id", ...handleGetCustomerV2);
|
||||
cusRouter.post("/:customer_id", ...handleUpdateCustomer);
|
||||
cusRouter.patch("/:customer_id", ...handleUpdateCustomer);
|
||||
|
||||
cusRouter.delete("/:customer_id", ...handleDeleteCustomer);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
ApiVersion,
|
||||
BillingInterval,
|
||||
BillingMethod,
|
||||
type CreatePlanParamsInput,
|
||||
type CreatePlanParamsV2Input,
|
||||
ProductItemInterval,
|
||||
ResetInterval,
|
||||
TierInfinite,
|
||||
@@ -28,8 +28,8 @@ test.concurrent(`${chalk.yellowBright("rpc create: metered feature with monthly
|
||||
await autumnRpc.plans.delete(productId, { allVersions: true });
|
||||
} catch (_error) {}
|
||||
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsInput>({
|
||||
id: productId,
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsV2Input>({
|
||||
plan_id: productId,
|
||||
name: "RPC Metered Monthly",
|
||||
group,
|
||||
auto_enable: false,
|
||||
@@ -57,8 +57,8 @@ test.concurrent(`${chalk.yellowBright("rpc create: tiered usage pricing")}`, asy
|
||||
await autumnRpc.plans.delete(productId, { allVersions: true });
|
||||
} catch (_error) {}
|
||||
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsInput>({
|
||||
id: productId,
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsV2Input>({
|
||||
plan_id: productId,
|
||||
name: "RPC Tiered Pricing",
|
||||
group,
|
||||
auto_enable: false,
|
||||
@@ -96,8 +96,8 @@ test.concurrent(`${chalk.yellowBright("rpc create: validation rejects reset/pric
|
||||
|
||||
let err: { code?: string } | null = null;
|
||||
try {
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsInput>({
|
||||
id: productId,
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsV2Input>({
|
||||
plan_id: productId,
|
||||
name: "RPC Invalid Intervals",
|
||||
group,
|
||||
auto_enable: false,
|
||||
@@ -5,12 +5,12 @@ import {
|
||||
type ApiProduct,
|
||||
ApiVersion,
|
||||
BillingInterval,
|
||||
type CreatePlanParamsInput,
|
||||
type CreatePlanParamsV2Input,
|
||||
} from "@autumn/shared";
|
||||
import { TestFeature } from "@tests/setup/v2Features";
|
||||
import chalk from "chalk";
|
||||
import { AutumnRpcCli } from "@/external/autumn/autumnRpcCli.js";
|
||||
import { AutumnInt } from "@/external/autumn/autumnCli.js";
|
||||
import { AutumnRpcCli } from "@/external/autumn/autumnRpcCli.js";
|
||||
|
||||
const autumnRpc = new AutumnRpcCli({ version: ApiVersion.V2_1 });
|
||||
const autumnV1_2 = new AutumnInt({ version: ApiVersion.V1_2 });
|
||||
@@ -24,8 +24,11 @@ test.concurrent(`${chalk.yellowBright("rpc create: minimal plan (id + name only)
|
||||
await autumnRpc.plans.delete(productId, { allVersions: true });
|
||||
} catch (_error) {}
|
||||
|
||||
const created = await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsInput>({
|
||||
id: productId,
|
||||
const created = await autumnRpc.plans.create<
|
||||
ApiPlanV1,
|
||||
CreatePlanParamsV2Input
|
||||
>({
|
||||
plan_id: productId,
|
||||
name: "RPC Minimal Plan",
|
||||
group,
|
||||
auto_enable: false,
|
||||
@@ -47,8 +50,11 @@ test.concurrent(`${chalk.yellowBright("rpc create: with base price and flags")}`
|
||||
await autumnRpc.plans.delete(productId, { allVersions: true });
|
||||
} catch (_error) {}
|
||||
|
||||
const created = await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsInput>({
|
||||
id: productId,
|
||||
const created = await autumnRpc.plans.create<
|
||||
ApiPlanV1,
|
||||
CreatePlanParamsV2Input
|
||||
>({
|
||||
plan_id: productId,
|
||||
name: "RPC Flags Plan",
|
||||
group,
|
||||
add_on: true,
|
||||
@@ -76,8 +82,11 @@ test.concurrent(`${chalk.yellowBright("rpc create: boolean feature")}`, async ()
|
||||
await autumnRpc.plans.delete(productId, { allVersions: true });
|
||||
} catch (_error) {}
|
||||
|
||||
const created = await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsInput>({
|
||||
id: productId,
|
||||
const created = await autumnRpc.plans.create<
|
||||
ApiPlanV1,
|
||||
CreatePlanParamsV2Input
|
||||
>({
|
||||
plan_id: productId,
|
||||
name: "RPC Boolean Plan",
|
||||
group,
|
||||
auto_enable: false,
|
||||
@@ -86,7 +95,7 @@ test.concurrent(`${chalk.yellowBright("rpc create: boolean feature")}`, async ()
|
||||
|
||||
expect(created.items.length).toBeGreaterThanOrEqual(1);
|
||||
const booleanItem = created.items.find(
|
||||
(item: any) => item.feature_id === TestFeature.Dashboard,
|
||||
(item) => item.feature_id === TestFeature.Dashboard,
|
||||
);
|
||||
expect(booleanItem).toBeDefined();
|
||||
|
||||
@@ -29,13 +29,13 @@ test.concurrent(`${chalk.yellowBright("rpc get: get plan response in latest form
|
||||
ApiPlanV1Schema.parse(plan);
|
||||
|
||||
const messagesResponseItem = plan.items.find(
|
||||
(item: any) => item.feature_id === TestFeature.Messages,
|
||||
(item) => item.feature_id === TestFeature.Messages,
|
||||
);
|
||||
const wordsResponseItem = plan.items.find(
|
||||
(item: any) => item.feature_id === TestFeature.Words,
|
||||
(item) => item.feature_id === TestFeature.Words,
|
||||
);
|
||||
const creditsResponseItem = plan.items.find(
|
||||
(item: any) => item.feature_id === TestFeature.Credits,
|
||||
(item) => item.feature_id === TestFeature.Credits,
|
||||
);
|
||||
|
||||
expect(messagesResponseItem).toBeDefined();
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
type ApiProduct,
|
||||
ApiProductSchema,
|
||||
ApiVersion,
|
||||
type CreatePlanParamsInput,
|
||||
type CreatePlanParamsV2Input,
|
||||
} from "@autumn/shared";
|
||||
import { TestFeature } from "@tests/setup/v2Features.js";
|
||||
import chalk from "chalk";
|
||||
@@ -28,12 +28,10 @@ test.concurrent(`${chalk.yellowBright("rpc regression: rest list stays cross-ver
|
||||
|
||||
try {
|
||||
await autumnRpc.plans.delete(freeId, { allVersions: true });
|
||||
} catch (_error) {
|
||||
// no-op
|
||||
}
|
||||
} catch (_error) {}
|
||||
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsInput>({
|
||||
id: freeId,
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsV2Input>({
|
||||
plan_id: freeId,
|
||||
name: "RPC List Free",
|
||||
group: freeGroup,
|
||||
items: [{ feature_id: TestFeature.Credits, included: 500 }],
|
||||
@@ -0,0 +1,49 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import {
|
||||
type ApiPlanV1,
|
||||
ApiVersion,
|
||||
BillingInterval,
|
||||
type CreatePlanParamsV2Input,
|
||||
} from "@autumn/shared";
|
||||
import chalk from "chalk";
|
||||
import { AutumnRpcCli } from "@/external/autumn/autumnRpcCli.js";
|
||||
|
||||
const autumnRpc = new AutumnRpcCli({ version: ApiVersion.V2_1 });
|
||||
const getSuffix = () => Math.random().toString(36).slice(2, 9);
|
||||
|
||||
test.concurrent(`${chalk.yellowBright("rpc delete: create then delete plan successfully")}`, async () => {
|
||||
const productId = `rpc_delete_${getSuffix()}`;
|
||||
const group = `rpc_group_${productId}`;
|
||||
|
||||
try {
|
||||
await autumnRpc.plans.delete(productId, { allVersions: true });
|
||||
} catch (_error) {}
|
||||
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsV2Input>({
|
||||
plan_id: productId,
|
||||
name: "RPC Delete Test",
|
||||
group,
|
||||
auto_enable: false,
|
||||
price: {
|
||||
amount: 1900,
|
||||
interval: BillingInterval.Month,
|
||||
},
|
||||
});
|
||||
|
||||
const beforeDelete = await autumnRpc.plans.get<ApiPlanV1>(productId);
|
||||
expect(beforeDelete.id).toBe(productId);
|
||||
|
||||
const deleteResult = await autumnRpc.plans.delete(productId, {
|
||||
allVersions: false,
|
||||
});
|
||||
expect(deleteResult.success).toBe(true);
|
||||
|
||||
let err: unknown = null;
|
||||
try {
|
||||
await autumnRpc.plans.get(productId);
|
||||
} catch (error) {
|
||||
err = error;
|
||||
}
|
||||
|
||||
expect(err).toBeDefined();
|
||||
});
|
||||
@@ -1,10 +1,16 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { ApiVersion, FreeTrialDuration, ResetInterval } from "@autumn/shared";
|
||||
import {
|
||||
ApiVersion,
|
||||
type CreatePlanParamsV2Input,
|
||||
FreeTrialDuration,
|
||||
ResetInterval,
|
||||
type UpdatePlanParamsV2Input,
|
||||
} from "@autumn/shared";
|
||||
import { TestFeature } from "@tests/setup/v2Features";
|
||||
import ctx from "@tests/utils/testInitUtils/createTestContext.js";
|
||||
import chalk from "chalk";
|
||||
import { AutumnRpcCli } from "@/external/autumn/autumnRpcCli.js";
|
||||
import { AutumnInt } from "@/external/autumn/autumnCli.js";
|
||||
import { AutumnRpcCli } from "@/external/autumn/autumnRpcCli.js";
|
||||
import { ProductService } from "@/internal/products/ProductService.js";
|
||||
|
||||
const autumnV2 = new AutumnInt({ version: ApiVersion.V2_0 });
|
||||
@@ -13,6 +19,8 @@ const autumnRpc = new AutumnRpcCli({ version: ApiVersion.V2_1 });
|
||||
const { db, org, env } = ctx;
|
||||
const getSuffix = () => Math.random().toString(36).slice(2, 9);
|
||||
|
||||
type UpdatePlanRpcInput = Omit<UpdatePlanParamsV2Input, "plan_id">;
|
||||
|
||||
test.concurrent(`${chalk.yellowBright("rpc regression: rest update then rpc inverse keeps product stable")}`, async () => {
|
||||
const productId = `rpc_roundtrip_${getSuffix()}`;
|
||||
const baselineGroup = `rpc_regression_baseline_${productId}`;
|
||||
@@ -59,13 +67,16 @@ test.concurrent(`${chalk.yellowBright("rpc regression: rest update then rpc inve
|
||||
await autumnRpc.plans.delete(productId, { allVersions: true });
|
||||
} catch (_error) {}
|
||||
|
||||
await autumnRpc.plans.create({
|
||||
id: productId,
|
||||
await autumnRpc.plans.create<unknown, CreatePlanParamsV2Input>({
|
||||
plan_id: productId,
|
||||
...baseline,
|
||||
});
|
||||
|
||||
await autumnV2.products.update(productId, restUpdates);
|
||||
await autumnRpc.plans.update(productId, baseline);
|
||||
await autumnRpc.plans.update<unknown, UpdatePlanRpcInput>(
|
||||
productId,
|
||||
baseline,
|
||||
);
|
||||
|
||||
const finalFull = await ProductService.getFull({
|
||||
db,
|
||||
@@ -78,7 +89,8 @@ test.concurrent(`${chalk.yellowBright("rpc regression: rest update then rpc inve
|
||||
expect(finalFull.group).toBe(baseline.group);
|
||||
expect(finalFull.is_add_on).toBe(baseline.add_on);
|
||||
expect(
|
||||
finalFull.entitlements.find((ent) => ent.feature_id === TestFeature.Messages)
|
||||
?.allowance,
|
||||
finalFull.entitlements.find(
|
||||
(ent) => ent.feature_id === TestFeature.Messages,
|
||||
)?.allowance,
|
||||
).toBe(100);
|
||||
});
|
||||
@@ -1,5 +1,10 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { ApiVersion, BillingInterval, type CreatePlanParamsInput } from "@autumn/shared";
|
||||
import {
|
||||
type ApiPlanV1,
|
||||
ApiVersion,
|
||||
BillingInterval,
|
||||
type CreatePlanParamsV2Input,
|
||||
} from "@autumn/shared";
|
||||
import chalk from "chalk";
|
||||
import { AutumnRpcCli } from "@/external/autumn/autumnRpcCli.js";
|
||||
|
||||
@@ -14,8 +19,8 @@ test.concurrent(`${chalk.yellowBright("rpc delete: create then delete plan succe
|
||||
await autumnRpc.plans.delete(productId, { allVersions: true });
|
||||
} catch (_error) {}
|
||||
|
||||
await autumnRpc.plans.create<any, CreatePlanParamsInput>({
|
||||
id: productId,
|
||||
await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsV2Input>({
|
||||
plan_id: productId,
|
||||
name: "RPC Delete Test",
|
||||
group,
|
||||
auto_enable: false,
|
||||
@@ -25,7 +30,7 @@ test.concurrent(`${chalk.yellowBright("rpc delete: create then delete plan succe
|
||||
},
|
||||
});
|
||||
|
||||
const beforeDelete = await autumnRpc.plans.get<any>(productId);
|
||||
const beforeDelete = await autumnRpc.plans.get<ApiPlanV1>(productId);
|
||||
expect(beforeDelete.id).toBe(productId);
|
||||
|
||||
const deleteResult = await autumnRpc.plans.delete(productId, {
|
||||
@@ -33,7 +38,7 @@ test.concurrent(`${chalk.yellowBright("rpc delete: create then delete plan succe
|
||||
});
|
||||
expect(deleteResult.success).toBe(true);
|
||||
|
||||
let err: any = null;
|
||||
let err: unknown = null;
|
||||
try {
|
||||
await autumnRpc.plans.get(productId);
|
||||
} catch (error) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
type ApiPlanV1,
|
||||
ApiVersion,
|
||||
BillingInterval,
|
||||
type CreatePlanParamsV2Input,
|
||||
ResetInterval,
|
||||
type UpdatePlanParamsV2Input,
|
||||
} from "@autumn/shared";
|
||||
@@ -44,7 +45,7 @@ const createTestPlan = async (planId: string) => {
|
||||
await autumnRpc.plans.delete(planId, { allVersions: true });
|
||||
} catch (_error) {}
|
||||
|
||||
return await autumnRpc.plans.create<ApiPlanV1>({
|
||||
return await autumnRpc.plans.create<ApiPlanV1, CreatePlanParamsV2Input>({
|
||||
plan_id: planId,
|
||||
name: `Test Plan ${planId}`,
|
||||
group: `group_${planId}`,
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
type CreateProductV2ParamsInput,
|
||||
ProductItemInterval,
|
||||
ResetInterval,
|
||||
type UpdatePlanParamsInput,
|
||||
type UpdatePlanParamsV2Input,
|
||||
} from "@autumn/shared";
|
||||
import { TestFeature } from "@tests/setup/v2Features";
|
||||
import ctx from "@tests/utils/testInitUtils/createTestContext.js";
|
||||
@@ -19,6 +19,7 @@ const autumnRpc = new AutumnRpcCli({ version: ApiVersion.V2_1 });
|
||||
const autumnV1_2 = new AutumnInt({ version: ApiVersion.V1_2 });
|
||||
|
||||
const { db, org, env } = ctx;
|
||||
type UpdatePlanRpcInput = Omit<UpdatePlanParamsV2Input, "plan_id">;
|
||||
|
||||
test.concurrent(`${chalk.yellowBright("rpc update: match existing entitlement by feature_id (no entitlement_id)")}`, async () => {
|
||||
const productId = "rpc_update_match_1";
|
||||
@@ -52,7 +53,7 @@ test.concurrent(`${chalk.yellowBright("rpc update: match existing entitlement by
|
||||
?.id,
|
||||
).toBeDefined();
|
||||
|
||||
await autumnRpc.plans.update<ApiPlanV1, UpdatePlanParamsInput>(productId, {
|
||||
await autumnRpc.plans.update<ApiPlanV1, UpdatePlanRpcInput>(productId, {
|
||||
items: [
|
||||
{
|
||||
feature_id: TestFeature.Messages,
|
||||
@@ -96,7 +97,7 @@ test.concurrent(`${chalk.yellowBright("rpc update: match entitlement with same f
|
||||
],
|
||||
});
|
||||
|
||||
await autumnRpc.plans.update<ApiPlanV1, UpdatePlanParamsInput>(productId, {
|
||||
await autumnRpc.plans.update<ApiPlanV1, UpdatePlanRpcInput>(productId, {
|
||||
items: [
|
||||
{
|
||||
feature_id: TestFeature.Messages,
|
||||
@@ -140,7 +141,7 @@ test.concurrent(`${chalk.yellowBright("rpc update: create NEW entitlement when i
|
||||
],
|
||||
});
|
||||
|
||||
await autumnRpc.plans.update<ApiPlanV1, UpdatePlanParamsInput>(productId, {
|
||||
await autumnRpc.plans.update<ApiPlanV1, UpdatePlanRpcInput>(productId, {
|
||||
items: [
|
||||
{
|
||||
feature_id: TestFeature.Messages,
|
||||
@@ -189,7 +190,7 @@ test.concurrent(`${chalk.yellowBright("rpc update: handle multiple features with
|
||||
],
|
||||
});
|
||||
|
||||
await autumnRpc.plans.update<ApiPlanV1, UpdatePlanParamsInput>(productId, {
|
||||
await autumnRpc.plans.update<ApiPlanV1, UpdatePlanRpcInput>(productId, {
|
||||
items: [
|
||||
{
|
||||
feature_id: TestFeature.Messages,
|
||||
Reference in New Issue
Block a user