diff --git a/.gitignore b/.gitignore index 2504c3d..b6d6e28 100644 --- a/.gitignore +++ b/.gitignore @@ -143,6 +143,7 @@ playground/ # PNPM .pnpm-store/ +.pnpmfile.cjs # MacOS -.DS_Store \ No newline at end of file +.DS_Store diff --git a/cli/src/commands/deploy/index.ts b/cli/src/commands/deploy/index.ts index e53899e..95feb9e 100644 --- a/cli/src/commands/deploy/index.ts +++ b/cli/src/commands/deploy/index.ts @@ -16,10 +16,7 @@ export default class DeployAll extends WithSyncConfigFilePath(BaseDeployCommand) `See also ${ux.colorize('blue', 'powersync deploy sync-config')} to deploy only sync config changes.`, `See also ${ux.colorize('blue', 'powersync deploy service-config')} to deploy only service config changes.` ].join('\n'); - static examples = [ - '<%= config.bin %> <%= command.id %>', - '<%= config.bin %> <%= command.id %> --instance-id= --project-id=' - ]; + static examples = ['<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --instance-id=']; static flags = { ...GENERAL_VALIDATION_FLAG_HELPERS.flags }; diff --git a/cli/src/commands/deploy/service-config.ts b/cli/src/commands/deploy/service-config.ts index c9c7122..e095206 100644 --- a/cli/src/commands/deploy/service-config.ts +++ b/cli/src/commands/deploy/service-config.ts @@ -12,10 +12,7 @@ const SERVICE_CONFIG_VALIDATION_FLAGS = generateValidationTestFlags({ export default class DeployServiceConfig extends BaseDeployCommand { static description = 'Deploy only service config changes (without sync config updates).'; - static examples = [ - '<%= config.bin %> <%= command.id %>', - '<%= config.bin %> <%= command.id %> --instance-id= --project-id=' - ]; + static examples = ['<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --instance-id=']; static flags = { ...SERVICE_CONFIG_VALIDATION_FLAGS.flags }; diff --git a/cli/src/commands/deploy/sync-config.ts b/cli/src/commands/deploy/sync-config.ts index 74c2319..de1cbb1 100644 --- a/cli/src/commands/deploy/sync-config.ts +++ b/cli/src/commands/deploy/sync-config.ts @@ -17,10 +17,7 @@ const SYNC_CONFIG_VALIDATION_FLAGS = generateValidationTestFlags({ export default class DeploySyncConfig extends WithSyncConfigFilePath(BaseDeployCommand) { static description = 'Deploy only sync config changes.'; - static examples = [ - '<%= config.bin %> <%= command.id %>', - '<%= config.bin %> <%= command.id %> --instance-id= --project-id=' - ]; + static examples = ['<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --instance-id=']; static flags = { ...SYNC_CONFIG_VALIDATION_FLAGS.flags }; diff --git a/cli/src/commands/fetch/status.ts b/cli/src/commands/fetch/status.ts index 02b6596..573702a 100644 --- a/cli/src/commands/fetch/status.ts +++ b/cli/src/commands/fetch/status.ts @@ -10,7 +10,7 @@ export default class FetchStatus extends SharedInstanceCommand { static examples = [ '<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --output=json', - '<%= config.bin %> <%= command.id %> --instance-id= --project-id=' + '<%= config.bin %> <%= command.id %> --instance-id=' ]; static flags = { output: Flags.string({ diff --git a/cli/src/commands/generate/schema.ts b/cli/src/commands/generate/schema.ts index e101b3e..6b05566 100644 --- a/cli/src/commands/generate/schema.ts +++ b/cli/src/commands/generate/schema.ts @@ -19,7 +19,7 @@ export default class GenerateSchema extends WithSyncConfigFilePath(SharedInstanc 'Generate a client-side schema file from the instance database schema and sync config. Supports multiple output types (e.g. type, dart). Requires a linked instance. Cloud and self-hosted.'; static examples = [ '<%= config.bin %> <%= command.id %> --output=ts --output-path=schema.ts', - '<%= config.bin %> <%= command.id %> --output=dart --output-path=lib/schema.dart --instance-id= --project-id=' + '<%= config.bin %> <%= command.id %> --output=dart --output-path=lib/schema.dart --instance-id=' ]; static flags = { output: Flags.string({ diff --git a/cli/src/commands/init/cloud.ts b/cli/src/commands/init/cloud.ts index 2f1d408..2d4c22c 100644 --- a/cli/src/commands/init/cloud.ts +++ b/cli/src/commands/init/cloud.ts @@ -68,12 +68,9 @@ export default class InitCloud extends InstanceCommand { const instructions = [ 'Create a new instance with ', - ux.colorize('blue', '\tpowersync link cloud --create --org-id= --project-id='), + ux.colorize('blue', '\tpowersync link cloud --create --project-id='), 'or pull an existing instance with ', - ux.colorize( - 'blue', - '\tpowersync pull instance --org-id= --project-id= --instance-id=' - ), + ux.colorize('blue', '\tpowersync pull instance --instance-id='), `Tip: use ${ux.colorize('blue', 'powersync fetch instances')} to see available organizations and projects for your token.`, 'Then run', ux.colorize('blue', '\tpowersync deploy'), diff --git a/cli/src/commands/link/cloud.ts b/cli/src/commands/link/cloud.ts index 212c200..8d5c254 100644 --- a/cli/src/commands/link/cloud.ts +++ b/cli/src/commands/link/cloud.ts @@ -16,11 +16,11 @@ import { writeCloudLink } from '../../api/cloud/write-cloud-link.js'; export default class LinkCloud extends CloudInstanceCommand { static commandHelpGroup = CommandHelpGroup.PROJECT_SETUP; static description = - 'Write or update cli.yaml with a Cloud instance (instance-id, org-id, project-id). Use --create to create a new instance from service.yaml name/region and link it; omit --instance-id when using --create. Org ID is optional when the token has a single organization.'; + 'Write or update cli.yaml with a Cloud instance link. Pass --instance-id to link an existing instance (org-id and project-id are resolved automatically). Use --create with --project-id to create a new instance from service.yaml and link it.'; static examples = [ - '<%= config.bin %> <%= command.id %> --project-id=', + '<%= config.bin %> <%= command.id %> --instance-id=', '<%= config.bin %> <%= command.id %> --create --project-id=', - '<%= config.bin %> <%= command.id %> --instance-id= --project-id= --org-id=' + '<%= config.bin %> <%= command.id %> --create --project-id= --org-id=' ]; static flags = { create: Flags.boolean({ @@ -30,19 +30,20 @@ export default class LinkCloud extends CloudInstanceCommand { }), 'instance-id': Flags.string({ default: env.INSTANCE_ID, - description: 'PowerSync Cloud instance ID. Omit when using --create. Resolved: flag → INSTANCE_ID → cli.yaml.', + description: 'PowerSync Cloud instance ID. Omit when using --create. Resolved: flag → INSTANCE_ID.', required: false }), 'org-id': Flags.string({ default: env.ORG_ID, description: - 'Organization ID. Optional when the token has a single org; required when the token has multiple orgs. Resolved: flag → ORG_ID → cli.yaml.', + 'Organization ID. Auto-resolved from the instance when linking an existing instance; required (or auto-resolved if single org) when using --create. Resolved: flag → ORG_ID.', required: false }), 'project-id': Flags.string({ default: env.PROJECT_ID, - description: 'Project ID. Resolved: flag → PROJECT_ID → cli.yaml.', - required: true + description: + 'Project ID. Required when using --create; auto-resolved from the instance otherwise. Resolved: flag → PROJECT_ID.', + required: false }) }; static summary = '[Cloud only] Link to a PowerSync Cloud instance (or create one with --create).'; @@ -51,10 +52,6 @@ export default class LinkCloud extends CloudInstanceCommand { const { flags } = await this.parse(LinkCloud); let { create, directory, 'instance-id': instanceId, 'org-id': orgId, 'project-id': projectId } = flags; - if (!orgId) { - orgId = await getDefaultOrgId(); - } - const projectDirectory = this.resolveProjectDir(flags); if (create) { if (instanceId) { @@ -63,6 +60,16 @@ export default class LinkCloud extends CloudInstanceCommand { }); } + if (!projectId) { + this.styledError({ + message: 'Pass --project-id when using --create.' + }); + } + + if (!orgId) { + orgId = await getDefaultOrgId(); + } + try { await validateCloudLinkConfig({ cloudClient: this.client, @@ -111,13 +118,13 @@ export default class LinkCloud extends CloudInstanceCommand { } try { - await validateCloudLinkConfig({ - cloudClient: this.client, - input: { instanceId, orgId, projectId }, - validateInstance: true + const instanceMeta = await this.client.getInstance({ id: instanceId }); + orgId = instanceMeta.org_id; + projectId = instanceMeta.app_id; + } catch { + this.styledError({ + message: `Instance ${instanceId} was not found, or is not accessible with the current token.` }); - } catch (error) { - this.styledError({ message: error instanceof Error ? error.message : String(error) }); } writeCloudLink(projectDirectory, { instanceId, orgId, projectId }); diff --git a/cli/src/commands/pull/instance.ts b/cli/src/commands/pull/instance.ts index 51b1614..6ca45d9 100644 --- a/cli/src/commands/pull/instance.ts +++ b/cli/src/commands/pull/instance.ts @@ -4,7 +4,6 @@ import { CloudInstanceCommand, CommandHelpGroup, ensureServiceTypeMatches, - getDefaultOrgId, SERVICE_FILENAME, ServiceType, SYNC_FILENAME, @@ -30,12 +29,8 @@ const PULL_CONFIG_HEADER = `# PowerSync Cloud config (fetched from cloud) export default class PullInstance extends CloudInstanceCommand { static commandHelpGroup = CommandHelpGroup.PROJECT_SETUP; static description = - 'Fetch an existing Cloud instance by ID: create the config directory if needed, write cli.yaml, and download service.yaml and sync-config.yaml. Pass --instance-id and --project-id when the directory is not yet linked; --org-id is optional when the token has a single organization. Cloud only.'; - static examples = [ - '<%= config.bin %> <%= command.id %>', - '<%= config.bin %> <%= command.id %> --instance-id= --project-id=', - '<%= config.bin %> <%= command.id %> --instance-id= --project-id= --org-id=' - ]; + 'Fetch an existing Cloud instance by ID: create the config directory if needed, write cli.yaml, and download service.yaml and sync-config.yaml. Pass --instance-id when the directory is not yet linked. Cloud only.'; + static examples = ['<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --instance-id=']; static flags = { overwrite: Flags.boolean({ description: @@ -47,19 +42,18 @@ export default class PullInstance extends CloudInstanceCommand { async run(): Promise { const { flags } = await this.parse(PullInstance); - const { directory, 'instance-id': instanceId, 'org-id': _orgId, 'project-id': projectId } = flags; + const { directory, 'instance-id': instanceId } = flags; - const resolvedOrgId = _orgId ?? (await getDefaultOrgId().catch(() => null)); /** * The pull instance command can be used to create a new powersync project directory */ const projectDir = this.resolveProjectDir(flags); if (!existsSync(projectDir)) { - if (instanceId && resolvedOrgId && projectId) { + if (instanceId) { mkdirSync(projectDir, { recursive: true }); } else { this.styledError({ - message: `Directory "${directory}" not found. Pass --instance-id, and --project-id to create the config directory and link, or run this command from a directory that already contains a linked PowerSync config.` + message: `Directory "${directory}" not found. Pass --instance-id to create the config directory and link, or run this command from a directory that already contains a linked PowerSync config.` }); } } @@ -74,13 +68,26 @@ export default class PullInstance extends CloudInstanceCommand { const linkPath = join(projectDir, CLI_FILENAME); if (!existsSync(linkPath)) { - if (!instanceId || !resolvedOrgId || !projectId) { + if (!instanceId) { this.styledError({ - message: `Linking is required. Pass --instance-id, --org-id, and --project-id to this command, or run ${ux.colorize('blue', 'powersync link cloud --instance-id= --org-id= --project-id=')} first.` + message: `Linking is required. Pass --instance-id to this command, or run ${ux.colorize('blue', 'powersync link cloud --instance-id=')} first.` }); } - writeCloudLink(projectDir, { instanceId, orgId: resolvedOrgId, projectId }); + let instanceMeta; + try { + instanceMeta = await this.client.getInstance({ id: instanceId }); + } catch { + this.styledError({ + message: `Instance ${instanceId} was not found, or is not accessible with the current token.` + }); + } + + writeCloudLink(projectDir, { + instanceId, + orgId: instanceMeta.org_id, + projectId: instanceMeta.app_id + }); this.log(`Created ${ux.colorize('blue', `${directory}/${CLI_FILENAME}`)} with Cloud instance link.`); } diff --git a/cli/test/command-types/resolution-order.test.ts b/cli/test/command-types/resolution-order.test.ts index ba7bd6d..ce75e45 100644 --- a/cli/test/command-types/resolution-order.test.ts +++ b/cli/test/command-types/resolution-order.test.ts @@ -9,6 +9,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import DestroyCommand from '../../src/commands/destroy.js'; import FetchStatusCommand from '../../src/commands/fetch/status.js'; import { root } from '../helpers/root.js'; +import { managementClientMock, resetManagementClientMocks } from '../setup.js'; type EnvSnapshot = { API_URL: string | undefined; @@ -57,6 +58,7 @@ describe('instance resolution order', () => { origCwd = process.cwd(); tmpRoot = mkdtempSync(join(tmpdir(), 'resolution-order-')); process.chdir(tmpRoot); + resetManagementClientMocks(); envSnapshot = { API_URL: env.API_URL, INSTANCE_ID: env.INSTANCE_ID, @@ -100,6 +102,13 @@ describe('instance resolution order', () => { const loadProjectSpy = vi.spyOn(CloudInstanceCommand.prototype, 'loadProject'); + // When --instance-id is passed as a flag, --org-id/--project-id are ignored; + // org and project are always resolved from getInstance. + managementClientMock.getInstance.mockResolvedValueOnce({ + app_id: IDS.flag.project, + id: IDS.flag.instance, + org_id: IDS.flag.org + }); await runDestroyDirect([ '--confirm=yes', `--instance-id=${IDS.flag.instance}`, @@ -210,6 +219,13 @@ describe('instance resolution order', () => { const loadProjectSpy = vi.spyOn(SharedInstanceCommand.prototype, 'loadProject'); vi.spyOn(FetchStatusCommand.prototype, 'getCloudStatus').mockRejectedValue(new Error('expected-test-failure')); + // When --instance-id is passed as a flag, --org-id/--project-id are ignored; + // org and project are always resolved from getInstance. + managementClientMock.getInstance.mockResolvedValueOnce({ + app_id: IDS.flag.project, + id: IDS.flag.instance, + org_id: IDS.flag.org + }); await runFetchStatusDirect([ '--output=json', `--instance-id=${IDS.flag.instance}`, diff --git a/cli/test/commands/link.test.ts b/cli/test/commands/link.test.ts index 4429c05..438554a 100644 --- a/cli/test/commands/link.test.ts +++ b/cli/test/commands/link.test.ts @@ -75,7 +75,7 @@ describe('link', () => { objects: [{ id: PROJECT_ID, name: 'Test Project' }], total: 1 }); - managementClientMock.getInstanceConfig.mockResolvedValue({}); + managementClientMock.getInstance.mockResolvedValue({ app_id: PROJECT_ID, id: INSTANCE_ID, org_id: ORG_ID }); origCwd = process.cwd(); tmpDir = mkdtempSync(join(tmpdir(), 'link-test-')); process.chdir(tmpDir); @@ -213,40 +213,22 @@ type: cloud expect(linkYaml.instance_id).toBe(INSTANCE_ID); }); - it('errors for invalid ObjectID flag values', async () => { - const { error } = await runLinkCloudDirect([ - `--instance-id=${INSTANCE_ID}`, - `--org-id=${ORG_ID}`, - '--project-id=invalid/project-id' - ]); - expect(error?.message).toContain('Invalid --project-id'); - }); - - it('errors when project does not exist in the organization', async () => { - accountsClientMock.listProjects.mockResolvedValueOnce({ objects: [], total: 0 }); - - const { error } = await runLinkCloudDirect([ - `--instance-id=${INSTANCE_ID}`, - `--org-id=${ORG_ID}`, - `--project-id=${PROJECT_ID}` - ]); - - expect(error?.message).toContain(`Project ${PROJECT_ID} was not found in organization ${ORG_ID}`); - expect(error?.message).not.toContain(', ::'); + it('links with instance-id only (resolves org and project automatically)', async () => { + const { error, stdout } = await runLinkCloudDirect([`--instance-id=${INSTANCE_ID}`]); + expect(error).toBeUndefined(); + expect(stdout).toContain(`Updated ${PROJECT_DIR}/${CLI_FILENAME} with Cloud instance link.`); + const linkYaml = parseYaml(readFileSync(join(tmpDir, PROJECT_DIR, CLI_FILENAME), 'utf8')); + expect(linkYaml.instance_id).toBe(INSTANCE_ID); + expect(linkYaml.org_id).toBe(ORG_ID); + expect(linkYaml.project_id).toBe(PROJECT_ID); }); it('errors when instance does not exist and --create is not used', async () => { - managementClientMock.getInstanceConfig.mockRejectedValueOnce(new Error('not found')); + managementClientMock.getInstance.mockRejectedValueOnce(new Error('not found')); - const { error } = await runLinkCloudDirect([ - `--instance-id=${INSTANCE_ID}`, - `--org-id=${ORG_ID}`, - `--project-id=${PROJECT_ID}` - ]); + const { error } = await runLinkCloudDirect([`--instance-id=${INSTANCE_ID}`]); - expect(error?.message).toContain( - `Instance ${INSTANCE_ID} was not found in project ${PROJECT_ID} in organization ${ORG_ID}` - ); + expect(error?.message).toContain(`Instance ${INSTANCE_ID} was not found`); }); }); diff --git a/cli/test/commands/migrate.test.ts b/cli/test/commands/migrate.test.ts index d6a34cd..dc22a5a 100644 --- a/cli/test/commands/migrate.test.ts +++ b/cli/test/commands/migrate.test.ts @@ -2,33 +2,36 @@ import { runCommand } from '@oclif/test'; import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; -import { expect, onTestFinished, test } from 'vitest'; +import { describe, expect, onTestFinished, test } from 'vitest'; import { root } from '../helpers/root.js'; -test('migrates from sync rules to sync streams', async () => { - const testDirectory = mkdtempSync(join(tmpdir(), 'migrate-test-')); - onTestFinished(() => rmSync(testDirectory, { recursive: true })); +describe('migrate', () => { + test('migrates from sync rules to sync streams', async () => { + const testDirectory = mkdtempSync(join(tmpdir(), 'migrate-test-')); + onTestFinished(() => rmSync(testDirectory, { recursive: true })); - const inputFile = join(testDirectory, 'input.yaml'); - const outputFile = join(testDirectory, 'output.yaml'); - writeFileSync( - inputFile, - ` + const inputFile = join(testDirectory, 'input.yaml'); + const outputFile = join(testDirectory, 'output.yaml'); + writeFileSync( + inputFile, + ` bucket_definitions: user_lists: parameters: SELECT request.user_id() as user_id data: - SELECT * FROM lists WHERE owner_id = bucket.user_id ` - ); + ); - const result = await runCommand(`migrate sync-rules --input-file ${inputFile} --output-file ${outputFile}`, { root }); - expect(result.error).toBeUndefined(); + const result = await runCommand(`migrate sync-rules --input-file ${inputFile} --output-file ${outputFile}`, { + root + }); + expect(result.error).toBeUndefined(); - const transformed = readFileSync(outputFile).toString('utf-8'); - expect(transformed) - .toStrictEqual(`# Adds YAML Schema support for VSCode users with the YAML extension installed. This enables features like validation and autocompletion based on the provided schema. + const transformed = readFileSync(outputFile).toString('utf8'); + expect(transformed) + .toStrictEqual(`# Adds YAML Schema support for VSCode users with the YAML extension installed. This enables features like validation and autocompletion based on the provided schema. # yaml-language-server: $schema=https://unpkg.com/@powersync/service-sync-rules@latest/schema/sync_rules.json config: edition: 3 @@ -41,4 +44,5 @@ streams: queries: - SELECT * FROM lists WHERE owner_id = auth.user_id() `); + }); }); diff --git a/cli/test/commands/pull/instance.test.ts b/cli/test/commands/pull/instance.test.ts index 26d8629..6131400 100644 --- a/cli/test/commands/pull/instance.test.ts +++ b/cli/test/commands/pull/instance.test.ts @@ -34,6 +34,7 @@ const MOCK_CONFIG_WITH_EMPTY_JWKS_KEYS = { const mockCloudClient = { deployInstance: vi.fn(), + getInstance: vi.fn(), getInstanceConfig: vi.fn() }; @@ -79,6 +80,8 @@ describe('pull instance', () => { origCwd = process.cwd(); tmpDir = mkdtempSync(join(tmpdir(), 'pull-instance-test-')); process.chdir(tmpDir); + mockCloudClient.getInstance.mockReset(); + mockCloudClient.getInstance.mockResolvedValue({ app_id: PROJECT_ID, id: INSTANCE_ID, org_id: ORG_ID }); mockCloudClient.getInstanceConfig.mockReset(); mockCloudClient.getInstanceConfig.mockRejectedValue(new Error('network error')); accountsClientMock.getOrganization.mockResolvedValue({ id: ORG_ID, label: 'Test Org' }); @@ -105,9 +108,7 @@ describe('pull instance', () => { expect(existsSync(projectDir)).toBe(false); mockCloudClient.getInstanceConfig.mockResolvedValueOnce({ config: MOCK_CONFIG }); const result = await runPullInstanceDirect({ - instanceId: INSTANCE_ID, - orgId: ORG_ID, - projectId: PROJECT_ID + instanceId: INSTANCE_ID }); expect(result.error).toBeUndefined(); expect(existsSync(projectDir)).toBe(true); @@ -138,9 +139,7 @@ describe('pull instance', () => { // No service.yaml; ensureServiceTypeMatches allows missing when configFileRequired is false mockCloudClient.getInstanceConfig.mockResolvedValueOnce({ config: MOCK_CONFIG }); const result = await runPullInstanceDirect({ - instanceId: INSTANCE_ID, - orgId: ORG_ID, - projectId: PROJECT_ID + instanceId: INSTANCE_ID }); expect(result.error).toBeUndefined(); expect(existsSync(join(projectDir, 'cli.yaml'))).toBe(true); diff --git a/cli/test/setup.ts b/cli/test/setup.ts index b32d818..bef29bc 100644 --- a/cli/test/setup.ts +++ b/cli/test/setup.ts @@ -38,6 +38,7 @@ export const managementClientMock = { deactivateInstance: vi.fn(), deployInstance: vi.fn(), destroyInstance: vi.fn(), + getInstance: vi.fn(), getInstanceConfig: vi.fn(), getInstanceStatus: vi.fn(), listRegions: vi.fn(), @@ -54,6 +55,11 @@ export function resetManagementClientMocks(): void { managementClientMock.destroyInstance.mockRejectedValue(new Error('mock destroy failure')); managementClientMock.deactivateInstance.mockRejectedValue(new Error('mock deactivate failure')); managementClientMock.deployInstance.mockRejectedValue(new Error('mock deploy failure')); + managementClientMock.getInstance.mockResolvedValue({ + app_id: MOCK_CLOUD_IDS.projectId, + id: MOCK_CLOUD_IDS.instanceId, + org_id: MOCK_CLOUD_IDS.orgId + }); managementClientMock.getInstanceConfig.mockRejectedValue(new Error('mock getInstanceConfig failure')); managementClientMock.getInstanceStatus.mockRejectedValue(new Error('mock getInstanceStatus failure')); managementClientMock.listRegions.mockResolvedValue({ regions: [{ name: 'us' }] }); diff --git a/cli/test/utils/cloud-client-factory.ts b/cli/test/utils/cloud-client-factory.ts index 544e6ef..df5c0f4 100644 --- a/cli/test/utils/cloud-client-factory.ts +++ b/cli/test/utils/cloud-client-factory.ts @@ -4,6 +4,7 @@ import { vi } from 'vitest'; /** Stub used as the cloud client in tests. Created once, returned by createCloudClient and exposed for mocking. */ const stub: PowerSyncManagementClient = { createInstance: vi.fn(), + getInstance: vi.fn(), getInstanceConfig: vi.fn(), getInstanceDiagnostics: vi.fn(), getInstanceStatus: vi.fn() diff --git a/packages/cli-core/src/command-types/CloudInstanceCommand.ts b/packages/cli-core/src/command-types/CloudInstanceCommand.ts index ca728dd..5ebb3c0 100644 --- a/packages/cli-core/src/command-types/CloudInstanceCommand.ts +++ b/packages/cli-core/src/command-types/CloudInstanceCommand.ts @@ -9,7 +9,6 @@ import { PowerSyncManagementClient } from '@powersync/management-client'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; -import { getDefaultOrgId } from '../clients/AccountsHubClientSDKClient.js'; import { createCloudClient } from '../clients/create-cloud-client.js'; import { ensureServiceTypeMatches, ServiceType } from '../utils/ensure-service-type.js'; import { env } from '../utils/env.js'; @@ -41,36 +40,36 @@ export type CloudInstanceCommandFlags = Interfaces.InferredFlags< * 1. Command-line flags (--instance-id, --org-id, --project-id) * 2. Linked config from cli.yaml * 3. Environment variables (INSTANCE_ID, ORG_ID, PROJECT_ID) - * 4. If org_id is still missing: token's single org (via accounts API); error if multiple orgs. + * 4. If org_id or project_id is still missing but instance_id is known: resolved via client.getInstance. * * @example * # Use linked project (cli.yaml) * pnpm exec powersync some-cloud-cmd * # Override with env - * INSTANCE_ID=... ORG_ID=... PROJECT_ID=... pnpm exec powersync some-cloud-cmd - * # Override with flags - * pnpm exec powersync some-cloud-cmd --instance-id=... --org-id=... --project-id=... + * INSTANCE_ID=... pnpm exec powersync some-cloud-cmd + * # Override with flags (--instance-id alone is sufficient) + * pnpm exec powersync some-cloud-cmd --instance-id=... */ export abstract class CloudInstanceCommand extends InstanceCommand { static baseFlags = { /** * Instance ID, org ID, and project ID are resolved in order: flags → cli.yaml → env (INSTANCE_ID, ORG_ID, PROJECT_ID). + * When only instance_id is available, org_id and project_id are resolved automatically via the management API. */ ...InstanceCommand.baseFlags, 'instance-id': Flags.string({ - dependsOn: ['project-id'], - description: 'PowerSync Cloud instance ID. Manually passed if the current context has not been linked.', + description: + 'PowerSync Cloud instance ID. Pass when the current directory is not yet linked. org-id and project-id are resolved automatically.', helpGroup: HelpGroup.CLOUD_PROJECT, required: false }), 'org-id': Flags.string({ - description: - 'Organization ID (optional). Defaults to the token’s single org when only one is available; pass explicitly if the token has multiple orgs.', + description: 'Organization ID. Auto-resolved from the instance when --instance-id is passed; rarely needed.', helpGroup: HelpGroup.CLOUD_PROJECT, required: false }), 'project-id': Flags.string({ - description: 'Project ID. Manually passed if the current context has not been linked.', + description: 'Project ID. Auto-resolved from the instance when --instance-id is passed; rarely needed.', helpGroup: HelpGroup.CLOUD_PROJECT, required: false }) @@ -156,19 +155,27 @@ export abstract class CloudInstanceCommand extends InstanceCommand { } const instance_id = flags['instance-id'] ?? (rawLink?.instance_id as string | undefined) ?? env.INSTANCE_ID; - const project_id = flags['project-id'] ?? (rawLink?.project_id as string | undefined) ?? env.PROJECT_ID; - let org_id = flags['org-id'] ?? (rawLink?.org_id as string | undefined) ?? env.ORG_ID; - - try { - if (org_id == null && instance_id != null) { - org_id = await getDefaultOrgId(); + // When --instance-id is explicitly passed, always resolve org/project from the API. + // --org-id / --project-id flags are accepted for backward compatibility but ignored. + const instanceIdFromFlag = flags['instance-id'] != null; + let project_id = instanceIdFromFlag + ? undefined + : (flags['project-id'] ?? (rawLink?.project_id as string | undefined) ?? env.PROJECT_ID); + let org_id = instanceIdFromFlag + ? undefined + : (flags['org-id'] ?? (rawLink?.org_id as string | undefined) ?? env.ORG_ID); + + if (instance_id != null && (org_id == null || project_id == null)) { + try { + const instanceMeta = await this.client.getInstance({ id: instance_id }); + org_id ??= instanceMeta.org_id; + project_id ??= instanceMeta.app_id; + } catch (error) { + this.styledError({ + error, + message: `Instance ${instance_id} was not found, or is not accessible with the current token.` + }); } - } catch (error) { - this.styledError({ - error, - message: - 'Linking is required before using this command. Provide flags, link the project (cli.yaml), or set environment variables.' - }); } if (instance_id != null || project_id != null || org_id != null) { diff --git a/packages/cli-core/src/command-types/SharedInstanceCommand.ts b/packages/cli-core/src/command-types/SharedInstanceCommand.ts index 68b8e88..2329c4d 100644 --- a/packages/cli-core/src/command-types/SharedInstanceCommand.ts +++ b/packages/cli-core/src/command-types/SharedInstanceCommand.ts @@ -16,7 +16,6 @@ import { PowerSyncManagementClient } from '@powersync/management-client'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; -import { getDefaultOrgId } from '../clients/AccountsHubClientSDKClient.js'; import { createCloudClient } from '../clients/create-cloud-client.js'; import { ensureServiceTypeMatches, ServiceType } from '../utils/ensure-service-type.js'; import { env } from '../utils/env.js'; @@ -43,18 +42,18 @@ export type SharedInstanceCommandFlags = Interfaces.InferredFlags< * - Then from environment variables. * * 2. **Per-field values** (instance_id, org_id, project_id for cloud; api_url, api_key for self-hosted): - * - Cloud: flags → cli.yaml → env. + * - Cloud: flags → cli.yaml → env; org_id and project_id auto-resolved via client.getInstance when only instance_id is known. * - Self-hosted: api_url from flag → cli.yaml → env; api_key from env → cli.yaml only (no flag). * * @example * # Use linked project (cli.yaml determines cloud vs self-hosted) * pnpm exec powersync some-shared-cmd * # Force cloud with env - * INSTANCE_ID=... ORG_ID=... PROJECT_ID=... pnpm exec powersync some-shared-cmd + * INSTANCE_ID=... pnpm exec powersync some-shared-cmd * # Force self-hosted with flag * pnpm exec powersync some-shared-cmd --api-url=https://... - * # Force cloud with flags - * pnpm exec powersync some-shared-cmd --instance-id=... --org-id=... --project-id=... + * # Force cloud with flags (--instance-id alone is sufficient) + * pnpm exec powersync some-shared-cmd --instance-id=... */ export abstract class SharedInstanceCommand extends InstanceCommand { static baseFlags = { @@ -67,20 +66,20 @@ export abstract class SharedInstanceCommand extends InstanceCommand { required: false }), 'instance-id': Flags.string({ - dependsOn: ['project-id'], description: - '[Cloud] PowerSync Cloud instance ID (BSON ObjectID). When set, context is treated as cloud (exclusive with --api-url). Resolved: flag → cli.yaml → INSTANCE_ID.', + '[Cloud] PowerSync Cloud instance ID (BSON ObjectID). When set, context is treated as cloud (exclusive with --api-url). org-id and project-id are resolved automatically. Resolved: flag → cli.yaml → INSTANCE_ID.', helpGroup: HelpGroup.CLOUD_PROJECT, required: false }), 'org-id': Flags.string({ description: - '[Cloud] Organization ID (optional). Defaults to the token’s single org when only one is available; pass explicitly if the token has multiple orgs. Resolved: flag → cli.yaml → ORG_ID.', + '[Cloud] Organization ID. Auto-resolved from the instance when --instance-id is passed; rarely needed. Resolved: flag → cli.yaml → ORG_ID.', helpGroup: HelpGroup.CLOUD_PROJECT, required: false }), 'project-id': Flags.string({ - description: '[Cloud] Project ID. Resolved: flag → cli.yaml → PROJECT_ID.', + description: + '[Cloud] Project ID. Auto-resolved from the instance when --instance-id is passed; rarely needed. Resolved: flag → cli.yaml → PROJECT_ID.', helpGroup: HelpGroup.CLOUD_PROJECT, required: false }), @@ -166,7 +165,7 @@ export abstract class SharedInstanceCommand extends InstanceCommand { const linkMissingErrorMessage = [ 'Linking is required before using this command.', - 'Provide --api-url (self-hosted) or --instance-id with --org-id and --project-id (cloud), or link the project first.' + 'Provide --api-url (self-hosted) or --instance-id (cloud), or link the project first.' ].join('\n'); // If we don't have a project type by now, we need to error @@ -189,17 +188,34 @@ export abstract class SharedInstanceCommand extends InstanceCommand { } } else { const _rawCloudCLIConfig = (rawCLIConfig as CloudCLIConfig) ?? { type: 'cloud' }; - try { - let org_id = flags['org-id'] ?? _rawCloudCLIConfig.org_id ?? env.ORG_ID; - if (org_id == null && (flags['instance-id'] || env.INSTANCE_ID)) { - org_id = await getDefaultOrgId(); + const instance_id = flags['instance-id'] ?? _rawCloudCLIConfig.instance_id ?? env.INSTANCE_ID; + // When --instance-id is explicitly passed, always resolve org/project from the API. + // --org-id / --project-id flags are accepted for backward compatibility but ignored. + const instanceIdFromFlag = flags['instance-id'] != null; + let org_id = instanceIdFromFlag ? undefined : (flags['org-id'] ?? _rawCloudCLIConfig.org_id ?? env.ORG_ID); + let project_id = instanceIdFromFlag + ? undefined + : (flags['project-id'] ?? _rawCloudCLIConfig.project_id ?? env.PROJECT_ID); + + if (instance_id != null && (org_id == null || project_id == null)) { + try { + const instanceMeta = await this.cloudClient.getInstance({ id: instance_id }); + org_id ??= instanceMeta.org_id; + project_id ??= instanceMeta.app_id; + } catch (error) { + this.styledError({ + error, + message: `Instance ${instance_id} was not found, or is not accessible with the current token.` + }); } + } + try { cliConfig = ResolvedCloudCLIConfig.decode({ ..._rawCloudCLIConfig, - instance_id: flags['instance-id'] ?? _rawCloudCLIConfig.instance_id! ?? env.INSTANCE_ID, + instance_id: instance_id!, org_id: org_id!, - project_id: flags['project-id'] ?? _rawCloudCLIConfig.project_id! ?? env.PROJECT_ID + project_id: project_id! }); } catch (error) { this.styledError({ error, message: linkMissingErrorMessage }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5bd6b85..6aaf310 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,12 +6,6 @@ settings: catalogs: default: - '@powersync/management-client': - specifier: ^0.0.6 - version: 0.0.6 - '@powersync/management-types': - specifier: ^0.0.5 - version: 0.0.5 '@powersync/service-client': specifier: ^0.0.3 version: 0.0.3 @@ -25,6 +19,8 @@ catalogs: specifier: ^0.15.0 version: 0.15.0 +pnpmfileChecksum: sha256-HLxCH33tReaJE95Lw6bAAh9xpDwj3ud/NXH2mOXbsEs= + patchedDependencies: oclif@4.22.81: hash: 7e5a3045552cab0cb2aeee4fcd9b6ea525253baa5eca6552f74904e3290ddebe @@ -101,11 +97,11 @@ importers: specifier: workspace:* version: link:../packages/schemas '@powersync/management-client': - specifier: 'catalog:' - version: 0.0.6(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) + specifier: link:/Users/luc/work/journeyapps-platform/powersync/public-packages/client + version: link:../../../journeyapps-platform/powersync/public-packages/client '@powersync/management-types': - specifier: 'catalog:' - version: 0.0.5 + specifier: link:/Users/luc/work/journeyapps-platform/powersync/public-packages/types + version: link:../../../journeyapps-platform/powersync/public-packages/types '@powersync/service-sync-rules': specifier: 'catalog:' version: 0.34.0 @@ -186,11 +182,11 @@ importers: specifier: workspace:* version: link:../schemas '@powersync/management-client': - specifier: 'catalog:' - version: 0.0.6(@types/debug@4.1.12)(@types/json-schema@7.0.15)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2) + specifier: link:/Users/luc/work/journeyapps-platform/powersync/public-packages/client + version: link:../../../../journeyapps-platform/powersync/public-packages/client '@powersync/management-types': - specifier: 'catalog:' - version: 0.0.5 + specifier: link:/Users/luc/work/journeyapps-platform/powersync/public-packages/types + version: link:../../../../journeyapps-platform/powersync/public-packages/types '@powersync/service-client': specifier: 'catalog:' version: 0.0.3(@types/debug@4.1.12)(@types/json-schema@7.0.15)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2) @@ -338,8 +334,8 @@ importers: packages/schemas: dependencies: '@powersync/management-types': - specifier: 'catalog:' - version: 0.0.5 + specifier: link:/Users/luc/work/journeyapps-platform/powersync/public-packages/types + version: link:../../../../journeyapps-platform/powersync/public-packages/types '@powersync/service-schema': specifier: 'catalog:' version: 1.20.2 @@ -1448,18 +1444,12 @@ packages: '@journeyapps-labs/common-sdk@1.0.2': resolution: {integrity: sha512-bPFrrSGdVnaVFe6ymc/desjZk02gQ8f0EKggrU1/BQIeFJvGeQ804iOJsIYmUVU1fv4qNmJD0mD0GUjxu93Z8g==} - '@journeyapps-labs/common-sdk@1.0.3': - resolution: {integrity: sha512-FjmLBhy6VjT+jrQc/uKKpHetFS+qW/s8rAZd4i+4T5Iv5kNs0kAkDBdK0ArmryMDvdrDmFZukkziGIv1Sgw3jA==} - '@journeyapps-labs/common-utils@1.0.1': resolution: {integrity: sha512-9P1f++wHSveqMQIWulLdGnDgvMdEqXP+j8eIscDm2bAuiMCIbij856AQgdrG0mQPPhL5SlUNlSGrfdKfhul2QA==} '@journeyapps-labs/micro-codecs@1.0.1': resolution: {integrity: sha512-Iy2sElOvk6C9NpzLHi0M2CYmVHVSRYK0y+BP/wRzaJ45z/3OUuXdwp9TqCEfVlqDIdDafoia7ES6X7oBWEBODw==} - '@journeyapps-labs/micro-codecs@1.0.2': - resolution: {integrity: sha512-RytuC7bFhSChlDYIxPQPEog9o6Qvb7+oMsjN72LI5A0w82HBshCy8/v+OHMEL8UiI8nsHk4KQQP9LBXbuDuBOg==} - '@journeyapps-labs/micro-errors@1.0.1': resolution: {integrity: sha512-L7a6AC0mX+AWw1q7RfFYNRrfxWrMlXMnNnFPysHBuZFrtLh4bT/4cnGwXANlm5OBNQC2urhTmtpdOXZVlxC7yw==} @@ -1605,12 +1595,6 @@ packages: resolution: {integrity: sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==} engines: {node: '>=12'} - '@powersync/management-client@0.0.6': - resolution: {integrity: sha512-s5tvk/3JUw9B1ry0X8YH30sMscqf5xkbGK0XNSZ4X6o0ATtJWxxe97Fgg1HoNTfN2W7lMSyTyZnBdf9jsVOluQ==} - - '@powersync/management-types@0.0.5': - resolution: {integrity: sha512-sh1vRo1pq0D2oxijiyy0bHz1fIVkuiZkW+hTSyDSumNtbmT18ELe7+Mto29xlCzQ10oJ1YeyskUwpi+ZWzfuIQ==} - '@powersync/service-client@0.0.3': resolution: {integrity: sha512-K83tOFdjRyFh76c4CKViRFyGJfBH9wSvtOvF2PxtbajAIPMzZEeunpnFj3vphx8CQyrDFWkR8/1Qa0BiCo30xQ==} @@ -8434,66 +8418,6 @@ snapshots: - tsx - yaml - '@journeyapps-labs/common-sdk@1.0.3(@types/debug@4.1.12)(@types/json-schema@7.0.15)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - '@journeyapps-labs/micro-errors': 1.0.1 - '@journeyapps-labs/micro-streaming': 1.0.1(@types/debug@4.1.12)(@types/json-schema@7.0.15)(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2) - '@types/node': 25.5.0 - agentkeepalive: 4.6.0 - bson: 7.2.0 - lodash: 4.17.23 - uuid: 13.0.0 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@types/debug' - - '@types/json-schema' - - '@vitest/browser' - - '@vitest/ui' - - happy-dom - - jiti - - jsdom - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - '@journeyapps-labs/common-sdk@1.0.3(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - '@journeyapps-labs/micro-errors': 1.0.1 - '@journeyapps-labs/micro-streaming': 1.0.1(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - '@types/node': 25.5.0 - agentkeepalive: 4.6.0 - bson: 7.2.0 - lodash: 4.17.23 - uuid: 13.0.0 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@types/debug' - - '@types/json-schema' - - '@vitest/browser' - - '@vitest/ui' - - happy-dom - - jiti - - jsdom - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - '@journeyapps-labs/common-utils@1.0.1': dependencies: uuid: 13.0.0 @@ -8524,38 +8448,6 @@ snapshots: - tsx - yaml - '@journeyapps-labs/micro-codecs@1.0.1(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - '@types/node': 24.10.10 - bson: 6.10.4 - ts-codec: 1.3.0 - vitest: 3.2.4(@types/node@24.10.10)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@types/debug' - - '@vitest/browser' - - '@vitest/ui' - - happy-dom - - jiti - - jsdom - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - '@journeyapps-labs/micro-codecs@1.0.2': - dependencies: - '@types/node': 24.10.10 - bson: 6.10.4 - ts-codec: 1.3.0 - '@journeyapps-labs/micro-errors@1.0.1': {} '@journeyapps-labs/micro-schema@1.0.1(@types/debug@4.1.12)(@types/json-schema@7.0.15)(@types/node@24.10.10)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2)': @@ -8590,70 +8482,6 @@ snapshots: - tsx - yaml - '@journeyapps-labs/micro-schema@1.0.1(@types/debug@4.1.12)(@types/json-schema@7.0.15)(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - '@apidevtools/json-schema-ref-parser': 14.2.1(@types/json-schema@7.0.15) - '@journeyapps-labs/micro-codecs': 1.0.1(@types/debug@4.1.12)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2) - '@journeyapps-labs/micro-errors': 1.0.1 - ajv: 8.17.1 - better-ajv-errors: 2.0.3(ajv@8.17.1) - ts-codec: 1.3.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2) - zod: 4.3.6 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@types/debug' - - '@types/json-schema' - - '@types/node' - - '@vitest/browser' - - '@vitest/ui' - - happy-dom - - jiti - - jsdom - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - '@journeyapps-labs/micro-schema@1.0.1(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - '@apidevtools/json-schema-ref-parser': 14.2.1(@types/json-schema@7.0.15) - '@journeyapps-labs/micro-codecs': 1.0.1(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - '@journeyapps-labs/micro-errors': 1.0.1 - ajv: 8.17.1 - better-ajv-errors: 2.0.3(ajv@8.17.1) - ts-codec: 1.3.0 - vitest: 3.2.4(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - zod: 4.3.6 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@types/debug' - - '@types/json-schema' - - '@types/node' - - '@vitest/browser' - - '@vitest/ui' - - happy-dom - - jiti - - jsdom - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - '@journeyapps-labs/micro-streaming@1.0.1(@types/debug@4.1.12)(@types/json-schema@7.0.15)(@types/node@24.10.10)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2)': dependencies: '@journeyapps-labs/micro-errors': 1.0.1 @@ -8682,62 +8510,6 @@ snapshots: - tsx - yaml - '@journeyapps-labs/micro-streaming@1.0.1(@types/debug@4.1.12)(@types/json-schema@7.0.15)(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - '@journeyapps-labs/micro-errors': 1.0.1 - '@journeyapps-labs/micro-schema': 1.0.1(@types/debug@4.1.12)(@types/json-schema@7.0.15)(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2) - '@types/express': 5.0.6 - bson: 6.10.4 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@types/debug' - - '@types/json-schema' - - '@types/node' - - '@vitest/browser' - - '@vitest/ui' - - happy-dom - - jiti - - jsdom - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - '@journeyapps-labs/micro-streaming@1.0.1(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - '@journeyapps-labs/micro-errors': 1.0.1 - '@journeyapps-labs/micro-schema': 1.0.1(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - '@types/express': 5.0.6 - bson: 6.10.4 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@types/debug' - - '@types/json-schema' - - '@types/node' - - '@vitest/browser' - - '@vitest/ui' - - happy-dom - - jiti - - jsdom - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -8960,67 +8732,6 @@ snapshots: '@pnpm/network.ca-file': 1.0.2 config-chain: 1.1.13 - '@powersync/management-client@0.0.6(@types/debug@4.1.12)(@types/json-schema@7.0.15)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - '@journeyapps-labs/common-sdk': 1.0.3(@types/debug@4.1.12)(@types/json-schema@7.0.15)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2) - '@powersync/management-types': 0.0.5 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@types/debug' - - '@types/json-schema' - - '@vitest/browser' - - '@vitest/ui' - - babel-plugin-macros - - happy-dom - - jiti - - jsdom - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - '@powersync/management-client@0.0.6(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)': - dependencies: - '@journeyapps-labs/common-sdk': 1.0.3(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - '@powersync/management-types': 0.0.5 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@types/debug' - - '@types/json-schema' - - '@vitest/browser' - - '@vitest/ui' - - babel-plugin-macros - - happy-dom - - jiti - - jsdom - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - '@powersync/management-types@0.0.5': - dependencies: - '@journeyapps-labs/micro-codecs': 1.0.2 - '@powersync/service-types': 0.15.0 - bson: 6.10.4 - ts-codec: 1.3.0 - transitivePeerDependencies: - - babel-plugin-macros - '@powersync/service-client@0.0.3(@types/debug@4.1.12)(@types/json-schema@7.0.15)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2)': dependencies: '@journeyapps-labs/common-sdk': 1.0.2(@types/debug@4.1.12)(@types/json-schema@7.0.15)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2) @@ -10540,6 +10251,7 @@ snapshots: '@types/node@25.5.0': dependencies: undici-types: 7.18.2 + optional: true '@types/normalize-package-data@2.4.4': {} @@ -10769,14 +10481,6 @@ snapshots: optionalDependencies: vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 @@ -10785,14 +10489,6 @@ snapshots: optionalDependencies: vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.18 @@ -14071,7 +13767,8 @@ snapshots: undici-types@7.16.0: {} - undici-types@7.18.2: {} + undici-types@7.18.2: + optional: true undici@7.22.0: {} @@ -14178,27 +13875,6 @@ snapshots: - tsx - yaml - vite-node@3.2.4(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - cac: 6.7.14 - debug: 4.4.3(supports-color@8.1.1) - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - vite-node@3.2.4(@types/node@24.10.10)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: cac: 6.7.14 @@ -14220,48 +13896,6 @@ snapshots: - tsx - yaml - vite-node@3.2.4(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - cac: 6.7.14 - debug: 4.4.3(supports-color@8.1.1) - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite-node@3.2.4(@types/node@25.5.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - cac: 6.7.14 - debug: 4.4.3(supports-color@8.1.1) - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: debug: 4.4.3(supports-color@8.1.1) @@ -14305,22 +13939,6 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - esbuild: 0.27.2 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 25.5.0 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.31.1 - tsx: 4.21.0 - yaml: 2.8.2 - vitefu@1.1.1(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)): optionalDependencies: vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) @@ -14411,133 +14029,6 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/debug@4.1.12)(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - debug: 4.4.3(supports-color@8.1.1) - expect-type: 1.3.0 - magic-string: 0.30.21 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@25.5.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/debug': 4.1.12 - '@types/node': 25.5.0 - jsdom: 27.4.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vitest@3.2.4(@types/node@24.10.10)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - debug: 4.4.3(supports-color@8.1.1) - expect-type: 1.3.0 - magic-string: 0.30.21 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 24.10.10 - jsdom: 27.4.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vitest@3.2.4(@types/node@25.5.0)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - debug: 4.4.3(supports-color@8.1.1) - expect-type: 1.3.0 - magic-string: 0.30.21 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 25.5.0 - jsdom: 27.4.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.10)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.18