mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-21 15:36:50 -05:00
Compare commits
3 Commits
claude/fix
...
claude/pub
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22a5bff977 | ||
|
|
23adf06cb0 | ||
|
|
a8a2d23e63 |
76
.github/workflows/size-compare.yml
vendored
76
.github/workflows/size-compare.yml
vendored
@@ -50,8 +50,6 @@ jobs:
|
|||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
checkName: web
|
checkName: web
|
||||||
ref: ${{github.base_ref}}
|
ref: ${{github.base_ref}}
|
||||||
timeoutSeconds: 1200
|
|
||||||
intervalSeconds: 30
|
|
||||||
- name: Wait for ${{github.base_ref}} API build to succeed
|
- name: Wait for ${{github.base_ref}} API build to succeed
|
||||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||||
id: master-api-build
|
id: master-api-build
|
||||||
@@ -59,8 +57,6 @@ jobs:
|
|||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
checkName: api
|
checkName: api
|
||||||
ref: ${{github.base_ref}}
|
ref: ${{github.base_ref}}
|
||||||
timeoutSeconds: 1200
|
|
||||||
intervalSeconds: 30
|
|
||||||
- name: Wait for ${{github.base_ref}} CLI build to succeed
|
- name: Wait for ${{github.base_ref}} CLI build to succeed
|
||||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||||
id: master-cli-build
|
id: master-cli-build
|
||||||
@@ -68,8 +64,6 @@ jobs:
|
|||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
checkName: cli
|
checkName: cli
|
||||||
ref: ${{github.base_ref}}
|
ref: ${{github.base_ref}}
|
||||||
timeoutSeconds: 1200
|
|
||||||
intervalSeconds: 30
|
|
||||||
|
|
||||||
- name: Wait for PR build to succeed
|
- name: Wait for PR build to succeed
|
||||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||||
@@ -78,8 +72,6 @@ jobs:
|
|||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
checkName: web
|
checkName: web
|
||||||
ref: ${{github.event.pull_request.head.sha}}
|
ref: ${{github.event.pull_request.head.sha}}
|
||||||
timeoutSeconds: 1200
|
|
||||||
intervalSeconds: 30
|
|
||||||
- name: Wait for API PR build to succeed
|
- name: Wait for API PR build to succeed
|
||||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||||
id: wait-for-api-build
|
id: wait-for-api-build
|
||||||
@@ -87,8 +79,6 @@ jobs:
|
|||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
checkName: api
|
checkName: api
|
||||||
ref: ${{github.event.pull_request.head.sha}}
|
ref: ${{github.event.pull_request.head.sha}}
|
||||||
timeoutSeconds: 1200
|
|
||||||
intervalSeconds: 30
|
|
||||||
- name: Wait for CLI PR build to succeed
|
- name: Wait for CLI PR build to succeed
|
||||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||||
id: wait-for-cli-build
|
id: wait-for-cli-build
|
||||||
@@ -96,32 +86,12 @@ jobs:
|
|||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
checkName: cli
|
checkName: cli
|
||||||
ref: ${{github.event.pull_request.head.sha}}
|
ref: ${{github.event.pull_request.head.sha}}
|
||||||
timeoutSeconds: 1200
|
|
||||||
intervalSeconds: 30
|
|
||||||
|
|
||||||
- name: Report build failure
|
- name: Report build failure
|
||||||
if: |
|
if: steps.wait-for-web-build.outputs.conclusion == 'failure' || steps.wait-for-api-build.outputs.conclusion == 'failure' || steps.wait-for-cli-build.outputs.conclusion == 'failure'
|
||||||
steps.wait-for-web-build.outputs.conclusion == 'failure' ||
|
|
||||||
steps.wait-for-api-build.outputs.conclusion == 'failure' ||
|
|
||||||
steps.wait-for-cli-build.outputs.conclusion == 'failure' ||
|
|
||||||
steps.master-web-build.outputs.conclusion == 'failure' ||
|
|
||||||
steps.master-api-build.outputs.conclusion == 'failure' ||
|
|
||||||
steps.master-cli-build.outputs.conclusion == 'failure'
|
|
||||||
run: |
|
run: |
|
||||||
echo "Build failed on PR branch or ${{github.base_ref}}"
|
echo "Build failed on PR branch or ${{github.base_ref}}"
|
||||||
exit 1
|
exit 1
|
||||||
- name: Warn on incomplete builds
|
|
||||||
if: |
|
|
||||||
steps.wait-for-web-build.outputs.conclusion != 'success' ||
|
|
||||||
steps.wait-for-api-build.outputs.conclusion != 'success' ||
|
|
||||||
steps.wait-for-cli-build.outputs.conclusion != 'success' ||
|
|
||||||
steps.master-web-build.outputs.conclusion != 'success' ||
|
|
||||||
steps.master-api-build.outputs.conclusion != 'success' ||
|
|
||||||
steps.master-cli-build.outputs.conclusion != 'success'
|
|
||||||
run: |
|
|
||||||
echo "::warning::Some builds did not complete successfully. Bundle stats may be incomplete."
|
|
||||||
echo "Base branch - web: ${{ steps.master-web-build.outputs.conclusion }}, api: ${{ steps.master-api-build.outputs.conclusion }}, cli: ${{ steps.master-cli-build.outputs.conclusion }}"
|
|
||||||
echo "PR - web: ${{ steps.wait-for-web-build.outputs.conclusion }}, api: ${{ steps.wait-for-api-build.outputs.conclusion }}, cli: ${{ steps.wait-for-cli-build.outputs.conclusion }}"
|
|
||||||
|
|
||||||
- name: Download web build artifact from ${{github.base_ref}}
|
- name: Download web build artifact from ${{github.base_ref}}
|
||||||
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
||||||
@@ -132,7 +102,6 @@ jobs:
|
|||||||
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
||||||
name: build-stats
|
name: build-stats
|
||||||
path: base
|
path: base
|
||||||
if_no_artifact_found: warn
|
|
||||||
- name: Download API build artifact from ${{github.base_ref}}
|
- name: Download API build artifact from ${{github.base_ref}}
|
||||||
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
||||||
id: pr-api-build
|
id: pr-api-build
|
||||||
@@ -142,46 +111,41 @@ jobs:
|
|||||||
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
||||||
name: api-build-stats
|
name: api-build-stats
|
||||||
path: base
|
path: base
|
||||||
if_no_artifact_found: warn
|
|
||||||
- name: Download build stats from PR
|
- name: Download build stats from PR
|
||||||
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
||||||
with:
|
with:
|
||||||
commit: ${{github.event.pull_request.head.sha}}
|
pr: ${{github.event.pull_request.number}}
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
||||||
name: build-stats
|
name: build-stats
|
||||||
path: head
|
path: head
|
||||||
allow_forks: true
|
allow_forks: true
|
||||||
if_no_artifact_found: warn
|
|
||||||
- name: Download API stats from PR
|
- name: Download API stats from PR
|
||||||
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
||||||
with:
|
with:
|
||||||
commit: ${{github.event.pull_request.head.sha}}
|
pr: ${{github.event.pull_request.number}}
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
||||||
name: api-build-stats
|
name: api-build-stats
|
||||||
path: head
|
path: head
|
||||||
allow_forks: true
|
allow_forks: true
|
||||||
if_no_artifact_found: warn
|
|
||||||
- name: Download CLI build artifact from ${{github.base_ref}}
|
- name: Download CLI build artifact from ${{github.base_ref}}
|
||||||
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11
|
||||||
with:
|
with:
|
||||||
branch: ${{github.base_ref}}
|
branch: ${{github.base_ref}}
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
||||||
name: cli-build-stats
|
name: cli-build-stats
|
||||||
path: base
|
path: base
|
||||||
if_no_artifact_found: warn
|
|
||||||
- name: Download CLI stats from PR
|
- name: Download CLI stats from PR
|
||||||
uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f # v18
|
uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11
|
||||||
with:
|
with:
|
||||||
commit: ${{github.event.pull_request.head.sha}}
|
pr: ${{github.event.pull_request.number}}
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
workflow_conclusion: '' # ignore the conclusion of the workflow, since we already checked it
|
||||||
name: cli-build-stats
|
name: cli-build-stats
|
||||||
path: head
|
path: head
|
||||||
allow_forks: true
|
allow_forks: true
|
||||||
if_no_artifact_found: warn
|
|
||||||
- name: Strip content hashes from stats files
|
- name: Strip content hashes from stats files
|
||||||
run: |
|
run: |
|
||||||
if [ -f ./head/web-stats.json ]; then
|
if [ -f ./head/web-stats.json ]; then
|
||||||
@@ -198,31 +162,19 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
- name: Generate combined bundle stats comment
|
- name: Generate combined bundle stats comment
|
||||||
if: ${{ !cancelled() }}
|
|
||||||
id: generate-comment
|
|
||||||
run: |
|
run: |
|
||||||
ARGS=""
|
|
||||||
for bundle in "desktop-client=web-stats.json" "loot-core=loot-core-stats.json" "api=api-stats.json" "cli=cli-stats.json"; do
|
|
||||||
NAME="${bundle%%=*}"
|
|
||||||
FILE="${bundle#*=}"
|
|
||||||
if [ -f "./base/$FILE" ] && [ -f "./head/$FILE" ]; then
|
|
||||||
ARGS="$ARGS --base $NAME=./base/$FILE --head $NAME=./head/$FILE"
|
|
||||||
else
|
|
||||||
echo "::warning::Skipping $NAME: base or head stats file missing"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ -z "$ARGS" ]; then
|
|
||||||
echo "::warning::No stats files available, skipping comment generation"
|
|
||||||
echo "has_comment=false" >> "$GITHUB_OUTPUT"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
node packages/ci-actions/bin/bundle-stats-comment.mjs \
|
node packages/ci-actions/bin/bundle-stats-comment.mjs \
|
||||||
$ARGS \
|
--base desktop-client=./base/web-stats.json \
|
||||||
|
--base loot-core=./base/loot-core-stats.json \
|
||||||
|
--base api=./base/api-stats.json \
|
||||||
|
--base cli=./base/cli-stats.json \
|
||||||
|
--head desktop-client=./head/web-stats.json \
|
||||||
|
--head loot-core=./head/loot-core-stats.json \
|
||||||
|
--head api=./head/api-stats.json \
|
||||||
|
--head cli=./head/cli-stats.json \
|
||||||
--identifier combined \
|
--identifier combined \
|
||||||
--format pr-body > bundle-stats-comment.md
|
--format pr-body > bundle-stats-comment.md
|
||||||
echo "has_comment=true" >> "$GITHUB_OUTPUT"
|
|
||||||
- name: Post combined bundle stats comment
|
- name: Post combined bundle stats comment
|
||||||
if: ${{ !cancelled() && steps.generate-comment.outputs.has_comment == 'true' }}
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||||
|
|||||||
7
.husky/post-merge
Executable file
7
.husky/post-merge
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Run yarn install after pulling/merging (if yarn.lock changed)
|
||||||
|
|
||||||
|
if git diff --name-only ORIG_HEAD HEAD | grep -q "^yarn.lock$"; then
|
||||||
|
echo "yarn.lock changed — running yarn install..."
|
||||||
|
yarn install
|
||||||
|
fi
|
||||||
23
bin/package-mobile
Executable file
23
bin/package-mobile
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
ROOT=`dirname $0`
|
||||||
|
|
||||||
|
cd "$ROOT/.."
|
||||||
|
|
||||||
|
echo "Building web assets for mobile..."
|
||||||
|
|
||||||
|
# Build the browser version (same assets used by the Capacitor wrapper)
|
||||||
|
./bin/package-browser
|
||||||
|
|
||||||
|
echo "Syncing Capacitor iOS project..."
|
||||||
|
cd packages/mobile
|
||||||
|
npx cap sync ios
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "iOS project ready at: packages/mobile/ios/App/App.xcworkspace"
|
||||||
|
echo ""
|
||||||
|
echo "To build for the App Store:"
|
||||||
|
echo " 1. Open the project: yarn mobile:open"
|
||||||
|
echo " 2. Select your signing team in Xcode"
|
||||||
|
echo " 3. Archive: Product > Archive"
|
||||||
|
echo " 4. Distribute via App Store Connect"
|
||||||
@@ -39,6 +39,9 @@
|
|||||||
"build:server": "yarn build:browser && yarn workspace @actual-app/sync-server build",
|
"build:server": "yarn build:browser && yarn workspace @actual-app/sync-server build",
|
||||||
"build:browser": "./bin/package-browser",
|
"build:browser": "./bin/package-browser",
|
||||||
"build:desktop": "./bin/package-electron",
|
"build:desktop": "./bin/package-electron",
|
||||||
|
"build:mobile": "yarn build:browser && yarn workspace @actual-app/mobile sync",
|
||||||
|
"mobile:open": "yarn workspace @actual-app/mobile open",
|
||||||
|
"mobile:run:ios": "yarn workspace @actual-app/mobile run:ios",
|
||||||
"build:plugins-service": "yarn workspace plugins-service build",
|
"build:plugins-service": "yarn workspace plugins-service build",
|
||||||
"build:api": "yarn workspace @actual-app/api build",
|
"build:api": "yarn workspace @actual-app/api build",
|
||||||
"build:cli": "yarn build --scope=@actual-app/cli",
|
"build:cli": "yarn build --scope=@actual-app/cli",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* Heavily inspired by https://github.com/twk3/rollup-size-compare-action (MIT).
|
* Heavily inspired by https://github.com/twk3/rollup-size-compare-action (MIT).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { access, readFile } from 'node:fs/promises';
|
import { readFile } from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import process from 'node:process';
|
import process from 'node:process';
|
||||||
|
|
||||||
@@ -179,19 +179,8 @@ function parseArgs(argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadStats(filePath) {
|
async function loadStats(filePath) {
|
||||||
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
||||||
|
|
||||||
// Check if the file exists before trying to read it
|
|
||||||
try {
|
|
||||||
await access(absolutePath);
|
|
||||||
} catch {
|
|
||||||
console.error(
|
|
||||||
`[bundle-stats] Stats file not found: "${filePath}" — skipping`,
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const absolutePath = path.resolve(process.cwd(), filePath);
|
||||||
const fileContents = await readFile(absolutePath, 'utf8');
|
const fileContents = await readFile(absolutePath, 'utf8');
|
||||||
const parsed = JSON.parse(fileContents);
|
const parsed = JSON.parse(fileContents);
|
||||||
|
|
||||||
@@ -207,7 +196,7 @@ async function loadStats(filePath) {
|
|||||||
? error.message
|
? error.message
|
||||||
: 'Unknown error while parsing stats file';
|
: 'Unknown error while parsing stats file';
|
||||||
console.error(`[bundle-stats] Failed to parse "${filePath}": ${message}`);
|
console.error(`[bundle-stats] Failed to parse "${filePath}": ${message}`);
|
||||||
return null;
|
throw new Error(`Failed to load stats file "${filePath}": ${message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -698,13 +687,6 @@ async function main() {
|
|||||||
);
|
);
|
||||||
const headStats = await loadStats(section.headPath);
|
const headStats = await loadStats(section.headPath);
|
||||||
|
|
||||||
if (!baseStats || !headStats) {
|
|
||||||
console.error(
|
|
||||||
`[bundle-stats] Skipping section "${section.name}": missing ${!baseStats ? 'base' : 'head'} stats`,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const statsDiff = getStatsDiff(baseStats, headStats);
|
const statsDiff = getStatsDiff(baseStats, headStats);
|
||||||
const chunkDiff = getChunkModuleDiff(baseStats, headStats);
|
const chunkDiff = getChunkModuleDiff(baseStats, headStats);
|
||||||
|
|
||||||
|
|||||||
346
packages/cli/src/commands/query.test.ts
Normal file
346
packages/cli/src/commands/query.test.ts
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
import * as api from '@actual-app/api';
|
||||||
|
import { Command } from 'commander';
|
||||||
|
|
||||||
|
import { printOutput } from '../output';
|
||||||
|
|
||||||
|
import { parseOrderBy, registerQueryCommand } from './query';
|
||||||
|
|
||||||
|
vi.mock('@actual-app/api', () => {
|
||||||
|
const queryObj = {
|
||||||
|
select: vi.fn().mockReturnThis(),
|
||||||
|
filter: vi.fn().mockReturnThis(),
|
||||||
|
orderBy: vi.fn().mockReturnThis(),
|
||||||
|
limit: vi.fn().mockReturnThis(),
|
||||||
|
offset: vi.fn().mockReturnThis(),
|
||||||
|
groupBy: vi.fn().mockReturnThis(),
|
||||||
|
calculate: vi.fn().mockReturnThis(),
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
q: vi.fn().mockReturnValue(queryObj),
|
||||||
|
aqlQuery: vi.fn().mockResolvedValue({ data: [] }),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mock('../connection', () => ({
|
||||||
|
withConnection: vi.fn((_opts, fn) => fn()),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('../output', () => ({
|
||||||
|
printOutput: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
function createProgram(): Command {
|
||||||
|
const program = new Command();
|
||||||
|
program.option('--format <format>');
|
||||||
|
program.option('--server-url <url>');
|
||||||
|
program.option('--password <pw>');
|
||||||
|
program.option('--session-token <token>');
|
||||||
|
program.option('--sync-id <id>');
|
||||||
|
program.option('--data-dir <dir>');
|
||||||
|
program.option('--verbose');
|
||||||
|
program.exitOverride();
|
||||||
|
registerQueryCommand(program);
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run(args: string[]) {
|
||||||
|
const program = createProgram();
|
||||||
|
await program.parseAsync(['node', 'test', ...args]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getQueryObj() {
|
||||||
|
return vi.mocked(api.q).mock.results[0]?.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('parseOrderBy', () => {
|
||||||
|
it('parses plain field names', () => {
|
||||||
|
expect(parseOrderBy('date')).toEqual(['date']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parses field:desc', () => {
|
||||||
|
expect(parseOrderBy('date:desc')).toEqual([{ date: 'desc' }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parses field:asc', () => {
|
||||||
|
expect(parseOrderBy('amount:asc')).toEqual([{ amount: 'asc' }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parses multiple mixed fields', () => {
|
||||||
|
expect(parseOrderBy('date:desc,amount:asc,id')).toEqual([
|
||||||
|
{ date: 'desc' },
|
||||||
|
{ amount: 'asc' },
|
||||||
|
'id',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws on invalid direction', () => {
|
||||||
|
expect(() => parseOrderBy('date:backwards')).toThrow(
|
||||||
|
'Invalid order direction "backwards"',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws on empty field', () => {
|
||||||
|
expect(() => parseOrderBy('date,,amount')).toThrow('empty field');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('query commands', () => {
|
||||||
|
let stderrSpy: ReturnType<typeof vi.spyOn>;
|
||||||
|
let stdoutSpy: ReturnType<typeof vi.spyOn>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
stderrSpy = vi
|
||||||
|
.spyOn(process.stderr, 'write')
|
||||||
|
.mockImplementation(() => true);
|
||||||
|
stdoutSpy = vi
|
||||||
|
.spyOn(process.stdout, 'write')
|
||||||
|
.mockImplementation(() => true);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
stderrSpy.mockRestore();
|
||||||
|
stdoutSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('run', () => {
|
||||||
|
it('builds a basic query from flags', async () => {
|
||||||
|
await run([
|
||||||
|
'query',
|
||||||
|
'run',
|
||||||
|
'--table',
|
||||||
|
'transactions',
|
||||||
|
'--select',
|
||||||
|
'date,amount',
|
||||||
|
'--limit',
|
||||||
|
'5',
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(api.q).toHaveBeenCalledWith('transactions');
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.select).toHaveBeenCalledWith(['date', 'amount']);
|
||||||
|
expect(qObj.limit).toHaveBeenCalledWith(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects unknown table name', async () => {
|
||||||
|
await expect(
|
||||||
|
run(['query', 'run', '--table', 'nonexistent']),
|
||||||
|
).rejects.toThrow('Unknown table "nonexistent"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parses order-by with desc direction', async () => {
|
||||||
|
await run([
|
||||||
|
'query',
|
||||||
|
'run',
|
||||||
|
'--table',
|
||||||
|
'transactions',
|
||||||
|
'--order-by',
|
||||||
|
'date:desc,amount:asc',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.orderBy).toHaveBeenCalledWith([
|
||||||
|
{ date: 'desc' },
|
||||||
|
{ amount: 'asc' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes --filter as JSON', async () => {
|
||||||
|
await run([
|
||||||
|
'query',
|
||||||
|
'run',
|
||||||
|
'--table',
|
||||||
|
'transactions',
|
||||||
|
'--filter',
|
||||||
|
'{"amount":{"$lt":0}}',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.filter).toHaveBeenCalledWith({ amount: { $lt: 0 } });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--last flag', () => {
|
||||||
|
it('sets default table, select, orderBy, and limit', async () => {
|
||||||
|
await run(['query', 'run', '--last', '10']);
|
||||||
|
|
||||||
|
expect(api.q).toHaveBeenCalledWith('transactions');
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.select).toHaveBeenCalledWith([
|
||||||
|
'date',
|
||||||
|
'account.name',
|
||||||
|
'payee.name',
|
||||||
|
'category.name',
|
||||||
|
'amount',
|
||||||
|
'notes',
|
||||||
|
]);
|
||||||
|
expect(qObj.orderBy).toHaveBeenCalledWith([{ date: 'desc' }]);
|
||||||
|
expect(qObj.limit).toHaveBeenCalledWith(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows explicit --select override', async () => {
|
||||||
|
await run(['query', 'run', '--last', '5', '--select', 'date,amount']);
|
||||||
|
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.select).toHaveBeenCalledWith(['date', 'amount']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows explicit --order-by override', async () => {
|
||||||
|
await run(['query', 'run', '--last', '5', '--order-by', 'amount:asc']);
|
||||||
|
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.orderBy).toHaveBeenCalledWith([{ amount: 'asc' }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows --table transactions explicitly', async () => {
|
||||||
|
await run(['query', 'run', '--last', '5', '--table', 'transactions']);
|
||||||
|
|
||||||
|
expect(api.q).toHaveBeenCalledWith('transactions');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors if --table is not transactions', async () => {
|
||||||
|
await expect(
|
||||||
|
run(['query', 'run', '--last', '5', '--table', 'accounts']),
|
||||||
|
).rejects.toThrow('--last implies --table transactions');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors if --limit is also set', async () => {
|
||||||
|
await expect(
|
||||||
|
run(['query', 'run', '--last', '5', '--limit', '10']),
|
||||||
|
).rejects.toThrow('--last and --limit are mutually exclusive');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--count flag', () => {
|
||||||
|
it('uses calculate with $count', async () => {
|
||||||
|
vi.mocked(api.aqlQuery).mockResolvedValueOnce({ data: 42 });
|
||||||
|
|
||||||
|
await run(['query', 'run', '--table', 'transactions', '--count']);
|
||||||
|
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.calculate).toHaveBeenCalledWith({ $count: '*' });
|
||||||
|
expect(printOutput).toHaveBeenCalledWith({ count: 42 }, undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors if --select is also set', async () => {
|
||||||
|
await expect(
|
||||||
|
run([
|
||||||
|
'query',
|
||||||
|
'run',
|
||||||
|
'--table',
|
||||||
|
'transactions',
|
||||||
|
'--count',
|
||||||
|
'--select',
|
||||||
|
'date',
|
||||||
|
]),
|
||||||
|
).rejects.toThrow('--count and --select are mutually exclusive');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--where alias', () => {
|
||||||
|
it('works the same as --filter', async () => {
|
||||||
|
await run([
|
||||||
|
'query',
|
||||||
|
'run',
|
||||||
|
'--table',
|
||||||
|
'transactions',
|
||||||
|
'--where',
|
||||||
|
'{"amount":{"$gt":0}}',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.filter).toHaveBeenCalledWith({ amount: { $gt: 0 } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors if both --where and --filter are provided', async () => {
|
||||||
|
await expect(
|
||||||
|
run([
|
||||||
|
'query',
|
||||||
|
'run',
|
||||||
|
'--table',
|
||||||
|
'transactions',
|
||||||
|
'--where',
|
||||||
|
'{}',
|
||||||
|
'--filter',
|
||||||
|
'{}',
|
||||||
|
]),
|
||||||
|
).rejects.toThrow('--where and --filter are mutually exclusive');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--offset flag', () => {
|
||||||
|
it('passes offset through to query', async () => {
|
||||||
|
await run([
|
||||||
|
'query',
|
||||||
|
'run',
|
||||||
|
'--table',
|
||||||
|
'transactions',
|
||||||
|
'--offset',
|
||||||
|
'20',
|
||||||
|
'--limit',
|
||||||
|
'10',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.offset).toHaveBeenCalledWith(20);
|
||||||
|
expect(qObj.limit).toHaveBeenCalledWith(10);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--group-by flag', () => {
|
||||||
|
it('passes group-by through to query', async () => {
|
||||||
|
await run([
|
||||||
|
'query',
|
||||||
|
'run',
|
||||||
|
'--table',
|
||||||
|
'transactions',
|
||||||
|
'--group-by',
|
||||||
|
'category.name',
|
||||||
|
'--select',
|
||||||
|
'category.name,amount',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const qObj = getQueryObj();
|
||||||
|
expect(qObj.groupBy).toHaveBeenCalledWith(['category.name']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('tables subcommand', () => {
|
||||||
|
it('lists available tables', async () => {
|
||||||
|
await run(['query', 'tables']);
|
||||||
|
|
||||||
|
expect(printOutput).toHaveBeenCalledWith(
|
||||||
|
expect.arrayContaining([
|
||||||
|
{ name: 'transactions' },
|
||||||
|
{ name: 'accounts' },
|
||||||
|
{ name: 'categories' },
|
||||||
|
{ name: 'payees' },
|
||||||
|
]),
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fields subcommand', () => {
|
||||||
|
it('lists fields for a known table', async () => {
|
||||||
|
await run(['query', 'fields', 'accounts']);
|
||||||
|
|
||||||
|
const output = vi.mocked(printOutput).mock.calls[0][0] as Array<{
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
}>;
|
||||||
|
expect(output).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({ name: 'id', type: 'id' }),
|
||||||
|
expect.objectContaining({ name: 'name', type: 'string' }),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors on unknown table', async () => {
|
||||||
|
await expect(run(['query', 'fields', 'unknown'])).rejects.toThrow(
|
||||||
|
'Unknown table "unknown"',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -10,6 +10,115 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|||||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse order-by strings like "date:desc,amount:asc,id" into
|
||||||
|
* AQL orderBy format: [{ date: 'desc' }, { amount: 'asc' }, 'id']
|
||||||
|
*/
|
||||||
|
export function parseOrderBy(
|
||||||
|
input: string,
|
||||||
|
): Array<string | Record<string, string>> {
|
||||||
|
return input.split(',').map(part => {
|
||||||
|
const trimmed = part.trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
throw new Error('--order-by contains an empty field');
|
||||||
|
}
|
||||||
|
const colonIndex = trimmed.indexOf(':');
|
||||||
|
if (colonIndex === -1) {
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
|
const field = trimmed.slice(0, colonIndex).trim();
|
||||||
|
if (!field) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid order field in "${trimmed}". Field name cannot be empty.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const direction = trimmed.slice(colonIndex + 1);
|
||||||
|
if (direction !== 'asc' && direction !== 'desc') {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid order direction "${direction}" for field "${field}". Expected "asc" or "desc".`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return { [field]: direction };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Import schema from API once it exposes table/field metadata
|
||||||
|
const TABLE_SCHEMA: Record<
|
||||||
|
string,
|
||||||
|
Record<string, { type: string; ref?: string }>
|
||||||
|
> = {
|
||||||
|
transactions: {
|
||||||
|
id: { type: 'id' },
|
||||||
|
account: { type: 'id', ref: 'accounts' },
|
||||||
|
date: { type: 'date' },
|
||||||
|
amount: { type: 'integer' },
|
||||||
|
payee: { type: 'id', ref: 'payees' },
|
||||||
|
category: { type: 'id', ref: 'categories' },
|
||||||
|
notes: { type: 'string' },
|
||||||
|
imported_id: { type: 'string' },
|
||||||
|
transfer_id: { type: 'id' },
|
||||||
|
cleared: { type: 'boolean' },
|
||||||
|
reconciled: { type: 'boolean' },
|
||||||
|
starting_balance_flag: { type: 'boolean' },
|
||||||
|
imported_payee: { type: 'string' },
|
||||||
|
is_parent: { type: 'boolean' },
|
||||||
|
is_child: { type: 'boolean' },
|
||||||
|
parent_id: { type: 'id' },
|
||||||
|
sort_order: { type: 'float' },
|
||||||
|
schedule: { type: 'id', ref: 'schedules' },
|
||||||
|
'account.name': { type: 'string', ref: 'accounts' },
|
||||||
|
'payee.name': { type: 'string', ref: 'payees' },
|
||||||
|
'category.name': { type: 'string', ref: 'categories' },
|
||||||
|
'category.group.name': { type: 'string', ref: 'category_groups' },
|
||||||
|
},
|
||||||
|
accounts: {
|
||||||
|
id: { type: 'id' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
offbudget: { type: 'boolean' },
|
||||||
|
closed: { type: 'boolean' },
|
||||||
|
sort_order: { type: 'float' },
|
||||||
|
},
|
||||||
|
categories: {
|
||||||
|
id: { type: 'id' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
is_income: { type: 'boolean' },
|
||||||
|
group_id: { type: 'id', ref: 'category_groups' },
|
||||||
|
sort_order: { type: 'float' },
|
||||||
|
hidden: { type: 'boolean' },
|
||||||
|
'group.name': { type: 'string', ref: 'category_groups' },
|
||||||
|
},
|
||||||
|
payees: {
|
||||||
|
id: { type: 'id' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
transfer_acct: { type: 'id', ref: 'accounts' },
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
id: { type: 'id' },
|
||||||
|
stage: { type: 'string' },
|
||||||
|
conditions_op: { type: 'string' },
|
||||||
|
conditions: { type: 'json' },
|
||||||
|
actions: { type: 'json' },
|
||||||
|
},
|
||||||
|
schedules: {
|
||||||
|
id: { type: 'id' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
rule: { type: 'id', ref: 'rules' },
|
||||||
|
next_date: { type: 'date' },
|
||||||
|
completed: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const AVAILABLE_TABLES = Object.keys(TABLE_SCHEMA).join(', ');
|
||||||
|
|
||||||
|
const LAST_DEFAULT_SELECT = [
|
||||||
|
'date',
|
||||||
|
'account.name',
|
||||||
|
'payee.name',
|
||||||
|
'category.name',
|
||||||
|
'amount',
|
||||||
|
'notes',
|
||||||
|
];
|
||||||
|
|
||||||
function buildQueryFromFile(
|
function buildQueryFromFile(
|
||||||
parsed: Record<string, unknown>,
|
parsed: Record<string, unknown>,
|
||||||
fallbackTable: string | undefined,
|
fallbackTable: string | undefined,
|
||||||
@@ -27,34 +136,125 @@ function buildQueryFromFile(
|
|||||||
queryObj = queryObj.orderBy(parsed.orderBy);
|
queryObj = queryObj.orderBy(parsed.orderBy);
|
||||||
}
|
}
|
||||||
if (typeof parsed.limit === 'number') queryObj = queryObj.limit(parsed.limit);
|
if (typeof parsed.limit === 'number') queryObj = queryObj.limit(parsed.limit);
|
||||||
|
if (typeof parsed.offset === 'number') {
|
||||||
|
queryObj = queryObj.offset(parsed.offset);
|
||||||
|
}
|
||||||
|
if (Array.isArray(parsed.groupBy)) {
|
||||||
|
queryObj = queryObj.groupBy(parsed.groupBy);
|
||||||
|
}
|
||||||
return queryObj;
|
return queryObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildQueryFromFlags(cmdOpts: Record<string, string | undefined>) {
|
function buildQueryFromFlags(cmdOpts: Record<string, string | undefined>) {
|
||||||
if (!cmdOpts.table) {
|
const last = cmdOpts.last ? parseIntFlag(cmdOpts.last, '--last') : undefined;
|
||||||
throw new Error('--table is required (or use --file)');
|
|
||||||
}
|
|
||||||
let queryObj = api.q(cmdOpts.table);
|
|
||||||
|
|
||||||
if (cmdOpts.select) {
|
if (last !== undefined) {
|
||||||
|
if (cmdOpts.table && cmdOpts.table !== 'transactions') {
|
||||||
|
throw new Error(
|
||||||
|
'--last implies --table transactions. Cannot use with --table ' +
|
||||||
|
cmdOpts.table,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (cmdOpts.limit) {
|
||||||
|
throw new Error('--last and --limit are mutually exclusive');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const table =
|
||||||
|
cmdOpts.table ?? (last !== undefined ? 'transactions' : undefined);
|
||||||
|
if (!table) {
|
||||||
|
throw new Error('--table is required (or use --file or --last)');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(table in TABLE_SCHEMA)) {
|
||||||
|
throw new Error(
|
||||||
|
`Unknown table "${table}". Available tables: ${AVAILABLE_TABLES}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdOpts.where && cmdOpts.filter) {
|
||||||
|
throw new Error('--where and --filter are mutually exclusive');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdOpts.count && cmdOpts.select) {
|
||||||
|
throw new Error('--count and --select are mutually exclusive');
|
||||||
|
}
|
||||||
|
|
||||||
|
let queryObj = api.q(table);
|
||||||
|
|
||||||
|
if (cmdOpts.count) {
|
||||||
|
queryObj = queryObj.calculate({ $count: '*' });
|
||||||
|
} else if (cmdOpts.select) {
|
||||||
queryObj = queryObj.select(cmdOpts.select.split(','));
|
queryObj = queryObj.select(cmdOpts.select.split(','));
|
||||||
|
} else if (last !== undefined) {
|
||||||
|
queryObj = queryObj.select(LAST_DEFAULT_SELECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdOpts.filter) {
|
const filterStr = cmdOpts.filter ?? cmdOpts.where;
|
||||||
queryObj = queryObj.filter(JSON.parse(cmdOpts.filter));
|
if (filterStr) {
|
||||||
|
queryObj = queryObj.filter(JSON.parse(filterStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdOpts.orderBy) {
|
const orderByStr =
|
||||||
queryObj = queryObj.orderBy(cmdOpts.orderBy.split(','));
|
cmdOpts.orderBy ??
|
||||||
|
(last !== undefined && !cmdOpts.count ? 'date:desc' : undefined);
|
||||||
|
if (orderByStr) {
|
||||||
|
queryObj = queryObj.orderBy(parseOrderBy(orderByStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdOpts.limit) {
|
const limitVal =
|
||||||
queryObj = queryObj.limit(parseIntFlag(cmdOpts.limit, '--limit'));
|
last ??
|
||||||
|
(cmdOpts.limit ? parseIntFlag(cmdOpts.limit, '--limit') : undefined);
|
||||||
|
if (limitVal !== undefined) {
|
||||||
|
queryObj = queryObj.limit(limitVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdOpts.offset) {
|
||||||
|
queryObj = queryObj.offset(parseIntFlag(cmdOpts.offset, '--offset'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdOpts.groupBy) {
|
||||||
|
queryObj = queryObj.groupBy(cmdOpts.groupBy.split(','));
|
||||||
}
|
}
|
||||||
|
|
||||||
return queryObj;
|
return queryObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RUN_EXAMPLES = `
|
||||||
|
Examples:
|
||||||
|
# Show last 5 transactions (shortcut)
|
||||||
|
actual query run --last 5
|
||||||
|
|
||||||
|
# Transactions ordered by date descending
|
||||||
|
actual query run --table transactions --select "date,amount,payee.name" --order-by "date:desc" --limit 10
|
||||||
|
|
||||||
|
# Filter with JSON (negative amounts = expenses)
|
||||||
|
actual query run --table transactions --filter '{"amount":{"$lt":0}}' --limit 5
|
||||||
|
|
||||||
|
# Count transactions
|
||||||
|
actual query run --table transactions --count
|
||||||
|
|
||||||
|
# Group by category (use --file for aggregate expressions)
|
||||||
|
echo '{"table":"transactions","groupBy":["category.name"],"select":["category.name",{"amount":{"$sum":"$amount"}}]}' | actual query run --file -
|
||||||
|
|
||||||
|
# Pagination
|
||||||
|
actual query run --table transactions --order-by "date:desc" --limit 10 --offset 20
|
||||||
|
|
||||||
|
# Use --where (alias for --filter)
|
||||||
|
actual query run --table transactions --where '{"payee.name":"Grocery Store"}' --limit 5
|
||||||
|
|
||||||
|
# Read query from a JSON file
|
||||||
|
actual query run --file query.json
|
||||||
|
|
||||||
|
# Pipe query from stdin
|
||||||
|
echo '{"table":"transactions","limit":5}' | actual query run --file -
|
||||||
|
|
||||||
|
Available tables: ${AVAILABLE_TABLES}
|
||||||
|
Use "actual query tables" and "actual query fields <table>" for schema info.
|
||||||
|
|
||||||
|
Common filter operators: $eq, $ne, $lt, $lte, $gt, $gte, $like, $and, $or
|
||||||
|
See ActualQL docs for full reference: https://actualbudget.org/docs/api/actual-ql/`;
|
||||||
|
|
||||||
export function registerQueryCommand(program: Command) {
|
export function registerQueryCommand(program: Command) {
|
||||||
const query = program
|
const query = program
|
||||||
.command('query')
|
.command('query')
|
||||||
@@ -65,16 +265,34 @@ export function registerQueryCommand(program: Command) {
|
|||||||
.description('Execute an AQL query')
|
.description('Execute an AQL query')
|
||||||
.option(
|
.option(
|
||||||
'--table <table>',
|
'--table <table>',
|
||||||
'Table to query (transactions, accounts, categories, payees)',
|
'Table to query (use "actual query tables" to list available tables)',
|
||||||
)
|
)
|
||||||
.option('--select <fields>', 'Comma-separated fields to select')
|
.option('--select <fields>', 'Comma-separated fields to select')
|
||||||
.option('--filter <json>', 'Filter expression as JSON')
|
.option('--filter <json>', 'Filter as JSON (e.g. \'{"amount":{"$lt":0}}\')')
|
||||||
.option('--order-by <fields>', 'Comma-separated fields to order by')
|
.option(
|
||||||
|
'--where <json>',
|
||||||
|
'Alias for --filter (cannot be used together with --filter)',
|
||||||
|
)
|
||||||
|
.option(
|
||||||
|
'--order-by <fields>',
|
||||||
|
'Fields with optional direction: field1:desc,field2 (default: asc)',
|
||||||
|
)
|
||||||
.option('--limit <n>', 'Limit number of results')
|
.option('--limit <n>', 'Limit number of results')
|
||||||
|
.option('--offset <n>', 'Skip first N results (for pagination)')
|
||||||
|
.option(
|
||||||
|
'--last <n>',
|
||||||
|
'Show last N transactions (implies --table transactions, --order-by date:desc)',
|
||||||
|
)
|
||||||
|
.option('--count', 'Count matching rows instead of returning them')
|
||||||
|
.option(
|
||||||
|
'--group-by <fields>',
|
||||||
|
'Comma-separated fields to group by (use with aggregate selects)',
|
||||||
|
)
|
||||||
.option(
|
.option(
|
||||||
'--file <path>',
|
'--file <path>',
|
||||||
'Read full query object from JSON file (use - for stdin)',
|
'Read full query object from JSON file (use - for stdin)',
|
||||||
)
|
)
|
||||||
|
.addHelpText('after', RUN_EXAMPLES)
|
||||||
.action(async cmdOpts => {
|
.action(async cmdOpts => {
|
||||||
const opts = program.opts();
|
const opts = program.opts();
|
||||||
await withConnection(opts, async () => {
|
await withConnection(opts, async () => {
|
||||||
@@ -87,7 +305,40 @@ export function registerQueryCommand(program: Command) {
|
|||||||
: buildQueryFromFlags(cmdOpts);
|
: buildQueryFromFlags(cmdOpts);
|
||||||
|
|
||||||
const result = await api.aqlQuery(queryObj);
|
const result = await api.aqlQuery(queryObj);
|
||||||
printOutput(result, opts.format);
|
|
||||||
|
if (cmdOpts.count) {
|
||||||
|
printOutput({ count: result.data }, opts.format);
|
||||||
|
} else {
|
||||||
|
printOutput(result, opts.format);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
query
|
||||||
|
.command('tables')
|
||||||
|
.description('List available tables for querying')
|
||||||
|
.action(() => {
|
||||||
|
const opts = program.opts();
|
||||||
|
const tables = Object.keys(TABLE_SCHEMA).map(name => ({ name }));
|
||||||
|
printOutput(tables, opts.format);
|
||||||
|
});
|
||||||
|
|
||||||
|
query
|
||||||
|
.command('fields <table>')
|
||||||
|
.description('List fields for a given table')
|
||||||
|
.action((table: string) => {
|
||||||
|
const opts = program.opts();
|
||||||
|
const schema = TABLE_SCHEMA[table];
|
||||||
|
if (!schema) {
|
||||||
|
throw new Error(
|
||||||
|
`Unknown table "${table}". Available tables: ${Object.keys(TABLE_SCHEMA).join(', ')}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const fields = Object.entries(schema).map(([name, info]) => ({
|
||||||
|
name,
|
||||||
|
type: info.type,
|
||||||
|
...(info.ref ? { ref: info.ref } : {}),
|
||||||
|
}));
|
||||||
|
printOutput(fields, opts.format);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,3 +101,30 @@ or
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## CLI Usage
|
||||||
|
|
||||||
|
The examples above are shown in JavaScript. If you're using the [CLI tool](../cli.md), you can express many of the same queries with command-line flags. Here's how the JS patterns translate:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Select specific fields (JS: .select(['date', 'amount', 'payee.name']))
|
||||||
|
actual query run --table transactions --select "date,amount,payee.name"
|
||||||
|
|
||||||
|
# Filter by condition (JS: .filter({ amount: { $lt: 0 } }))
|
||||||
|
actual query run --table transactions --filter '{"amount":{"$lt":0}}'
|
||||||
|
|
||||||
|
# Order by field descending (JS: .orderBy([{ date: 'desc' }]))
|
||||||
|
actual query run --table transactions --order-by "date:desc"
|
||||||
|
|
||||||
|
# Search by month (JS: .filter({ date: { $transform: '$month', $eq: '2021-01' } }))
|
||||||
|
actual query run --table transactions --filter '{"date":{"$transform":"$month","$eq":"2021-01"}}'
|
||||||
|
|
||||||
|
# Group by payee with sum — use --file for aggregate queries
|
||||||
|
echo '{"table":"transactions","groupBy":["payee.name"],"select":["payee.name",{"amount":{"$sum":"$amount"}}]}' | actual query run --file -
|
||||||
|
|
||||||
|
# Count transactions (JS: .calculate({ $count: '*' }))
|
||||||
|
actual query run --table transactions --count
|
||||||
|
|
||||||
|
# Quick shortcut: last 10 transactions
|
||||||
|
actual query run --last 10
|
||||||
|
```
|
||||||
|
|||||||
@@ -274,16 +274,80 @@ actual schedules delete <id>
|
|||||||
|
|
||||||
### Query (ActualQL)
|
### Query (ActualQL)
|
||||||
|
|
||||||
Run queries using [ActualQL](./actual-ql/index.md):
|
Run queries using [ActualQL](./actual-ql/index.md).
|
||||||
|
|
||||||
|
#### Subcommands
|
||||||
|
|
||||||
|
| Subcommand | Description |
|
||||||
|
| ---------------------- | --------------------------------- |
|
||||||
|
| `query run` | Execute an AQL query |
|
||||||
|
| `query tables` | List available tables |
|
||||||
|
| `query fields <table>` | List fields and types for a table |
|
||||||
|
|
||||||
|
#### `query run` Options
|
||||||
|
|
||||||
|
| Option | Description |
|
||||||
|
| --------------------- | ------------------------------------------------------------------------------------------- |
|
||||||
|
| `--table <table>` | Table to query (use `actual query tables` to list) |
|
||||||
|
| `--select <fields>` | Comma-separated fields to select |
|
||||||
|
| `--filter <json>` | Filter as JSON (e.g. `'{"amount":{"$lt":0}}'`) |
|
||||||
|
| `--where <json>` | Alias for `--filter` (cannot be used together) |
|
||||||
|
| `--order-by <fields>` | Fields with optional direction: `field1:desc,field2` (default: asc) |
|
||||||
|
| `--limit <n>` | Limit number of results |
|
||||||
|
| `--offset <n>` | Skip first N results (for pagination) |
|
||||||
|
| `--last <n>` | Show last N transactions (shortcut: implies `--table transactions`, `--order-by date:desc`) |
|
||||||
|
| `--count` | Count matching rows instead of returning them |
|
||||||
|
| `--group-by <fields>` | Comma-separated fields to group by |
|
||||||
|
| `--file <path>` | Read query from JSON file (use `-` for stdin) |
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run a query (inline)
|
# Show last 5 transactions (convenience shortcut)
|
||||||
actual query run --table transactions --select "date,amount,payee" --filter '{"amount":{"$lt":0}}' --limit 10
|
actual query run --last 5
|
||||||
|
|
||||||
# Run a query (from file)
|
# Override default columns with --last
|
||||||
|
actual query run --last 10 --select "date,amount,notes"
|
||||||
|
|
||||||
|
# Transactions ordered by date descending with limit
|
||||||
|
actual query run --table transactions --select "date,amount,payee.name" --order-by "date:desc" --limit 10
|
||||||
|
|
||||||
|
# Filter with JSON — negative amounts (expenses)
|
||||||
|
actual query run --table transactions --filter '{"amount":{"$lt":0}}' --limit 5
|
||||||
|
|
||||||
|
# Use --where (alias for --filter, more intuitive for SQL users)
|
||||||
|
actual query run --table transactions --where '{"payee.name":"Grocery Store"}' --limit 5
|
||||||
|
|
||||||
|
# Count all transactions
|
||||||
|
actual query run --table transactions --count
|
||||||
|
|
||||||
|
# Count with a filter
|
||||||
|
actual query run --table transactions --filter '{"category.name":"Groceries"}' --count
|
||||||
|
|
||||||
|
# Group by category with aggregate (use --file for aggregate expressions)
|
||||||
|
echo '{"table":"transactions","groupBy":["category.name"],"select":["category.name",{"amount":{"$sum":"$amount"}}]}' | actual query run --file -
|
||||||
|
|
||||||
|
# Pagination: skip first 20, show next 10
|
||||||
|
actual query run --table transactions --order-by "date:desc" --limit 10 --offset 20
|
||||||
|
|
||||||
|
# Multi-field ordering
|
||||||
|
actual query run --table transactions --order-by "date:desc,amount:asc" --limit 10
|
||||||
|
|
||||||
|
# Run a query from a JSON file
|
||||||
actual query run --file query.json
|
actual query run --file query.json
|
||||||
|
|
||||||
|
# Pipe query from stdin
|
||||||
|
echo '{"table":"transactions","select":["date","amount"],"limit":5}' | actual query run --file -
|
||||||
|
|
||||||
|
# List available tables
|
||||||
|
actual query tables
|
||||||
|
|
||||||
|
# List fields for a table
|
||||||
|
actual query fields transactions
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See [ActualQL](./actual-ql/index.md) for full filter/function reference including `$transform`, `$month`, `$year`, and aggregate functions.
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
7
packages/mobile/.gitignore
vendored
Normal file
7
packages/mobile/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# iOS build artifacts
|
||||||
|
ios/App/Pods/
|
||||||
|
ios/App/DerivedData/
|
||||||
|
ios/App/build/
|
||||||
|
|
||||||
|
# Node modules are at root level
|
||||||
|
node_modules/
|
||||||
46
packages/mobile/capacitor.config.ts
Normal file
46
packages/mobile/capacitor.config.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import type { CapacitorConfig } from '@capacitor/cli';
|
||||||
|
|
||||||
|
const config: CapacitorConfig = {
|
||||||
|
appId: 'org.actualbudget.mobile',
|
||||||
|
appName: 'Actual Budget',
|
||||||
|
// Point to the desktop-client build output
|
||||||
|
webDir: '../desktop-client/build',
|
||||||
|
server: {
|
||||||
|
// Serve from localhost to enable COOP/COEP headers,
|
||||||
|
// which are required for SharedArrayBuffer (used by absurd-sql).
|
||||||
|
// On iOS, this uses WKURLSchemeHandler with the http scheme,
|
||||||
|
// allowing cross-origin isolation to work in WKWebView.
|
||||||
|
iosScheme: 'http',
|
||||||
|
androidScheme: 'http',
|
||||||
|
},
|
||||||
|
ios: {
|
||||||
|
// Minimum iOS version that supports SharedArrayBuffer in WKWebView
|
||||||
|
// with cross-origin isolation headers (iOS 15.2+)
|
||||||
|
minVersion: '16.0',
|
||||||
|
// Allow inline media playback (needed for some UI interactions)
|
||||||
|
allowsLinkPreview: false,
|
||||||
|
contentInset: 'always',
|
||||||
|
preferredContentMode: 'mobile',
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
SplashScreen: {
|
||||||
|
launchAutoHide: true,
|
||||||
|
launchShowDuration: 2000,
|
||||||
|
backgroundColor: '#5c3dbb',
|
||||||
|
showSpinner: false,
|
||||||
|
iosSpinnerStyle: 'small',
|
||||||
|
splashFullScreen: true,
|
||||||
|
splashImmersive: true,
|
||||||
|
},
|
||||||
|
Keyboard: {
|
||||||
|
resize: 'body',
|
||||||
|
resizeOnFullScreen: true,
|
||||||
|
},
|
||||||
|
StatusBar: {
|
||||||
|
style: 'LIGHT',
|
||||||
|
backgroundColor: '#5c3dbb',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
13
packages/mobile/ios/.gitignore
vendored
Normal file
13
packages/mobile/ios/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
App/build
|
||||||
|
App/Pods
|
||||||
|
App/output
|
||||||
|
App/App/public
|
||||||
|
DerivedData
|
||||||
|
xcuserdata
|
||||||
|
|
||||||
|
# Cordova plugins for Capacitor
|
||||||
|
capacitor-cordova-ios-plugins
|
||||||
|
|
||||||
|
# Generated Config files
|
||||||
|
App/App/capacitor.config.json
|
||||||
|
App/App/config.xml
|
||||||
416
packages/mobile/ios/App/App.xcodeproj/project.pbxproj
Normal file
416
packages/mobile/ios/App/App.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 48;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
|
||||||
|
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
|
||||||
|
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
||||||
|
A1B2C3D41000000000000001 /* ActualBridgeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D41000000000000002 /* ActualBridgeViewController.swift */; };
|
||||||
|
A1B2C3D41000000000000003 /* CrossOriginIsolationPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D41000000000000004 /* CrossOriginIsolationPlugin.swift */; };
|
||||||
|
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
|
||||||
|
504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
|
||||||
|
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
|
||||||
|
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
|
||||||
|
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
||||||
|
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
||||||
|
504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
A1B2C3D41000000000000002 /* ActualBridgeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActualBridgeViewController.swift; sourceTree = "<group>"; };
|
||||||
|
A1B2C3D41000000000000004 /* CrossOriginIsolationPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrossOriginIsolationPlugin.swift; sourceTree = "<group>"; };
|
||||||
|
504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
|
504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
|
504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
|
||||||
|
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
504EC3011FED79650016851F /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
504EC2FB1FED79650016851F = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
504EC3061FED79650016851F /* App */,
|
||||||
|
504EC3051FED79650016851F /* Products */,
|
||||||
|
7F8756D8B27F46E3366F6CEA /* Pods */,
|
||||||
|
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
504EC3051FED79650016851F /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
504EC3041FED79650016851F /* App.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
504EC3061FED79650016851F /* App */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
50379B222058CBB4000EE86E /* capacitor.config.json */,
|
||||||
|
504EC3071FED79650016851F /* AppDelegate.swift */,
|
||||||
|
A1B2C3D41000000000000002 /* ActualBridgeViewController.swift */,
|
||||||
|
A1B2C3D41000000000000004 /* CrossOriginIsolationPlugin.swift */,
|
||||||
|
504EC30B1FED79650016851F /* Main.storyboard */,
|
||||||
|
504EC30E1FED79650016851F /* Assets.xcassets */,
|
||||||
|
504EC3101FED79650016851F /* LaunchScreen.storyboard */,
|
||||||
|
504EC3131FED79650016851F /* Info.plist */,
|
||||||
|
2FAD9762203C412B000D30F8 /* config.xml */,
|
||||||
|
50B271D01FEDC1A000F3C39B /* public */,
|
||||||
|
);
|
||||||
|
path = App;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
7F8756D8B27F46E3366F6CEA /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */,
|
||||||
|
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
504EC3031FED79650016851F /* App */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */;
|
||||||
|
buildPhases = (
|
||||||
|
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */,
|
||||||
|
504EC3001FED79650016851F /* Sources */,
|
||||||
|
504EC3011FED79650016851F /* Frameworks */,
|
||||||
|
504EC3021FED79650016851F /* Resources */,
|
||||||
|
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = App;
|
||||||
|
productName = App;
|
||||||
|
productReference = 504EC3041FED79650016851F /* App.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
504EC2FC1FED79650016851F /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastSwiftUpdateCheck = 0920;
|
||||||
|
LastUpgradeCheck = 0920;
|
||||||
|
TargetAttributes = {
|
||||||
|
504EC3031FED79650016851F = {
|
||||||
|
CreatedOnToolsVersion = 9.2;
|
||||||
|
LastSwiftMigration = 1100;
|
||||||
|
ProvisioningStyle = Automatic;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
|
||||||
|
compatibilityVersion = "Xcode 8.0";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 504EC2FB1FED79650016851F;
|
||||||
|
packageReferences = (
|
||||||
|
);
|
||||||
|
productRefGroup = 504EC3051FED79650016851F /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
504EC3031FED79650016851F /* App */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
504EC3021FED79650016851F /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
|
||||||
|
50B271D11FEDC1A000F3C39B /* public in Resources */,
|
||||||
|
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
|
||||||
|
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
|
||||||
|
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
|
||||||
|
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
504EC3001FED79650016851F /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
|
||||||
|
A1B2C3D41000000000000001 /* ActualBridgeViewController.swift in Sources */,
|
||||||
|
A1B2C3D41000000000000003 /* CrossOriginIsolationPlugin.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
504EC30B1FED79650016851F /* Main.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
504EC30C1FED79650016851F /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
504EC3111FED79650016851F /* Base */,
|
||||||
|
);
|
||||||
|
name = LaunchScreen.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
504EC3141FED79650016851F /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
504EC3151FED79650016851F /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
504EC3171FED79650016851F /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.actualbudget.mobile;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
504EC3181FED79650016851F /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.actualbudget.mobile;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
504EC3141FED79650016851F /* Debug */,
|
||||||
|
504EC3151FED79650016851F /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
504EC3171FED79650016851F /* Debug */,
|
||||||
|
504EC3181FED79650016851F /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 504EC2FC1FED79650016851F /* Project object */;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
34
packages/mobile/ios/App/App/ActualBridgeViewController.swift
Normal file
34
packages/mobile/ios/App/App/ActualBridgeViewController.swift
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import UIKit
|
||||||
|
import Capacitor
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
/// Custom Capacitor bridge view controller that enables cross-origin isolation
|
||||||
|
/// for SharedArrayBuffer support in WKWebView.
|
||||||
|
///
|
||||||
|
/// SharedArrayBuffer is required by absurd-sql, which Actual Budget uses for
|
||||||
|
/// local-first SQLite storage in the browser/WebView environment.
|
||||||
|
class ActualBridgeViewController: CAPBridgeViewController {
|
||||||
|
|
||||||
|
override func webViewConfiguration(for instanceConfiguration: InstanceConfiguration) -> WKWebViewConfiguration {
|
||||||
|
let config = super.webViewConfiguration(for: instanceConfiguration)
|
||||||
|
|
||||||
|
// Enable SharedArrayBuffer support by setting crossOriginIsolation
|
||||||
|
// This is available on iOS 15.4+ and is required for absurd-sql
|
||||||
|
if #available(iOS 15.4, *) {
|
||||||
|
// Set preferences for cross-origin isolation
|
||||||
|
let prefs = config.preferences
|
||||||
|
prefs.isElementFullscreenEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow file access for local assets
|
||||||
|
config.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
|
||||||
|
config.setValue(true, forKey: "allowUniversalAccessFromFileURLs")
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
override func capacitorDidLoad() {
|
||||||
|
// Register the cross-origin isolation plugin
|
||||||
|
bridge?.registerPluginInstance(CrossOriginIsolationPlugin())
|
||||||
|
}
|
||||||
|
}
|
||||||
49
packages/mobile/ios/App/App/AppDelegate.swift
Normal file
49
packages/mobile/ios/App/App/AppDelegate.swift
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import UIKit
|
||||||
|
import Capacitor
|
||||||
|
|
||||||
|
@UIApplicationMain
|
||||||
|
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
|
||||||
|
var window: UIWindow?
|
||||||
|
|
||||||
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||||
|
// Override point for customization after application launch.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationWillResignActive(_ application: UIApplication) {
|
||||||
|
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||||
|
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||||
|
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||||
|
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||||
|
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||||
|
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationWillTerminate(_ application: UIApplication) {
|
||||||
|
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||||
|
}
|
||||||
|
|
||||||
|
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
||||||
|
// Called when the app was launched with a url. Feel free to add additional processing here,
|
||||||
|
// but if you want the App API to support tracking app url opens, make sure to keep this call
|
||||||
|
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||||
|
// Called when the app was launched with an activity, including Universal Links.
|
||||||
|
// Feel free to add additional processing here, but if you want the App API to support
|
||||||
|
// tracking app url opens, make sure to keep this call
|
||||||
|
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "AppIcon-512@2x.png",
|
||||||
|
"idiom": "universal",
|
||||||
|
"platform": "ios",
|
||||||
|
"size": "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info": {
|
||||||
|
"author": "xcode",
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"version": 1,
|
||||||
|
"author": "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
23
packages/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
vendored
Normal file
23
packages/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"idiom": "universal",
|
||||||
|
"filename": "splash-2732x2732-2.png",
|
||||||
|
"scale": "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "universal",
|
||||||
|
"filename": "splash-2732x2732-1.png",
|
||||||
|
"scale": "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "universal",
|
||||||
|
"filename": "splash-2732x2732.png",
|
||||||
|
"scale": "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info": {
|
||||||
|
"version": 1,
|
||||||
|
"author": "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
packages/mobile/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png
vendored
Normal file
BIN
packages/mobile/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
packages/mobile/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png
vendored
Normal file
BIN
packages/mobile/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
packages/mobile/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png
vendored
Normal file
BIN
packages/mobile/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17105"/>
|
||||||
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="EHf-IW-A2E">
|
||||||
|
<objects>
|
||||||
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
|
<imageView key="view" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Splash" id="snD-IY-ifK">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
</imageView>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
<resources>
|
||||||
|
<image name="Splash" width="1366" height="1366"/>
|
||||||
|
<systemColor name="systemBackgroundColor">
|
||||||
|
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</systemColor>
|
||||||
|
</resources>
|
||||||
|
</document>
|
||||||
19
packages/mobile/ios/App/App/Base.lproj/Main.storyboard
Normal file
19
packages/mobile/ios/App/App/Base.lproj/Main.storyboard
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<device id="retina4_7" orientation="portrait">
|
||||||
|
<adaptation id="fullscreen"/>
|
||||||
|
</device>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Bridge View Controller-->
|
||||||
|
<scene sceneID="tne-QT-ifu">
|
||||||
|
<objects>
|
||||||
|
<viewController id="BYZ-38-t0r" customClass="ActualBridgeViewController" customModule="App" sceneMemberID="viewController"/>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
39
packages/mobile/ios/App/App/CrossOriginIsolationPlugin.swift
Normal file
39
packages/mobile/ios/App/App/CrossOriginIsolationPlugin.swift
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import Foundation
|
||||||
|
import Capacitor
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
/// A Capacitor plugin that injects Cross-Origin-Opener-Policy and
|
||||||
|
/// Cross-Origin-Embedder-Policy headers into the WKWebView configuration.
|
||||||
|
///
|
||||||
|
/// These headers are required for SharedArrayBuffer support, which is used by
|
||||||
|
/// absurd-sql (the SQLite-in-browser engine) for offline local-first data storage.
|
||||||
|
///
|
||||||
|
/// On iOS 16+, WKWebView supports SharedArrayBuffer when COOP/COEP headers are present.
|
||||||
|
@objc(CrossOriginIsolationPlugin)
|
||||||
|
public class CrossOriginIsolationPlugin: CAPPlugin, CAPBridgedPlugin {
|
||||||
|
public let identifier = "CrossOriginIsolationPlugin"
|
||||||
|
public let jsName = "CrossOriginIsolation"
|
||||||
|
public let pluginMethods: [CAPPluginMethod] = []
|
||||||
|
|
||||||
|
override public func load() {
|
||||||
|
// Inject a script that sets SharedArrayBuffer override flag
|
||||||
|
// as a fallback for environments where COOP/COEP can't be set
|
||||||
|
let script = WKUserScript(
|
||||||
|
source: """
|
||||||
|
// Ensure SharedArrayBuffer override is set for Capacitor context
|
||||||
|
if (!window.SharedArrayBuffer) {
|
||||||
|
localStorage.setItem('SharedArrayBufferOverride', 'true');
|
||||||
|
console.log('[Capacitor] SharedArrayBuffer not available, override enabled');
|
||||||
|
} else {
|
||||||
|
console.log('[Capacitor] SharedArrayBuffer is available');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as running in Capacitor for platform detection
|
||||||
|
window.__ACTUAL_IS_CAPACITOR__ = true;
|
||||||
|
""",
|
||||||
|
injectionTime: .atDocumentStart,
|
||||||
|
forMainFrameOnly: true
|
||||||
|
)
|
||||||
|
bridge?.webView?.configuration.userContentController.addUserScript(script)
|
||||||
|
}
|
||||||
|
}
|
||||||
58
packages/mobile/ios/App/App/Info.plist
Normal file
58
packages/mobile/ios/App/App/Info.plist
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Actual Budget</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(MARKETING_VERSION)</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<true/>
|
||||||
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
<false/>
|
||||||
|
<key>NSAppTransportSecurity</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSAllowsLocalNetworking</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
23
packages/mobile/ios/App/Podfile
Normal file
23
packages/mobile/ios/App/Podfile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
|
||||||
|
|
||||||
|
platform :ios, '16.0'
|
||||||
|
use_frameworks!
|
||||||
|
|
||||||
|
# workaround to avoid Xcode caching of Pods that requires
|
||||||
|
# Product -> Clean Build Folder after new Cordova plugins installed
|
||||||
|
# Requires CocoaPods 1.6 or newer
|
||||||
|
install! 'cocoapods', :disable_input_output_paths => true
|
||||||
|
|
||||||
|
def capacitor_pods
|
||||||
|
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
|
||||||
|
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
|
||||||
|
end
|
||||||
|
|
||||||
|
target 'App' do
|
||||||
|
capacitor_pods
|
||||||
|
# Add your Pods here
|
||||||
|
end
|
||||||
|
|
||||||
|
post_install do |installer|
|
||||||
|
assertDeploymentTarget(installer)
|
||||||
|
end
|
||||||
24
packages/mobile/package.json
Normal file
24
packages/mobile/package.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@actual-app/mobile",
|
||||||
|
"version": "26.3.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "Actual Budget iOS app powered by Capacitor",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"build": "yarn workspace @actual-app/web build && npx cap sync ios",
|
||||||
|
"sync": "npx cap sync ios",
|
||||||
|
"open": "npx cap open ios",
|
||||||
|
"run:ios": "npx cap run ios"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@capacitor/app": "^7.0.0",
|
||||||
|
"@capacitor/core": "^7.0.0",
|
||||||
|
"@capacitor/ios": "^7.0.0",
|
||||||
|
"@capacitor/keyboard": "^7.0.0",
|
||||||
|
"@capacitor/splash-screen": "^7.0.0",
|
||||||
|
"@capacitor/status-bar": "^7.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@capacitor/cli": "^7.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
packages/mobile/tsconfig.json
Normal file
8
packages/mobile/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "."
|
||||||
|
},
|
||||||
|
"include": ["capacitor.config.ts"]
|
||||||
|
}
|
||||||
6
upcoming-release-notes/7240.md
Normal file
6
upcoming-release-notes/7240.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
category: Enhancements
|
||||||
|
authors: [MatissJanis]
|
||||||
|
---
|
||||||
|
|
||||||
|
cli: improved aql support
|
||||||
6
upcoming-release-notes/7248.md
Normal file
6
upcoming-release-notes/7248.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
category: Maintenance
|
||||||
|
authors: [MatissJanis]
|
||||||
|
---
|
||||||
|
|
||||||
|
Add post-merge hook to automatically install dependencies when yarn.lock changes after merges.
|
||||||
394
yarn.lock
394
yarn.lock
@@ -182,6 +182,20 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"@actual-app/mobile@workspace:packages/mobile":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@actual-app/mobile@workspace:packages/mobile"
|
||||||
|
dependencies:
|
||||||
|
"@capacitor/app": "npm:^7.0.0"
|
||||||
|
"@capacitor/cli": "npm:^7.0.0"
|
||||||
|
"@capacitor/core": "npm:^7.0.0"
|
||||||
|
"@capacitor/ios": "npm:^7.0.0"
|
||||||
|
"@capacitor/keyboard": "npm:^7.0.0"
|
||||||
|
"@capacitor/splash-screen": "npm:^7.0.0"
|
||||||
|
"@capacitor/status-bar": "npm:^7.0.0"
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@actual-app/sync-server@workspace:*, @actual-app/sync-server@workspace:packages/sync-server":
|
"@actual-app/sync-server@workspace:*, @actual-app/sync-server@workspace:packages/sync-server":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@actual-app/sync-server@workspace:packages/sync-server"
|
resolution: "@actual-app/sync-server@workspace:packages/sync-server"
|
||||||
@@ -2137,6 +2151,88 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@capacitor/app@npm:^7.0.0":
|
||||||
|
version: 7.1.2
|
||||||
|
resolution: "@capacitor/app@npm:7.1.2"
|
||||||
|
peerDependencies:
|
||||||
|
"@capacitor/core": ">=7.0.0"
|
||||||
|
checksum: 10/f48ebfca4e86cbf578a893cbfc9136b70af85a42638048467b32a68a98548b0713d524f7fe24ed0172acaa8d94324d185ba4e2d6e83608da84ce79f1cb38aafe
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@capacitor/cli@npm:^7.0.0":
|
||||||
|
version: 7.6.0
|
||||||
|
resolution: "@capacitor/cli@npm:7.6.0"
|
||||||
|
dependencies:
|
||||||
|
"@ionic/cli-framework-output": "npm:^2.2.8"
|
||||||
|
"@ionic/utils-subprocess": "npm:^3.0.1"
|
||||||
|
"@ionic/utils-terminal": "npm:^2.3.5"
|
||||||
|
commander: "npm:^12.1.0"
|
||||||
|
debug: "npm:^4.4.0"
|
||||||
|
env-paths: "npm:^2.2.0"
|
||||||
|
fs-extra: "npm:^11.2.0"
|
||||||
|
kleur: "npm:^4.1.5"
|
||||||
|
native-run: "npm:^2.0.3"
|
||||||
|
open: "npm:^8.4.0"
|
||||||
|
plist: "npm:^3.1.0"
|
||||||
|
prompts: "npm:^2.4.2"
|
||||||
|
rimraf: "npm:^6.0.1"
|
||||||
|
semver: "npm:^7.6.3"
|
||||||
|
tar: "npm:^7.5.3"
|
||||||
|
tslib: "npm:^2.8.1"
|
||||||
|
xml2js: "npm:^0.6.2"
|
||||||
|
bin:
|
||||||
|
cap: bin/capacitor
|
||||||
|
capacitor: bin/capacitor
|
||||||
|
checksum: 10/87d5a765df53548814b5aac2da15f4bd53fb0b5bd400e6837f906d7a486e59f88a0e67891a12f31c1acf89a210703396d5a90744aa68794aae04ca6ef47beba3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@capacitor/core@npm:^7.0.0":
|
||||||
|
version: 7.6.0
|
||||||
|
resolution: "@capacitor/core@npm:7.6.0"
|
||||||
|
dependencies:
|
||||||
|
tslib: "npm:^2.1.0"
|
||||||
|
checksum: 10/7eb5e45e8e5a39852b758c0fe3fab62df4af7ad903dd286395bdb1408a46eac0eb1a6c36d34b94f66f7c7263f026b543325fd973adf93ed0886d1b27b62c9f99
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@capacitor/ios@npm:^7.0.0":
|
||||||
|
version: 7.6.0
|
||||||
|
resolution: "@capacitor/ios@npm:7.6.0"
|
||||||
|
peerDependencies:
|
||||||
|
"@capacitor/core": ^7.6.0
|
||||||
|
checksum: 10/08ef3c1cf0085b1268d6320265ec04b1b48a0d53310e265b8cf2833a60de6ee9da01e4a92dbfc93e0259611cd3044f399164720955107e8c2a1caf3fa11baf41
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@capacitor/keyboard@npm:^7.0.0":
|
||||||
|
version: 7.0.5
|
||||||
|
resolution: "@capacitor/keyboard@npm:7.0.5"
|
||||||
|
peerDependencies:
|
||||||
|
"@capacitor/core": ">=7.0.0"
|
||||||
|
checksum: 10/c4588923e436c7ac0ddcba58437c7430d405e97da17a6c6e0a34e9d4a50f1be9f757ecacc748ae439b56de0c3b805d5d32819d010674385ac38002bfb3d58f55
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@capacitor/splash-screen@npm:^7.0.0":
|
||||||
|
version: 7.0.5
|
||||||
|
resolution: "@capacitor/splash-screen@npm:7.0.5"
|
||||||
|
peerDependencies:
|
||||||
|
"@capacitor/core": ">=7.0.0"
|
||||||
|
checksum: 10/6b4668150c9d82a5a4819139f5440a0040bd656178519a68b5ae8ef89be17a3eebe10b062903f76a0ee492b342c1d8975d400c62e0d4ea6de45bbfcf1c99c771
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@capacitor/status-bar@npm:^7.0.0":
|
||||||
|
version: 7.0.5
|
||||||
|
resolution: "@capacitor/status-bar@npm:7.0.5"
|
||||||
|
peerDependencies:
|
||||||
|
"@capacitor/core": ">=7.0.0"
|
||||||
|
checksum: 10/8a50eb8a4c14126469dde5604bb272c33472ee7a607e40a031f26adaff8de0ac72bb0a45575fe727084a9a5e87340dacb46f153e095c6cb147fbe76506bb98e4
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@chevrotain/cst-dts-gen@npm:11.0.3":
|
"@chevrotain/cst-dts-gen@npm:11.0.3":
|
||||||
version: 11.0.3
|
version: 11.0.3
|
||||||
resolution: "@chevrotain/cst-dts-gen@npm:11.0.3"
|
resolution: "@chevrotain/cst-dts-gen@npm:11.0.3"
|
||||||
@@ -4630,6 +4726,106 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@ionic/cli-framework-output@npm:^2.2.8":
|
||||||
|
version: 2.2.8
|
||||||
|
resolution: "@ionic/cli-framework-output@npm:2.2.8"
|
||||||
|
dependencies:
|
||||||
|
"@ionic/utils-terminal": "npm:2.3.5"
|
||||||
|
debug: "npm:^4.0.0"
|
||||||
|
tslib: "npm:^2.0.1"
|
||||||
|
checksum: 10/773cf0cdbd0fbb5709822b84c06a9e9cec6df5a87d9542bcc21a027a9434117e1d3f1a7d04fe11f252d9d232a5678d056ea80d2d4506e38a5f18fc563a990f34
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@ionic/utils-array@npm:2.1.6":
|
||||||
|
version: 2.1.6
|
||||||
|
resolution: "@ionic/utils-array@npm:2.1.6"
|
||||||
|
dependencies:
|
||||||
|
debug: "npm:^4.0.0"
|
||||||
|
tslib: "npm:^2.0.1"
|
||||||
|
checksum: 10/13d7b56906bb394a9362622c001578f0788f06ee2d8c724a51fb415cf4bdc1ccf1f92c2358935524f0089a660a4323d5f0bfa9403a0b3050ed921c039125b5e8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@ionic/utils-fs@npm:3.1.7, @ionic/utils-fs@npm:^3.1.7":
|
||||||
|
version: 3.1.7
|
||||||
|
resolution: "@ionic/utils-fs@npm:3.1.7"
|
||||||
|
dependencies:
|
||||||
|
"@types/fs-extra": "npm:^8.0.0"
|
||||||
|
debug: "npm:^4.0.0"
|
||||||
|
fs-extra: "npm:^9.0.0"
|
||||||
|
tslib: "npm:^2.0.1"
|
||||||
|
checksum: 10/65279a445b4499b9db40dae0c4eface0fdcd6ee95c7931ecb89fb097ee07e61e316ad13da7f495ee567d95dd0dddcbad9b1e46656676e22e51041dde62b06b9d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@ionic/utils-object@npm:2.1.6":
|
||||||
|
version: 2.1.6
|
||||||
|
resolution: "@ionic/utils-object@npm:2.1.6"
|
||||||
|
dependencies:
|
||||||
|
debug: "npm:^4.0.0"
|
||||||
|
tslib: "npm:^2.0.1"
|
||||||
|
checksum: 10/c545f09ede118a801c7eb4c794d4b479c574a98023b752421c0b18e340cb0f509aa7d7e92ef9b1048361e194a0b6f80df8922cd56bae8201d2fb796b71d87e60
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@ionic/utils-process@npm:2.1.12":
|
||||||
|
version: 2.1.12
|
||||||
|
resolution: "@ionic/utils-process@npm:2.1.12"
|
||||||
|
dependencies:
|
||||||
|
"@ionic/utils-object": "npm:2.1.6"
|
||||||
|
"@ionic/utils-terminal": "npm:2.3.5"
|
||||||
|
debug: "npm:^4.0.0"
|
||||||
|
signal-exit: "npm:^3.0.3"
|
||||||
|
tree-kill: "npm:^1.2.2"
|
||||||
|
tslib: "npm:^2.0.1"
|
||||||
|
checksum: 10/3a94eeb4cc7c05a2d3058e997a2ca05c50bf1a9d76e39b91659d0cbb402adbe2b24b8bc08d8b95bbab1703328dcc50c2e333b345700709ed2ec94e8d844d20c1
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@ionic/utils-stream@npm:3.1.7":
|
||||||
|
version: 3.1.7
|
||||||
|
resolution: "@ionic/utils-stream@npm:3.1.7"
|
||||||
|
dependencies:
|
||||||
|
debug: "npm:^4.0.0"
|
||||||
|
tslib: "npm:^2.0.1"
|
||||||
|
checksum: 10/23667cfeaa4f710e556cd4f055ae6a99a59bf9f83ed7224fea5cf82d2e0539b8d42c4bf133db82f8a2156c004145fdb2e252837388b552c5775126700bce4a95
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@ionic/utils-subprocess@npm:^3.0.1":
|
||||||
|
version: 3.0.1
|
||||||
|
resolution: "@ionic/utils-subprocess@npm:3.0.1"
|
||||||
|
dependencies:
|
||||||
|
"@ionic/utils-array": "npm:2.1.6"
|
||||||
|
"@ionic/utils-fs": "npm:3.1.7"
|
||||||
|
"@ionic/utils-process": "npm:2.1.12"
|
||||||
|
"@ionic/utils-stream": "npm:3.1.7"
|
||||||
|
"@ionic/utils-terminal": "npm:2.3.5"
|
||||||
|
cross-spawn: "npm:^7.0.3"
|
||||||
|
debug: "npm:^4.0.0"
|
||||||
|
tslib: "npm:^2.0.1"
|
||||||
|
checksum: 10/7411d691b3cdaa1ab74171a521813118a4b7180a373d6d80ee6b2b7946490486b3cb9f8ca338a9ffb4167c098d0c79ce14d8579ac82db794e5e1017b73bf85eb
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@ionic/utils-terminal@npm:2.3.5, @ionic/utils-terminal@npm:^2.3.4, @ionic/utils-terminal@npm:^2.3.5":
|
||||||
|
version: 2.3.5
|
||||||
|
resolution: "@ionic/utils-terminal@npm:2.3.5"
|
||||||
|
dependencies:
|
||||||
|
"@types/slice-ansi": "npm:^4.0.0"
|
||||||
|
debug: "npm:^4.0.0"
|
||||||
|
signal-exit: "npm:^3.0.3"
|
||||||
|
slice-ansi: "npm:^4.0.0"
|
||||||
|
string-width: "npm:^4.1.0"
|
||||||
|
strip-ansi: "npm:^6.0.0"
|
||||||
|
tslib: "npm:^2.0.1"
|
||||||
|
untildify: "npm:^4.0.0"
|
||||||
|
wrap-ansi: "npm:^7.0.0"
|
||||||
|
checksum: 10/40bae30f8cff2d7efa74118d96b2ab16ac9048ba8ffe28a8c203cd398f2688955ddb28d5ebe0c6948890632dc1ca2fe5e84c547ce930cde3ac7be4d5f53e5245
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@isaacs/balanced-match@npm:^4.0.1":
|
"@isaacs/balanced-match@npm:^4.0.1":
|
||||||
version: 4.0.1
|
version: 4.0.1
|
||||||
resolution: "@isaacs/balanced-match@npm:4.0.1"
|
resolution: "@isaacs/balanced-match@npm:4.0.1"
|
||||||
@@ -9911,6 +10107,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/fs-extra@npm:^8.0.0":
|
||||||
|
version: 8.1.5
|
||||||
|
resolution: "@types/fs-extra@npm:8.1.5"
|
||||||
|
dependencies:
|
||||||
|
"@types/node": "npm:*"
|
||||||
|
checksum: 10/565d9e55cd05064b3ab272b8748ed512b8fa5cddc23fd32b0d5f147f9ea3a45981577c4478b5060cae7b3d914c508bd2ea97eb84d9c1fa6f967982c892e4ab26
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/geojson@npm:*":
|
"@types/geojson@npm:*":
|
||||||
version: 7946.0.16
|
version: 7946.0.16
|
||||||
resolution: "@types/geojson@npm:7946.0.16"
|
resolution: "@types/geojson@npm:7946.0.16"
|
||||||
@@ -10368,6 +10573,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/slice-ansi@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "@types/slice-ansi@npm:4.0.0"
|
||||||
|
checksum: 10/343086bc4e686349382b386a6fb49d632fb4dd08ecc08f1b9872815199efe8db7648731e56c1d10dc0f596fe77a8fce6136e0067136f8e0cefda6b29797aa4f1
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/sockjs@npm:^0.3.36":
|
"@types/sockjs@npm:^0.3.36":
|
||||||
version: 0.3.36
|
version: 0.3.36
|
||||||
resolution: "@types/sockjs@npm:0.3.36"
|
resolution: "@types/sockjs@npm:0.3.36"
|
||||||
@@ -12270,6 +12482,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"big-integer@npm:1.6.x":
|
||||||
|
version: 1.6.52
|
||||||
|
resolution: "big-integer@npm:1.6.52"
|
||||||
|
checksum: 10/4bc6ae152a96edc9f95020f5fc66b13d26a9ad9a021225a9f0213f7e3dc44269f423aa8c42e19d6ac4a63bb2b22140b95d10be8f9ca7a6d9aa1b22b330d1f514
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"big.js@npm:^5.2.2":
|
"big.js@npm:^5.2.2":
|
||||||
version: 5.2.2
|
version: 5.2.2
|
||||||
resolution: "big.js@npm:5.2.2"
|
resolution: "big.js@npm:5.2.2"
|
||||||
@@ -12422,6 +12641,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"bplist-parser@npm:^0.3.2":
|
||||||
|
version: 0.3.2
|
||||||
|
resolution: "bplist-parser@npm:0.3.2"
|
||||||
|
dependencies:
|
||||||
|
big-integer: "npm:1.6.x"
|
||||||
|
checksum: 10/6edf4354c32f5661c258422e478be0f5c6a779bb87c2ae15ee92dd1c046368decbff8a28c86c558a3b7007e1381b91d5eed1c4c8e83e86405197777d944abaa8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"brace-expansion@npm:^1.1.7":
|
"brace-expansion@npm:^1.1.7":
|
||||||
version: 1.1.12
|
version: 1.1.12
|
||||||
resolution: "brace-expansion@npm:1.1.12"
|
resolution: "brace-expansion@npm:1.1.12"
|
||||||
@@ -15582,6 +15810,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"elementtree@npm:^0.1.7":
|
||||||
|
version: 0.1.7
|
||||||
|
resolution: "elementtree@npm:0.1.7"
|
||||||
|
dependencies:
|
||||||
|
sax: "npm:1.1.4"
|
||||||
|
checksum: 10/7e8f0683c0f5a95b298f56426f0f3796600ddac611cfaf92b76f1f4354b04c3f9aadadd1f86a91e5df372a58f2c3da97ae5988597f5052dd15bbeefbff8381c9
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"elliptic@npm:^6.5.3, elliptic@npm:^6.6.1":
|
"elliptic@npm:^6.5.3, elliptic@npm:^6.6.1":
|
||||||
version: 6.6.1
|
version: 6.6.1
|
||||||
resolution: "elliptic@npm:6.6.1"
|
resolution: "elliptic@npm:6.6.1"
|
||||||
@@ -17629,6 +17866,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"glob@npm:^13.0.3":
|
||||||
|
version: 13.0.6
|
||||||
|
resolution: "glob@npm:13.0.6"
|
||||||
|
dependencies:
|
||||||
|
minimatch: "npm:^10.2.2"
|
||||||
|
minipass: "npm:^7.1.3"
|
||||||
|
path-scurry: "npm:^2.0.2"
|
||||||
|
checksum: 10/201ad69e5f0aa74e1d8c00a481581f8b8c804b6a4fbfabeeb8541f5d756932800331daeba99b58fb9e4cd67e12ba5a7eba5b82fb476691588418060b84353214
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"glob@npm:^7.0.5, glob@npm:^7.1.3, glob@npm:^7.1.6":
|
"glob@npm:^7.0.5, glob@npm:^7.1.3, glob@npm:^7.1.6":
|
||||||
version: 7.2.3
|
version: 7.2.3
|
||||||
resolution: "glob@npm:7.2.3"
|
resolution: "glob@npm:7.2.3"
|
||||||
@@ -18774,6 +19022,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ini@npm:^4.1.1":
|
||||||
|
version: 4.1.3
|
||||||
|
resolution: "ini@npm:4.1.3"
|
||||||
|
checksum: 10/f536b414d1442e5b233429e2b56efcdb354109b2d65ddd489e5939d8f0f5ad23c88aa2b19c92987249d0dd63ba8192e9aeb1a02b0459549c5a9ff31acd729a5d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"inline-style-parser@npm:0.2.4":
|
"inline-style-parser@npm:0.2.4":
|
||||||
version: 0.2.4
|
version: 0.2.4
|
||||||
resolution: "inline-style-parser@npm:0.2.4"
|
resolution: "inline-style-parser@npm:0.2.4"
|
||||||
@@ -19954,6 +20209,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"kleur@npm:^4.1.5":
|
||||||
|
version: 4.1.5
|
||||||
|
resolution: "kleur@npm:4.1.5"
|
||||||
|
checksum: 10/44d84cc4eedd4311099402ef6d4acd9b2d16e08e499d6ef3bb92389bd4692d7ef09e35248c26e27f98acac532122acb12a1bfee645994ae3af4f0a37996da7df
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"kolorist@npm:^1.8.0":
|
"kolorist@npm:^1.8.0":
|
||||||
version: 1.8.0
|
version: 1.8.0
|
||||||
resolution: "kolorist@npm:1.8.0"
|
resolution: "kolorist@npm:1.8.0"
|
||||||
@@ -21892,6 +22154,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"minipass@npm:^7.1.3":
|
||||||
|
version: 7.1.3
|
||||||
|
resolution: "minipass@npm:7.1.3"
|
||||||
|
checksum: 10/175e4d5e20980c3cd316ae82d2c031c42f6c746467d8b1905b51060a0ba4461441a0c25bb67c025fd9617f9a3873e152c7b543c6b5ac83a1846be8ade80dffd6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"minizlib@npm:^2.1.1":
|
"minizlib@npm:^2.1.1":
|
||||||
version: 2.1.2
|
version: 2.1.2
|
||||||
resolution: "minizlib@npm:2.1.2"
|
resolution: "minizlib@npm:2.1.2"
|
||||||
@@ -22039,6 +22308,27 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"native-run@npm:^2.0.3":
|
||||||
|
version: 2.0.3
|
||||||
|
resolution: "native-run@npm:2.0.3"
|
||||||
|
dependencies:
|
||||||
|
"@ionic/utils-fs": "npm:^3.1.7"
|
||||||
|
"@ionic/utils-terminal": "npm:^2.3.4"
|
||||||
|
bplist-parser: "npm:^0.3.2"
|
||||||
|
debug: "npm:^4.3.4"
|
||||||
|
elementtree: "npm:^0.1.7"
|
||||||
|
ini: "npm:^4.1.1"
|
||||||
|
plist: "npm:^3.1.0"
|
||||||
|
split2: "npm:^4.2.0"
|
||||||
|
through2: "npm:^4.0.2"
|
||||||
|
tslib: "npm:^2.6.2"
|
||||||
|
yauzl: "npm:^2.10.0"
|
||||||
|
bin:
|
||||||
|
native-run: bin/native-run
|
||||||
|
checksum: 10/f78268262d94f758d4d0ecb7a3ece3c4b38f57aefcc9d71d99e0f1d81c5ea9bf2dd6f459fab64652071f5743f3a80e92259590c54754be6f25a600d9b4ccd856
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"natural-compare@npm:^1.4.0":
|
"natural-compare@npm:^1.4.0":
|
||||||
version: 1.4.0
|
version: 1.4.0
|
||||||
resolution: "natural-compare@npm:1.4.0"
|
resolution: "natural-compare@npm:1.4.0"
|
||||||
@@ -22945,7 +23235,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"package-json-from-dist@npm:^1.0.0":
|
"package-json-from-dist@npm:^1.0.0, package-json-from-dist@npm:^1.0.1":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "package-json-from-dist@npm:1.0.1"
|
resolution: "package-json-from-dist@npm:1.0.1"
|
||||||
checksum: 10/58ee9538f2f762988433da00e26acc788036914d57c71c246bf0be1b60cdbd77dd60b6a3e1a30465f0b248aeb80079e0b34cb6050b1dfa18c06953bb1cbc7602
|
checksum: 10/58ee9538f2f762988433da00e26acc788036914d57c71c246bf0be1b60cdbd77dd60b6a3e1a30465f0b248aeb80079e0b34cb6050b1dfa18c06953bb1cbc7602
|
||||||
@@ -23198,6 +23488,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"path-scurry@npm:^2.0.2":
|
||||||
|
version: 2.0.2
|
||||||
|
resolution: "path-scurry@npm:2.0.2"
|
||||||
|
dependencies:
|
||||||
|
lru-cache: "npm:^11.0.0"
|
||||||
|
minipass: "npm:^7.1.2"
|
||||||
|
checksum: 10/2b4257422bcb870a4c2d205b3acdbb213a72f5e2250f61c80f79c9d014d010f82bdf8584441612c8e1fa4eb098678f5704a66fa8377d72646bad4be38e57a2c3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"path-to-regexp@npm:0.1.12":
|
"path-to-regexp@npm:0.1.12":
|
||||||
version: 0.1.12
|
version: 0.1.12
|
||||||
resolution: "path-to-regexp@npm:0.1.12"
|
resolution: "path-to-regexp@npm:0.1.12"
|
||||||
@@ -25359,6 +25659,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"readable-stream@npm:3, readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0, readable-stream@npm:^3.6.2":
|
||||||
|
version: 3.6.2
|
||||||
|
resolution: "readable-stream@npm:3.6.2"
|
||||||
|
dependencies:
|
||||||
|
inherits: "npm:^2.0.3"
|
||||||
|
string_decoder: "npm:^1.1.1"
|
||||||
|
util-deprecate: "npm:^1.0.1"
|
||||||
|
checksum: 10/d9e3e53193adcdb79d8f10f2a1f6989bd4389f5936c6f8b870e77570853561c362bee69feca2bbb7b32368ce96a85504aa4cedf7cf80f36e6a9de30d64244048
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"readable-stream@npm:^2.0.1, readable-stream@npm:^2.3.8, readable-stream@npm:~2.3.6":
|
"readable-stream@npm:^2.0.1, readable-stream@npm:^2.3.8, readable-stream@npm:~2.3.6":
|
||||||
version: 2.3.8
|
version: 2.3.8
|
||||||
resolution: "readable-stream@npm:2.3.8"
|
resolution: "readable-stream@npm:2.3.8"
|
||||||
@@ -25374,17 +25685,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0, readable-stream@npm:^3.6.2":
|
|
||||||
version: 3.6.2
|
|
||||||
resolution: "readable-stream@npm:3.6.2"
|
|
||||||
dependencies:
|
|
||||||
inherits: "npm:^2.0.3"
|
|
||||||
string_decoder: "npm:^1.1.1"
|
|
||||||
util-deprecate: "npm:^1.0.1"
|
|
||||||
checksum: 10/d9e3e53193adcdb79d8f10f2a1f6989bd4389f5936c6f8b870e77570853561c362bee69feca2bbb7b32368ce96a85504aa4cedf7cf80f36e6a9de30d64244048
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"readable-stream@npm:~1.0.31":
|
"readable-stream@npm:~1.0.31":
|
||||||
version: 1.0.34
|
version: 1.0.34
|
||||||
resolution: "readable-stream@npm:1.0.34"
|
resolution: "readable-stream@npm:1.0.34"
|
||||||
@@ -26039,6 +26339,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"rimraf@npm:^6.0.1":
|
||||||
|
version: 6.1.3
|
||||||
|
resolution: "rimraf@npm:6.1.3"
|
||||||
|
dependencies:
|
||||||
|
glob: "npm:^13.0.3"
|
||||||
|
package-json-from-dist: "npm:^1.0.1"
|
||||||
|
bin:
|
||||||
|
rimraf: dist/esm/bin.mjs
|
||||||
|
checksum: 10/dd98ec2ad7cd2cccae1c7110754d472eac8edb2bab8a8b057dce04edfe1433dab246a889b3fd85a66c78ca81caa1429caa0e736c7647f6832b04fd5d4dfb8ab8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1, ripemd160@npm:^2.0.3":
|
"ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1, ripemd160@npm:^2.0.3":
|
||||||
version: 2.0.3
|
version: 2.0.3
|
||||||
resolution: "ripemd160@npm:2.0.3"
|
resolution: "ripemd160@npm:2.0.3"
|
||||||
@@ -26396,6 +26708,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"sax@npm:1.1.4":
|
||||||
|
version: 1.1.4
|
||||||
|
resolution: "sax@npm:1.1.4"
|
||||||
|
checksum: 10/50dd85c562f6de00f1a6c4049f27471258b35c77961498784976445455f99d105bac0de2edf342730b6e0e410346581622c21494355178b6883611619757ae1b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"sax@npm:>=0.6.0, sax@npm:^1.2.4":
|
"sax@npm:>=0.6.0, sax@npm:^1.2.4":
|
||||||
version: 1.4.1
|
version: 1.4.1
|
||||||
resolution: "sax@npm:1.4.1"
|
resolution: "sax@npm:1.4.1"
|
||||||
@@ -26986,6 +27305,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"slice-ansi@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "slice-ansi@npm:4.0.0"
|
||||||
|
dependencies:
|
||||||
|
ansi-styles: "npm:^4.0.0"
|
||||||
|
astral-regex: "npm:^2.0.0"
|
||||||
|
is-fullwidth-code-point: "npm:^3.0.0"
|
||||||
|
checksum: 10/4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"slice-ansi@npm:^7.1.0":
|
"slice-ansi@npm:^7.1.0":
|
||||||
version: 7.1.2
|
version: 7.1.2
|
||||||
resolution: "slice-ansi@npm:7.1.2"
|
resolution: "slice-ansi@npm:7.1.2"
|
||||||
@@ -27206,6 +27536,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"split2@npm:^4.2.0":
|
||||||
|
version: 4.2.0
|
||||||
|
resolution: "split2@npm:4.2.0"
|
||||||
|
checksum: 10/09bbefc11bcf03f044584c9764cd31a252d8e52cea29130950b26161287c11f519807c5e54bd9e5804c713b79c02cefe6a98f4688630993386be353e03f534ab
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"sprintf-js@npm:^1.1.1, sprintf-js@npm:^1.1.2":
|
"sprintf-js@npm:^1.1.1, sprintf-js@npm:^1.1.2":
|
||||||
version: 1.1.3
|
version: 1.1.3
|
||||||
resolution: "sprintf-js@npm:1.1.3"
|
resolution: "sprintf-js@npm:1.1.3"
|
||||||
@@ -27882,6 +28219,19 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"tar@npm:^7.5.3":
|
||||||
|
version: 7.5.12
|
||||||
|
resolution: "tar@npm:7.5.12"
|
||||||
|
dependencies:
|
||||||
|
"@isaacs/fs-minipass": "npm:^4.0.0"
|
||||||
|
chownr: "npm:^3.0.0"
|
||||||
|
minipass: "npm:^7.1.2"
|
||||||
|
minizlib: "npm:^3.1.0"
|
||||||
|
yallist: "npm:^5.0.0"
|
||||||
|
checksum: 10/a72114d28ab9b4878eeebaae8987692a577c390683c13f150d8330e139237038cc46fbb0be6983b02acf5a31b01d74776436ba03790f320a59efb44b8ac39e39
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"teex@npm:^1.0.1":
|
"teex@npm:^1.0.1":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "teex@npm:1.0.1"
|
resolution: "teex@npm:1.0.1"
|
||||||
@@ -28017,6 +28367,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"through2@npm:^4.0.2":
|
||||||
|
version: 4.0.2
|
||||||
|
resolution: "through2@npm:4.0.2"
|
||||||
|
dependencies:
|
||||||
|
readable-stream: "npm:3"
|
||||||
|
checksum: 10/72c246233d9a989bbebeb6b698ef0b7b9064cb1c47930f79b25d87b6c867e075432811f69b7b2ac8da00ca308191c507bdab913944be8019ac43b036ce88f6ba
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"thunky@npm:^1.0.2":
|
"thunky@npm:^1.0.2":
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
resolution: "thunky@npm:1.1.0"
|
resolution: "thunky@npm:1.1.0"
|
||||||
@@ -28258,6 +28617,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"tree-kill@npm:^1.2.2":
|
||||||
|
version: 1.2.2
|
||||||
|
resolution: "tree-kill@npm:1.2.2"
|
||||||
|
bin:
|
||||||
|
tree-kill: cli.js
|
||||||
|
checksum: 10/49117f5f410d19c84b0464d29afb9642c863bc5ba40fcb9a245d474c6d5cc64d1b177a6e6713129eb346b40aebb9d4631d967517f9fbe8251c35b21b13cd96c7
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"trim-lines@npm:^3.0.0":
|
"trim-lines@npm:^3.0.0":
|
||||||
version: 3.0.1
|
version: 3.0.1
|
||||||
resolution: "trim-lines@npm:3.0.1"
|
resolution: "trim-lines@npm:3.0.1"
|
||||||
@@ -28364,7 +28732,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.6.0, tslib@npm:^2.8.0, tslib@npm:^2.8.1":
|
"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2, tslib@npm:^2.8.0, tslib@npm:^2.8.1":
|
||||||
version: 2.8.1
|
version: 2.8.1
|
||||||
resolution: "tslib@npm:2.8.1"
|
resolution: "tslib@npm:2.8.1"
|
||||||
checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7
|
checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7
|
||||||
|
|||||||
Reference in New Issue
Block a user