@apso/cli 0.8.6 → 0.10.1

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.
Files changed (91) hide show
  1. package/README.md +221 -1653
  2. package/dist/commands/config.d.ts +13 -0
  3. package/dist/commands/config.js +114 -0
  4. package/dist/commands/deploy.d.ts +11 -0
  5. package/dist/commands/deploy.js +141 -0
  6. package/dist/commands/dev.d.ts +15 -0
  7. package/dist/commands/dev.js +95 -0
  8. package/dist/commands/generate.d.ts +12 -0
  9. package/dist/commands/generate.js +179 -0
  10. package/dist/commands/init.d.ts +16 -0
  11. package/dist/commands/init.js +313 -0
  12. package/dist/commands/link.d.ts +11 -0
  13. package/dist/commands/link.js +139 -0
  14. package/dist/commands/login.d.ts +22 -0
  15. package/dist/commands/login.js +345 -0
  16. package/dist/commands/logout.d.ts +9 -0
  17. package/dist/commands/logout.js +38 -0
  18. package/dist/commands/logs.d.ts +10 -0
  19. package/dist/commands/logs.js +64 -0
  20. package/dist/commands/mcp/serve.d.ts +11 -0
  21. package/dist/commands/mcp/serve.js +818 -0
  22. package/dist/commands/migrate.d.ts +11 -0
  23. package/dist/commands/migrate.js +137 -0
  24. package/dist/commands/open.d.ts +10 -0
  25. package/dist/commands/open.js +79 -0
  26. package/dist/commands/projects.d.ts +10 -0
  27. package/dist/commands/projects.js +106 -0
  28. package/dist/commands/schema/diff.d.ts +7 -0
  29. package/dist/commands/schema/diff.js +63 -0
  30. package/dist/commands/schema/pull.d.ts +9 -0
  31. package/dist/commands/schema/pull.js +81 -0
  32. package/dist/commands/schema/push.d.ts +9 -0
  33. package/dist/commands/schema/push.js +97 -0
  34. package/dist/commands/schema/validate.d.ts +9 -0
  35. package/dist/commands/schema/validate.js +90 -0
  36. package/dist/commands/server/new.d.ts +2 -19
  37. package/dist/commands/server/new.js +6 -192
  38. package/dist/commands/server/scaffold.d.ts +2 -25
  39. package/dist/commands/server/scaffold.js +6 -312
  40. package/dist/commands/status.d.ts +7 -0
  41. package/dist/commands/status.js +53 -0
  42. package/dist/commands/unlink.d.ts +9 -0
  43. package/dist/commands/unlink.js +47 -0
  44. package/dist/commands/whoami.d.ts +10 -0
  45. package/dist/commands/whoami.js +97 -0
  46. package/dist/lib/api/client.js +1 -1
  47. package/dist/lib/api/services.js +3 -3
  48. package/dist/lib/api/types.d.ts +9 -2
  49. package/dist/lib/apsorc-parser.d.ts +0 -19
  50. package/dist/lib/apsorc-parser.js +2 -73
  51. package/dist/lib/guards.d.ts +3 -20
  52. package/dist/lib/guards.js +1 -113
  53. package/dist/lib/index.d.ts +1 -9
  54. package/dist/lib/index.js +1 -18
  55. package/dist/lib/migrate/entity-generator.d.ts +14 -0
  56. package/dist/lib/migrate/entity-generator.js +7 -0
  57. package/dist/lib/migrate/sandbox.d.ts +42 -0
  58. package/dist/lib/migrate/sandbox.js +337 -0
  59. package/dist/lib/migrate/snapshot.d.ts +80 -0
  60. package/dist/lib/migrate/snapshot.js +100 -0
  61. package/dist/lib/templates/python/models/model-col-datetime.eta +1 -1
  62. package/dist/lib/templates/python/models/model-col-string.eta +1 -1
  63. package/dist/lib/templates/python/models/model-col-text.eta +1 -1
  64. package/dist/lib/templates/python/models/model-col-varchar.eta +1 -1
  65. package/dist/lib/utils/field.d.ts +12 -0
  66. package/dist/lib/utils/field.js +80 -1
  67. package/dist/lib/utils/schema-convert.d.ts +71 -0
  68. package/dist/lib/utils/schema-convert.js +169 -0
  69. package/dist/lib/utils/spinner.d.ts +19 -0
  70. package/dist/lib/utils/spinner.js +87 -0
  71. package/dist/lib/utils/template.d.ts +12 -0
  72. package/dist/lib/utils/template.js +49 -0
  73. package/npm-shrinkwrap.json +18118 -0
  74. package/oclif.manifest.json +547 -41
  75. package/package.json +26 -5
  76. package/dist/lib/controller.d.ts +0 -10
  77. package/dist/lib/controller.js +0 -99
  78. package/dist/lib/dto.d.ts +0 -16
  79. package/dist/lib/dto.js +0 -92
  80. package/dist/lib/entity.d.ts +0 -19
  81. package/dist/lib/entity.js +0 -56
  82. package/dist/lib/enums.d.ts +0 -6
  83. package/dist/lib/enums.js +0 -28
  84. package/dist/lib/gql-dto.d.ts +0 -3
  85. package/dist/lib/gql-dto.js +0 -39
  86. package/dist/lib/index-module.d.ts +0 -13
  87. package/dist/lib/index-module.js +0 -26
  88. package/dist/lib/module.d.ts +0 -13
  89. package/dist/lib/module.js +0 -42
  90. package/dist/lib/service.d.ts +0 -2
  91. package/dist/lib/service.js +0 -61
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Schema Conversion Utilities
3
+ *
4
+ * Converts between local .apsorc format and platform ServiceSchema format.
5
+ */
6
+ import { Entity } from "../types/entity";
7
+ import { RelationshipMap } from "../types/relationship";
8
+ import { ServiceSchema } from "../api/types";
9
+ /**
10
+ * Parsed .apsorc data shape (subset of ParsedApsorc from apsorc-parser.ts)
11
+ */
12
+ export interface ParsedApsorcInput {
13
+ rootFolder: string;
14
+ apiType: string;
15
+ entities: Entity[];
16
+ relationshipMap: RelationshipMap;
17
+ }
18
+ /**
19
+ * Shape returned by serviceSchemaToApsorc for writing back to .apsorc
20
+ */
21
+ export interface ApsorcOutput {
22
+ version: number;
23
+ rootFolder: string;
24
+ apiType: string;
25
+ entities: ApsorcEntityOutput[];
26
+ relationships: ApsorcRelationshipOutput[];
27
+ }
28
+ export interface ApsorcEntityOutput {
29
+ name: string;
30
+ primaryKeyType?: "serial" | "uuid";
31
+ created_at?: boolean;
32
+ updated_at?: boolean;
33
+ fields?: ApsorcFieldOutput[];
34
+ scopeBy?: string | string[];
35
+ }
36
+ export interface ApsorcFieldOutput {
37
+ name: string;
38
+ type: string;
39
+ nullable?: boolean;
40
+ unique?: boolean;
41
+ default?: unknown;
42
+ index?: boolean;
43
+ }
44
+ export interface ApsorcRelationshipOutput {
45
+ from: string;
46
+ to: string;
47
+ type: "OneToMany" | "ManyToOne" | "ManyToMany" | "OneToOne";
48
+ to_name?: string;
49
+ nullable?: boolean;
50
+ bi_directional?: boolean;
51
+ cascadeDelete?: boolean;
52
+ }
53
+ /**
54
+ * Convert parsed .apsorc data to platform ServiceSchema format.
55
+ *
56
+ * The local .apsorc stores relationships as a flat RelationshipMap keyed by entity name.
57
+ * The platform ServiceSchema stores relationships embedded per-entity.
58
+ */
59
+ export declare function apsorcToServiceSchema(parsed: ParsedApsorcInput): Omit<ServiceSchema, "id" | "serviceId" | "version" | "createdAt" | "updatedAt">;
60
+ /**
61
+ * Convert platform ServiceSchema to .apsorc format for writing to disk.
62
+ *
63
+ * Reverses the conversion: flattens per-entity relationships back into a
64
+ * top-level relationships array in v2 format.
65
+ */
66
+ export declare function serviceSchemaToApsorc(schema: ServiceSchema): ApsorcOutput;
67
+ /**
68
+ * Compute a SHA-256 hash of a schema for sync tracking.
69
+ * Uses deterministic JSON serialization (recursively sorted keys).
70
+ */
71
+ export declare function computeSchemaHash(schema: unknown): string;
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /**
3
+ * Schema Conversion Utilities
4
+ *
5
+ * Converts between local .apsorc format and platform ServiceSchema format.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.computeSchemaHash = exports.serviceSchemaToApsorc = exports.apsorcToServiceSchema = void 0;
9
+ const tslib_1 = require("tslib");
10
+ const crypto = tslib_1.__importStar(require("crypto"));
11
+ /**
12
+ * Map from SchemaRelationship type format to ApsorcRelationship type format
13
+ */
14
+ function platformTypeToApsorcType(type) {
15
+ const map = {
16
+ "one-to-one": "OneToOne",
17
+ "one-to-many": "OneToMany",
18
+ "many-to-one": "ManyToOne",
19
+ "many-to-many": "ManyToMany",
20
+ };
21
+ return map[type];
22
+ }
23
+ /**
24
+ * Map from ApsorcRelationship type format to SchemaRelationship type format
25
+ */
26
+ function apsorcTypeToPlatformType(type) {
27
+ const map = {
28
+ OneToOne: "one-to-one",
29
+ OneToMany: "one-to-many",
30
+ ManyToOne: "many-to-one",
31
+ ManyToMany: "many-to-many",
32
+ };
33
+ return map[type] || "many-to-one";
34
+ }
35
+ /**
36
+ * Convert parsed .apsorc data to platform ServiceSchema format.
37
+ *
38
+ * The local .apsorc stores relationships as a flat RelationshipMap keyed by entity name.
39
+ * The platform ServiceSchema stores relationships embedded per-entity.
40
+ */
41
+ function apsorcToServiceSchema(parsed) {
42
+ const entities = parsed.entities.map((entity) => {
43
+ // Convert fields
44
+ const fields = (entity.fields || []).map((field) => {
45
+ var _a;
46
+ return ({
47
+ name: field.name,
48
+ type: field.type,
49
+ nullable: field.nullable,
50
+ unique: field.unique,
51
+ default: (_a = field.default) !== null && _a !== void 0 ? _a : undefined,
52
+ primaryKey: field.primary,
53
+ index: field.index,
54
+ });
55
+ });
56
+ // Get relationships for this entity from the map
57
+ const entityRelationships = parsed.relationshipMap[entity.name] || [];
58
+ const relationships = entityRelationships.map((rel) => ({
59
+ name: rel.name,
60
+ type: apsorcTypeToPlatformType(rel.type),
61
+ target: rel.name,
62
+ inverseSide: rel.referenceName || undefined,
63
+ cascade: rel.cascadeDelete,
64
+ nullable: rel.nullable,
65
+ }));
66
+ const schemaEntity = {
67
+ name: entity.name,
68
+ fields,
69
+ relationships: relationships.length > 0 ? relationships : undefined,
70
+ scopeBy: entity.scopeBy
71
+ ? Array.isArray(entity.scopeBy)
72
+ ? entity.scopeBy
73
+ : [entity.scopeBy]
74
+ : undefined,
75
+ };
76
+ return schemaEntity;
77
+ });
78
+ return { entities };
79
+ }
80
+ exports.apsorcToServiceSchema = apsorcToServiceSchema;
81
+ /**
82
+ * Convert platform ServiceSchema to .apsorc format for writing to disk.
83
+ *
84
+ * Reverses the conversion: flattens per-entity relationships back into a
85
+ * top-level relationships array in v2 format.
86
+ */
87
+ function serviceSchemaToApsorc(schema) {
88
+ const entities = [];
89
+ const relationships = [];
90
+ for (const schemaEntity of schema.entities) {
91
+ // Convert fields back to .apsorc format
92
+ const fields = (schemaEntity.fields || [])
93
+ .filter((f) => !f.primaryKey) // Primary keys are implicit in .apsorc
94
+ .map((field) => {
95
+ const out = {
96
+ name: field.name,
97
+ type: field.type,
98
+ };
99
+ if (field.nullable)
100
+ out.nullable = true;
101
+ if (field.unique)
102
+ out.unique = true;
103
+ if (field.default !== undefined)
104
+ out.default = field.default;
105
+ if (field.index)
106
+ out.index = true;
107
+ return out;
108
+ });
109
+ const entityOut = {
110
+ name: schemaEntity.name,
111
+ };
112
+ if (fields.length > 0) {
113
+ entityOut.fields = fields;
114
+ }
115
+ if (schemaEntity.scopeBy && schemaEntity.scopeBy.length > 0) {
116
+ entityOut.scopeBy =
117
+ schemaEntity.scopeBy.length === 1
118
+ ? schemaEntity.scopeBy[0]
119
+ : schemaEntity.scopeBy;
120
+ }
121
+ entities.push(entityOut);
122
+ // Convert per-entity relationships to flat array
123
+ if (schemaEntity.relationships) {
124
+ for (const rel of schemaEntity.relationships) {
125
+ relationships.push({
126
+ from: schemaEntity.name,
127
+ to: rel.target,
128
+ type: platformTypeToApsorcType(rel.type),
129
+ to_name: rel.inverseSide || undefined,
130
+ nullable: rel.nullable,
131
+ cascadeDelete: rel.cascade,
132
+ });
133
+ }
134
+ }
135
+ }
136
+ return {
137
+ version: 2,
138
+ rootFolder: "src",
139
+ apiType: "rest",
140
+ entities,
141
+ relationships,
142
+ };
143
+ }
144
+ exports.serviceSchemaToApsorc = serviceSchemaToApsorc;
145
+ /**
146
+ * Recursively sort all object keys for deterministic serialization.
147
+ */
148
+ function sortKeys(value) {
149
+ if (Array.isArray(value)) {
150
+ return value.map(sortKeys);
151
+ }
152
+ if (value !== null && typeof value === "object") {
153
+ const sorted = {};
154
+ for (const key of Object.keys(value).sort()) {
155
+ sorted[key] = sortKeys(value[key]);
156
+ }
157
+ return sorted;
158
+ }
159
+ return value;
160
+ }
161
+ /**
162
+ * Compute a SHA-256 hash of a schema for sync tracking.
163
+ * Uses deterministic JSON serialization (recursively sorted keys).
164
+ */
165
+ function computeSchemaHash(schema) {
166
+ const serialized = JSON.stringify(sortKeys(schema));
167
+ return crypto.createHash("sha256").update(serialized).digest("hex");
168
+ }
169
+ exports.computeSchemaHash = computeSchemaHash;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Spinner Utility
3
+ *
4
+ * Thin wrapper around `ora` for consistent spinner behavior.
5
+ * Respects the noColor config setting.
6
+ */
7
+ interface SpinnerInstance {
8
+ start(text?: string): SpinnerInstance;
9
+ stop(): SpinnerInstance;
10
+ succeed(text?: string): SpinnerInstance;
11
+ fail(text?: string): SpinnerInstance;
12
+ text: string;
13
+ }
14
+ /**
15
+ * Create a spinner that respects noColor config.
16
+ * Falls back to simple log messages if ora is not available.
17
+ */
18
+ export declare function createSpinner(text: string): Promise<SpinnerInstance>;
19
+ export {};
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /**
3
+ * Spinner Utility
4
+ *
5
+ * Thin wrapper around `ora` for consistent spinner behavior.
6
+ * Respects the noColor config setting.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || function (mod) {
25
+ if (mod && mod.__esModule) return mod;
26
+ var result = {};
27
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
28
+ __setModuleDefault(result, mod);
29
+ return result;
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.createSpinner = void 0;
33
+ const config_1 = require("../config");
34
+ /**
35
+ * Create a spinner that respects noColor config.
36
+ * Falls back to simple log messages if ora is not available.
37
+ */
38
+ async function createSpinner(text) {
39
+ const config = config_1.globalConfig.read();
40
+ try {
41
+ // Dynamic import to keep ora optional at startup
42
+ const ora = (await Promise.resolve().then(() => __importStar(require("ora")))).default;
43
+ const spinner = ora({
44
+ text,
45
+ color: config.noColor ? undefined : "cyan",
46
+ isSilent: false,
47
+ });
48
+ return spinner;
49
+ }
50
+ catch {
51
+ // Fallback: simple text output when ora is not installed
52
+ return createFallbackSpinner(text);
53
+ }
54
+ }
55
+ exports.createSpinner = createSpinner;
56
+ /**
57
+ * Fallback spinner that uses plain text output.
58
+ */
59
+ function createFallbackSpinner(initialText) {
60
+ let currentText = initialText;
61
+ const instance = {
62
+ get text() {
63
+ return currentText;
64
+ },
65
+ set text(value) {
66
+ currentText = value;
67
+ },
68
+ start(text) {
69
+ if (text)
70
+ currentText = text;
71
+ console.log(` ${currentText}...`);
72
+ return instance;
73
+ },
74
+ stop() {
75
+ return instance;
76
+ },
77
+ succeed(text) {
78
+ console.log(` ${text || currentText}`);
79
+ return instance;
80
+ },
81
+ fail(text) {
82
+ console.log(` ${text || currentText}`);
83
+ return instance;
84
+ },
85
+ };
86
+ return instance;
87
+ }
@@ -0,0 +1,12 @@
1
+ import { TargetLanguage } from "../types";
2
+ export declare const TEMPLATE_REPOS: Record<TargetLanguage, string>;
3
+ export declare const PROJECT_NAME_PATTERN: RegExp;
4
+ /**
5
+ * Clone a template repository into the given project path.
6
+ * Removes the .git directory after cloning.
7
+ */
8
+ export declare function cloneTemplate(projectPath: string, language: TargetLanguage, log: (msg: string) => void): void;
9
+ /**
10
+ * Initialize a fresh git repository in the given directory.
11
+ */
12
+ export declare function initGitRepo(projectPath: string): void;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initGitRepo = exports.cloneTemplate = exports.PROJECT_NAME_PATTERN = exports.TEMPLATE_REPOS = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs = tslib_1.__importStar(require("fs"));
6
+ const path = tslib_1.__importStar(require("path"));
7
+ const shelljs_1 = tslib_1.__importDefault(require("shelljs"));
8
+ exports.TEMPLATE_REPOS = {
9
+ typescript: "https://github.com/apsoai/service-template.git",
10
+ python: "https://github.com/apsoai/service-template-python.git",
11
+ go: "https://github.com/apsoai/service-template-go.git",
12
+ };
13
+ exports.PROJECT_NAME_PATTERN = /^[A-Za-z][\w-]*$/;
14
+ /**
15
+ * Clone a template repository into the given project path.
16
+ * Removes the .git directory after cloning.
17
+ */
18
+ function cloneTemplate(projectPath, language, log) {
19
+ const repoUrl = exports.TEMPLATE_REPOS[language];
20
+ log(`Cloning ${language} service template...`);
21
+ if (fs.existsSync(projectPath)) {
22
+ throw new Error(`Directory already exists: ${projectPath}`);
23
+ }
24
+ try {
25
+ fs.mkdirSync(projectPath, { recursive: true });
26
+ }
27
+ catch (error) {
28
+ throw new Error(`Failed to create directory: ${error.message}`);
29
+ }
30
+ const cloneResult = shelljs_1.default.exec(`git clone --depth=1 --branch=main "${repoUrl}" "${projectPath}"`, { silent: true });
31
+ if (cloneResult.code !== 0) {
32
+ shelljs_1.default.rm("-rf", projectPath);
33
+ throw new Error(`Failed to clone the template repository from GitHub.\n` +
34
+ `Error Output:\n${cloneResult.stderr}\n\n` +
35
+ `Please check your network connection and ensure the repository exists at ${repoUrl}`);
36
+ }
37
+ shelljs_1.default.rm("-rf", path.join(projectPath, ".git"));
38
+ }
39
+ exports.cloneTemplate = cloneTemplate;
40
+ /**
41
+ * Initialize a fresh git repository in the given directory.
42
+ */
43
+ function initGitRepo(projectPath) {
44
+ const result = shelljs_1.default.exec(`git init "${projectPath}"`, { silent: true });
45
+ if (result.code !== 0) {
46
+ throw new Error(`Failed to initialize git repository: ${result.stderr}`);
47
+ }
48
+ }
49
+ exports.initGitRepo = initGitRepo;