@syncular/cli 0.0.0-44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+ import { resolveDefaultSyncularConfigPath } from '../paths';
5
+ import type { TargetId } from './types';
6
+ import { TARGET_IDS } from './types';
7
+
8
+ const TARGET_STATE_RELATIVE_PATH = '.syncular/target.json';
9
+ const DEFAULT_TARGET_ID: TargetId = 'spaces';
10
+
11
+ interface StoredTargetState {
12
+ target: TargetId;
13
+ }
14
+
15
+ export function listTargetIds(): readonly TargetId[] {
16
+ return TARGET_IDS;
17
+ }
18
+
19
+ export function isTargetId(value: string): value is TargetId {
20
+ return TARGET_IDS.includes(value as TargetId);
21
+ }
22
+
23
+ export function resolveTargetStatePath(cwd: string): string {
24
+ return resolve(cwd, TARGET_STATE_RELATIVE_PATH);
25
+ }
26
+
27
+ export async function readStoredTargetId(
28
+ cwd: string
29
+ ): Promise<TargetId | null> {
30
+ const statePath = resolveTargetStatePath(cwd);
31
+ if (!existsSync(statePath)) {
32
+ return null;
33
+ }
34
+
35
+ try {
36
+ const raw = await readFile(statePath, 'utf8');
37
+ const parsed = JSON.parse(raw) as Partial<StoredTargetState>;
38
+ if (typeof parsed.target !== 'string' || !isTargetId(parsed.target)) {
39
+ return null;
40
+ }
41
+ return parsed.target;
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+
47
+ export async function writeStoredTargetId(args: {
48
+ cwd: string;
49
+ targetId: TargetId;
50
+ }): Promise<string> {
51
+ const statePath = resolveTargetStatePath(args.cwd);
52
+ await mkdir(resolve(args.cwd, '.syncular'), { recursive: true });
53
+ await writeFile(
54
+ statePath,
55
+ `${JSON.stringify({ target: args.targetId } satisfies StoredTargetState, null, 2)}\n`,
56
+ 'utf8'
57
+ );
58
+ return statePath;
59
+ }
60
+
61
+ export async function resolveEffectiveTargetId(args: {
62
+ cwd: string;
63
+ explicitTargetId: string | null;
64
+ }): Promise<{
65
+ source: 'flag' | 'state' | 'default';
66
+ targetId: TargetId;
67
+ }> {
68
+ if (args.explicitTargetId) {
69
+ if (!isTargetId(args.explicitTargetId)) {
70
+ throw new Error(
71
+ `Unsupported --target "${args.explicitTargetId}". Supported targets: ${TARGET_IDS.join(', ')}.`
72
+ );
73
+ }
74
+ return {
75
+ source: 'flag',
76
+ targetId: args.explicitTargetId,
77
+ };
78
+ }
79
+
80
+ const storedTargetId = await readStoredTargetId(args.cwd);
81
+ if (storedTargetId) {
82
+ return {
83
+ source: 'state',
84
+ targetId: storedTargetId,
85
+ };
86
+ }
87
+
88
+ return {
89
+ source: 'default',
90
+ targetId: DEFAULT_TARGET_ID,
91
+ };
92
+ }
93
+
94
+ export function resolveTargetDefaultConfigPath(args: {
95
+ cwd: string;
96
+ targetId: TargetId;
97
+ }): string {
98
+ return resolveDefaultSyncularConfigPath(args.cwd);
99
+ }
@@ -0,0 +1,8 @@
1
+ export const TARGET_IDS = ['spaces'] as const;
2
+ export type TargetId = (typeof TARGET_IDS)[number];
3
+
4
+ export interface TargetDefinition {
5
+ id: TargetId;
6
+ description: string;
7
+ defaultBuildpackId: 'contract-worker';
8
+ }
@@ -0,0 +1,2 @@
1
+ export * from './registry';
2
+ export * from './syncular-types';
@@ -0,0 +1,42 @@
1
+ import { TEMPLATE_EXTENSION_MANIFEST } from '../extensions';
2
+
3
+ type TemplateManifest = typeof TEMPLATE_EXTENSION_MANIFEST;
4
+ function buildTemplateRegistry(manifest: TemplateManifest) {
5
+ const entries = Object.entries(manifest);
6
+ const seenTemplateIds = new Set<string>();
7
+
8
+ for (const [registryKey, manifestEntry] of entries) {
9
+ const templateId = manifestEntry.template.id;
10
+ if (templateId.length === 0) {
11
+ throw new Error(`Template "${registryKey}" has an empty id.`);
12
+ }
13
+
14
+ if (seenTemplateIds.has(templateId)) {
15
+ throw new Error(`Duplicate template id in manifest: "${templateId}".`);
16
+ }
17
+ seenTemplateIds.add(templateId);
18
+ }
19
+
20
+ return Object.freeze(
21
+ Object.fromEntries(
22
+ entries.map(([registryKey, manifestEntry]) => [
23
+ registryKey,
24
+ manifestEntry.template,
25
+ ])
26
+ )
27
+ ) as {
28
+ [K in keyof TemplateManifest]: TemplateManifest[K]['template'];
29
+ };
30
+ }
31
+
32
+ export const templateRegistry = buildTemplateRegistry(
33
+ TEMPLATE_EXTENSION_MANIFEST
34
+ );
35
+
36
+ const TEMPLATE_IDS = Object.freeze(
37
+ Object.values(templateRegistry).map((template) => template.id)
38
+ ) as readonly string[];
39
+
40
+ export function listTemplateIds(): readonly string[] {
41
+ return TEMPLATE_IDS;
42
+ }
@@ -0,0 +1,10 @@
1
+ export type {
2
+ SyncularClientDialect,
3
+ SyncularElectronDialect,
4
+ SyncularLibrariesTarget,
5
+ SyncularServerDialect,
6
+ } from '@syncular/cli-template-syncular-libraries';
7
+ export {
8
+ DEFAULT_SYNCULAR_LIBRARIES_TARGETS,
9
+ SYNCULAR_LIBRARIES_TARGETS,
10
+ } from '@syncular/cli-template-syncular-libraries';
package/src/types.ts ADDED
@@ -0,0 +1,67 @@
1
+ export type RootCommand =
2
+ | 'help'
3
+ | 'version'
4
+ | 'doctor'
5
+ | 'console'
6
+ | 'login'
7
+ | 'logout'
8
+ | 'whoami'
9
+ | 'create-space'
10
+ | 'create'
11
+ | 'dev'
12
+ | 'typegen'
13
+ | 'migrate-status'
14
+ | 'migrate-up'
15
+ | 'build'
16
+ | 'eject'
17
+ | 'target'
18
+ | 'deploy'
19
+ | 'verify'
20
+ | 'rollback'
21
+ | 'deployments'
22
+ | 'interactive';
23
+
24
+ export interface ParsedArgs {
25
+ command: RootCommand | null;
26
+ subcommand: string | null;
27
+ flags: Set<string>;
28
+ flagValues: Map<string, string>;
29
+ positionals: string[];
30
+ }
31
+
32
+ export interface InteractiveField {
33
+ id: string;
34
+ label: string;
35
+ kind?: 'string' | 'number' | 'boolean';
36
+ placeholder?: string;
37
+ required?: boolean;
38
+ defaultValue?: string;
39
+ }
40
+
41
+ export interface InteractiveCommand {
42
+ id:
43
+ | 'doctor'
44
+ | 'console'
45
+ | 'create'
46
+ | 'create-space'
47
+ | 'dev'
48
+ | 'typegen'
49
+ | 'migrate-status'
50
+ | 'migrate-up'
51
+ | 'build'
52
+ | 'eject'
53
+ | 'target'
54
+ | 'deploy'
55
+ | 'verify'
56
+ | 'deployments'
57
+ | 'rollback'
58
+ | 'login'
59
+ | 'logout'
60
+ | 'whoami'
61
+ | 'help'
62
+ | 'quit';
63
+ label: string;
64
+ description: string;
65
+ fields?: InteractiveField[];
66
+ buildArgv(values: Record<string, string>): string[] | null;
67
+ }