@apso/cli 0.8.6 → 0.10.2

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
@@ -1,321 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- const core_1 = require("@oclif/core");
5
- const path = tslib_1.__importStar(require("path"));
6
- const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
7
- const lib_1 = require("../../lib");
8
4
  const base_command_1 = tslib_1.__importDefault(require("../../lib/base-command"));
9
- const apsorc_parser_1 = require("../../lib/apsorc-parser");
10
- const perf_hooks_1 = require("perf_hooks");
11
- const Eta = tslib_1.__importStar(require("eta"));
12
- const file_system_1 = require("../../lib/utils/file-system");
13
- Eta.configure({
14
- views: path.join(__dirname, "../../lib/templates"),
15
- cache: false,
16
- });
17
5
  class Scaffold extends base_command_1.default {
18
- async scaffoldServer(options) {
19
- const { dir, entity, relationshipMap, apiType, allEntities } = options;
20
- const entityBuildStart = perf_hooks_1.performance.now();
21
- this.log(`Building... ${entity.name}`);
22
- const entityName = entity.name;
23
- const filePath = path.join(dir, entityName);
24
- const entityRelationships = relationshipMap[entity.name] || [];
25
- await (0, lib_1.createEntity)({
26
- apiBaseDir: filePath,
27
- entity,
28
- relationships: entityRelationships,
29
- apiType,
30
- allEntities,
31
- });
32
- switch (apiType) {
33
- case apsorc_parser_1.ApiType.Graphql:
34
- await this.setupGraphqlFiles(dir, entity, relationshipMap);
35
- break;
36
- case apsorc_parser_1.ApiType.Rest:
37
- await this.setupRestFiles(dir, entity, relationshipMap, apiType, allEntities);
38
- break;
39
- default:
40
- break;
41
- }
42
- await (0, lib_1.createModule)(filePath, entity, { apiType });
43
- const entityBuildTime = perf_hooks_1.performance.now() - entityBuildStart;
44
- console.log(`[apso] Finished building entity '${entity.name}' in ${entityBuildTime.toFixed(2)} ms`);
45
- }
46
- async setupRestFiles(dir, entity, relationshipMap, apiType, allEntities) {
47
- const filePath = path.join(dir, entity.name);
48
- const entityRelationships = relationshipMap[entity.name] || [];
49
- const tDto = perf_hooks_1.performance.now();
50
- await (0, lib_1.createDto)(filePath, entity, entityRelationships, {
51
- apiType,
52
- allEntities,
53
- });
54
- if (process.env.DEBUG) {
55
- console.log(`[timing] createDto for ${entity.name}: ${(perf_hooks_1.performance.now() - tDto).toFixed(2)}ms`);
56
- const used = process.memoryUsage();
57
- console.log(`[mem] heapUsed after createDto for ${entity.name}: ${(used.heapUsed /
58
- 1024 /
59
- 1024).toFixed(2)} MB`);
60
- }
61
- const tService = perf_hooks_1.performance.now();
62
- await (0, lib_1.createService)(filePath, entity, relationshipMap);
63
- if (process.env.DEBUG) {
64
- console.log(`[timing] createService for ${entity.name}: ${(perf_hooks_1.performance.now() - tService).toFixed(2)}ms`);
65
- const used = process.memoryUsage();
66
- console.log(`[mem] heapUsed after createService for ${entity.name}: ${(used.heapUsed /
67
- 1024 /
68
- 1024).toFixed(2)} MB`);
69
- }
70
- const tController = perf_hooks_1.performance.now();
71
- await (0, lib_1.createController)(filePath, entity, relationshipMap);
72
- if (process.env.DEBUG) {
73
- console.log(`[timing] createController for ${entity.name}: ${(perf_hooks_1.performance.now() - tController).toFixed(2)}ms`);
74
- }
75
- }
76
- async setupGraphqlFiles(dir, entity, relationshipMap) {
77
- const filePath = path.join(dir, entity.name);
78
- const entityRelationships = relationshipMap[entity.name] || [];
79
- await (0, lib_1.createGqlDTO)(filePath, entity, entityRelationships);
80
- }
81
6
  async run() {
82
- const { flags } = await this.parse(Scaffold);
83
- const skipFormat = flags["skip-format"];
84
- const totalBuildStart = perf_hooks_1.performance.now();
85
- const { rootFolder, entities, relationshipMap, apiType, auth, language: configLanguage } = (0, lib_1.parseApsorc)();
86
- // Resolve language: flag > .apsorc > prompt
87
- let language;
88
- if (flags.language) {
89
- language = flags.language;
90
- }
91
- else if (configLanguage && (0, lib_1.isLanguageSupported)(configLanguage)) {
92
- language = configLanguage;
93
- console.log(`[apso] Using language from .apsorc: ${language}`);
94
- }
95
- else {
96
- // Prompt the user
97
- const implementedLanguages = (0, lib_1.getImplementedLanguages)();
98
- const { selectedLanguage } = await inquirer_1.default.prompt([
99
- {
100
- type: "list",
101
- name: "selectedLanguage",
102
- message: "Select target language for code generation:",
103
- choices: implementedLanguages.map((lang) => ({
104
- name: lang === "typescript" ? "TypeScript (NestJS + TypeORM)" :
105
- lang === "python" ? "Python (FastAPI + SQLAlchemy)" :
106
- "Go (Gin + GORM)",
107
- value: lang,
108
- })),
109
- default: "typescript",
110
- },
111
- ]);
112
- language = selectedLanguage;
113
- }
114
- // Validate language support
115
- if (!(0, lib_1.isLanguageSupported)(language)) {
116
- this.error(`Unsupported language: ${language}. Supported: typescript, python, go`);
117
- }
118
- const implementedLanguages = (0, lib_1.getImplementedLanguages)();
119
- if (!implementedLanguages.includes(language)) {
120
- this.error(`Language '${language}' is not yet implemented. Currently available: ${implementedLanguages.join(", ")}`);
121
- }
122
- const rootPath = path.join(process.cwd(), rootFolder);
123
- const autogenPath = path.join(rootPath, "autogen");
124
- const lowerCaseApiType = apiType.toLowerCase();
125
- console.log(`[apso] Generating ${language} code for ${entities.length} entities...`);
126
- // For TypeScript, use the existing code path (for backward compatibility)
127
- // For other languages, use the new generator system
128
- await (language === "typescript" ? this.scaffoldTypeScript({
129
- autogenPath,
130
- rootPath,
131
- entities,
132
- relationshipMap,
133
- apiType: lowerCaseApiType,
134
- auth,
135
- skipFormat,
136
- }) : this.scaffoldWithGenerator({
137
- language,
138
- rootFolder,
139
- autogenPath,
140
- entities,
141
- relationshipMap,
142
- apiType: lowerCaseApiType,
143
- auth,
144
- skipFormat,
145
- }));
146
- const totalBuildTime = perf_hooks_1.performance.now() - totalBuildStart;
147
- console.log(`[apso] Finished building all entities in ${totalBuildTime.toFixed(2)} ms`);
148
- }
149
- /**
150
- * Scaffolds TypeScript code using the existing code path (for backward compatibility)
151
- */
152
- async scaffoldTypeScript(options) {
153
- const { autogenPath, rootPath, entities, relationshipMap, apiType, auth, skipFormat } = options;
154
- await (0, lib_1.createEnums)(autogenPath, entities, apiType);
155
- await Promise.all(entities.map(async (entity) => {
156
- const scaffoldModel = this.scaffoldServer.bind(this);
157
- await scaffoldModel({
158
- dir: autogenPath,
159
- entity,
160
- relationshipMap,
161
- apiType,
162
- allEntities: entities,
163
- });
164
- if (process.env.DEBUG) {
165
- const used = process.memoryUsage();
166
- console.log(`[mem] heapUsed after ${entity.name}: ${(used.heapUsed /
167
- 1024 /
168
- 1024).toFixed(2)} MB`);
169
- }
170
- }));
171
- // Generate guards (auth and/or scope) based on .apsorc configuration
172
- await (0, lib_1.createGuards)(rootPath, entities, auth);
173
- await (0, lib_1.createIndexAppModule)(autogenPath, entities, apiType);
174
- if (skipFormat) {
175
- console.log("[apso] Skipping formatting (--skip-format flag set)");
176
- }
177
- else {
178
- const formatStart = perf_hooks_1.performance.now();
179
- console.log("[apso] Formatting files...");
180
- await this.runNpmCommand(["run", "format", "src/autogen/**/*.ts", "src/guards/**/*.ts"], true);
181
- const formatTime = perf_hooks_1.performance.now() - formatStart;
182
- console.log(`[apso] Finished formatting in ${formatTime.toFixed(2)} ms`);
183
- }
184
- }
185
- /**
186
- * Scaffolds code using the new generator system (for Python, Go, and future languages)
187
- * Note: Sequential file operations are intentional to provide progress feedback
188
- */
189
- /* eslint-disable no-await-in-loop */
190
- async scaffoldWithGenerator(options) {
191
- const { language, rootFolder, autogenPath, entities, relationshipMap, apiType, auth } = options;
192
- // Create generator configuration
193
- const generatorConfig = {
194
- language,
195
- rootFolder,
196
- apiType,
197
- entities,
198
- relationshipMap,
199
- auth,
200
- };
201
- // Create the appropriate generator
202
- const generator = (0, lib_1.createGenerator)(generatorConfig);
203
- // Validate configuration
204
- const validationResult = generator.validateConfig(generatorConfig);
205
- if (!validationResult.valid) {
206
- this.error(`Configuration validation failed:\n${validationResult.errors.join("\n")}`);
207
- }
208
- if (validationResult.warnings.length > 0) {
209
- console.log(`[apso] Warnings:\n${validationResult.warnings.join("\n")}`);
210
- }
211
- // Generate enums
212
- const enumFiles = await generator.generateEnums(entities, apiType);
213
- for (const file of enumFiles) {
214
- const fullPath = path.join(autogenPath, file.path);
215
- await (0, file_system_1.createFile)(fullPath, file.content);
216
- console.log(`[apso] Generated ${fullPath}`);
217
- }
218
- // Generate files for each entity
219
- for (const entity of entities) {
220
- console.log(`[apso] Building... ${entity.name}`);
221
- const entityBuildStart = perf_hooks_1.performance.now();
222
- const entityRelationships = relationshipMap[entity.name] || [];
223
- // Generate entity files
224
- const entityFiles = await generator.generateEntity({
225
- entity,
226
- relationships: entityRelationships,
227
- allEntities: entities,
228
- apiType,
229
- });
230
- for (const file of entityFiles) {
231
- const fullPath = path.join(autogenPath, file.path);
232
- await (0, file_system_1.createFile)(fullPath, file.content);
233
- }
234
- // Generate DTO files
235
- const dtoFiles = await generator.generateDto({
236
- entity,
237
- relationships: entityRelationships,
238
- allEntities: entities,
239
- apiType,
240
- });
241
- for (const file of dtoFiles) {
242
- const fullPath = path.join(autogenPath, file.path);
243
- await (0, file_system_1.createFile)(fullPath, file.content);
244
- }
245
- // Generate service files
246
- const serviceFiles = await generator.generateService({
247
- entity,
248
- relationships: entityRelationships,
249
- allEntities: entities,
250
- apiType,
251
- relationshipMap,
252
- });
253
- for (const file of serviceFiles) {
254
- const fullPath = path.join(autogenPath, file.path);
255
- await (0, file_system_1.createFile)(fullPath, file.content);
256
- }
257
- // Generate controller files
258
- const controllerFiles = await generator.generateController({
259
- entity,
260
- relationships: entityRelationships,
261
- allEntities: entities,
262
- apiType,
263
- relationshipMap,
264
- });
265
- for (const file of controllerFiles) {
266
- const fullPath = path.join(autogenPath, file.path);
267
- await (0, file_system_1.createFile)(fullPath, file.content);
268
- }
269
- // Generate module files
270
- const moduleFiles = await generator.generateModule({
271
- entity,
272
- relationships: entityRelationships,
273
- allEntities: entities,
274
- apiType,
275
- });
276
- for (const file of moduleFiles) {
277
- const fullPath = path.join(autogenPath, file.path);
278
- await (0, file_system_1.createFile)(fullPath, file.content);
279
- }
280
- const entityBuildTime = perf_hooks_1.performance.now() - entityBuildStart;
281
- console.log(`[apso] Finished building entity '${entity.name}' in ${entityBuildTime.toFixed(2)} ms`);
282
- }
283
- // Generate guards
284
- const guardFiles = await generator.generateGuards(entities, auth);
285
- const rootPath = path.dirname(autogenPath);
286
- for (const file of guardFiles) {
287
- const fullPath = path.join(rootPath, "autogen", file.path);
288
- await (0, file_system_1.createFile)(fullPath, file.content);
289
- console.log(`[apso] Generated ${fullPath}`);
290
- }
291
- // Generate index module
292
- const indexFiles = await generator.generateIndexModule(entities, apiType);
293
- for (const file of indexFiles) {
294
- const fullPath = path.join(autogenPath, file.path);
295
- await (0, file_system_1.createFile)(fullPath, file.content);
296
- console.log(`[apso] Generated ${fullPath}`);
297
- }
7
+ this.warn('"apso server scaffold" is deprecated. Use "apso generate" instead.');
8
+ await this.config.runCommand("generate", this.argv);
298
9
  }
299
10
  }
300
- Scaffold.description = "Setup new entities and interfaces for an Apso Server";
301
- Scaffold.examples = [
302
- `$ apso server scaffold`,
303
- `$ apso server scaffold --skip-format`,
304
- `$ apso server scaffold --language typescript`,
305
- `$ apso server scaffold --language python`,
306
- `$ apso server scaffold --language go`,
307
- ];
308
- Scaffold.flags = {
309
- help: core_1.Flags.help({ char: "h" }),
310
- "skip-format": core_1.Flags.boolean({
311
- description: "Skip the formatting step (useful when prettier is not available)",
312
- default: false,
313
- }),
314
- language: core_1.Flags.string({
315
- char: "l",
316
- description: "Target language for code generation (typescript, python, go). If not specified, uses .apsorc config or prompts.",
317
- options: ["typescript", "python", "go"],
318
- }),
319
- };
320
- Scaffold.args = {};
11
+ Scaffold.hidden = true;
12
+ Scaffold.description = "[Deprecated] Use 'apso generate' instead";
13
+ Scaffold.examples = [`$ apso generate`];
14
+ Scaffold.strict = false;
321
15
  exports.default = Scaffold;
@@ -0,0 +1,7 @@
1
+ import BaseCommand from "../lib/base-command";
2
+ export default class Status extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {};
6
+ run(): Promise<void>;
7
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const base_command_1 = tslib_1.__importDefault(require("../lib/base-command"));
5
+ const config_1 = require("../lib/config");
6
+ const services_1 = require("../lib/api/services");
7
+ class Status extends base_command_1.default {
8
+ async run() {
9
+ // Auth guard
10
+ if (!config_1.credentials.isValid()) {
11
+ this.error("Not logged in. Run 'apso login' first.");
12
+ }
13
+ // Link guard
14
+ const link = config_1.projectLink.read();
15
+ if (!link) {
16
+ this.error("Project not linked. Run 'apso link' first.");
17
+ }
18
+ // Fetch service
19
+ const service = await services_1.servicesApi.get(link.workspaceSlug, link.serviceSlug);
20
+ this.log(`Service: ${service.name} (${service.slug})`);
21
+ this.log(`Workspace: ${link.workspaceSlug}`);
22
+ this.log(`Status: ${service.status}`);
23
+ this.log(`GitHub: ${service.githubRepo || "not connected"}`);
24
+ if (service.endpoint) {
25
+ this.log(`Endpoint: ${service.endpoint}`);
26
+ }
27
+ if (service.lastDeployedAt) {
28
+ this.log(`Last deployed: ${new Date(service.lastDeployedAt).toLocaleString()}`);
29
+ }
30
+ // Fetch latest build
31
+ const latestBuild = await services_1.buildApi.getLatest(link.workspaceSlug, link.serviceSlug);
32
+ if (latestBuild) {
33
+ this.log("");
34
+ this.log("Latest build:");
35
+ this.log(` ID: ${latestBuild.id}`);
36
+ this.log(` Status: ${latestBuild.status}`);
37
+ this.log(` Started: ${new Date(latestBuild.startedAt).toLocaleString()}`);
38
+ if (latestBuild.completedAt) {
39
+ this.log(` Completed: ${new Date(latestBuild.completedAt).toLocaleString()}`);
40
+ }
41
+ if (latestBuild.error) {
42
+ this.log(` Error: ${latestBuild.error}`);
43
+ }
44
+ }
45
+ else {
46
+ this.log("\nNo builds found. Run 'apso deploy' to trigger one.");
47
+ }
48
+ }
49
+ }
50
+ Status.description = "Show the current service and latest build status";
51
+ Status.examples = [`$ apso status`];
52
+ Status.flags = {};
53
+ exports.default = Status;
@@ -0,0 +1,9 @@
1
+ import BaseCommand from "../lib/base-command";
2
+ export default class Unlink extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const core_1 = require("@oclif/core");
5
+ const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
6
+ const base_command_1 = tslib_1.__importDefault(require("../lib/base-command"));
7
+ const config_1 = require("../lib/config");
8
+ class Unlink extends base_command_1.default {
9
+ async run() {
10
+ const { flags } = await this.parse(Unlink);
11
+ const link = config_1.projectLink.read();
12
+ if (!link) {
13
+ this.log("Project is not linked. Nothing to do.");
14
+ return;
15
+ }
16
+ this.log(`Currently linked to: ${link.workspaceSlug}/${link.serviceSlug}`);
17
+ if (!flags.yes) {
18
+ const { confirm } = await inquirer_1.default.prompt([
19
+ {
20
+ type: "confirm",
21
+ name: "confirm",
22
+ message: "Remove project link?",
23
+ default: false,
24
+ },
25
+ ]);
26
+ if (!confirm) {
27
+ this.log("Unlink cancelled.");
28
+ return;
29
+ }
30
+ }
31
+ config_1.projectLink.remove();
32
+ this.log("Project unlinked.");
33
+ }
34
+ }
35
+ Unlink.description = "Remove the link between this project and the platform";
36
+ Unlink.examples = [
37
+ `$ apso unlink`,
38
+ `$ apso unlink --yes`,
39
+ ];
40
+ Unlink.flags = {
41
+ yes: core_1.Flags.boolean({
42
+ char: "y",
43
+ description: "Skip confirmation prompt",
44
+ default: false,
45
+ }),
46
+ };
47
+ exports.default = Unlink;
@@ -0,0 +1,10 @@
1
+ import BaseCommand from "../lib/base-command";
2
+ export default class Whoami extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ help: import("@oclif/core/lib/interfaces").BooleanFlag<void>;
7
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const core_1 = require("@oclif/core");
5
+ const base_command_1 = tslib_1.__importDefault(require("../lib/base-command"));
6
+ const config_1 = require("../lib/config");
7
+ class Whoami extends base_command_1.default {
8
+ async run() {
9
+ const { flags } = await this.parse(Whoami);
10
+ const creds = config_1.credentials.read();
11
+ if (!creds) {
12
+ if (flags.json) {
13
+ this.log(JSON.stringify({ authenticated: false }, null, 2));
14
+ }
15
+ else {
16
+ this.log("Not logged in. Run 'apso login' to authenticate.");
17
+ }
18
+ return;
19
+ }
20
+ const config = config_1.globalConfig.read();
21
+ const link = config_1.projectLink.read();
22
+ // Check if session is valid
23
+ const isValid = config_1.credentials.isValid();
24
+ const needsRefresh = config_1.credentials.needsRefresh();
25
+ const info = {
26
+ authenticated: true,
27
+ user: {
28
+ id: creds.user.id,
29
+ email: creds.user.email,
30
+ name: creds.user.name || undefined,
31
+ },
32
+ session: {
33
+ valid: isValid,
34
+ needsRefresh,
35
+ expiresAt: creds.tokens.expiresAt,
36
+ },
37
+ context: {
38
+ workspace: (link === null || link === void 0 ? void 0 : link.workspaceSlug) || config.defaultWorkspace || undefined,
39
+ service: (link === null || link === void 0 ? void 0 : link.serviceSlug) || undefined,
40
+ },
41
+ config: {
42
+ apiUrl: config.apiUrl,
43
+ webUrl: config.webUrl,
44
+ },
45
+ };
46
+ if (flags.json) {
47
+ this.log(JSON.stringify(info, null, 2));
48
+ return;
49
+ }
50
+ // Pretty print
51
+ this.log("");
52
+ this.log(` Email: ${creds.user.email}`);
53
+ if (creds.user.name) {
54
+ this.log(` Name: ${creds.user.name}`);
55
+ }
56
+ this.log(` User ID: ${creds.user.id}`);
57
+ this.log("");
58
+ // Session status
59
+ if (!isValid) {
60
+ this.log(" Session: Expired (run 'apso login' to refresh)");
61
+ }
62
+ else if (needsRefresh) {
63
+ this.log(" Session: Valid (will refresh soon)");
64
+ }
65
+ else {
66
+ this.log(" Session: Valid");
67
+ }
68
+ this.log("");
69
+ // Context
70
+ if (link) {
71
+ this.log(` Workspace: ${link.workspaceSlug}`);
72
+ this.log(` Service: ${link.serviceSlug}`);
73
+ }
74
+ else if (config.defaultWorkspace) {
75
+ this.log(` Workspace: ${config.defaultWorkspace} (default)`);
76
+ this.log(" Service: None (run 'apso use <service>' to set)");
77
+ }
78
+ else {
79
+ this.log(" Workspace: None (run 'apso use <service>' to set)");
80
+ this.log(" Service: None");
81
+ }
82
+ this.log("");
83
+ }
84
+ }
85
+ Whoami.description = "Display information about the current user and context";
86
+ Whoami.examples = [
87
+ "$ apso whoami",
88
+ "$ apso whoami --json",
89
+ ];
90
+ Whoami.flags = {
91
+ help: core_1.Flags.help({ char: "h" }),
92
+ json: core_1.Flags.boolean({
93
+ description: "Output as JSON",
94
+ default: false,
95
+ }),
96
+ };
97
+ exports.default = Whoami;
@@ -114,7 +114,7 @@ async function refreshAccessToken() {
114
114
  }
115
115
  try {
116
116
  const config = config_1.globalConfig.read();
117
- const response = await fetch(`${config.apiUrl}/auth/cli/refresh`, {
117
+ const response = await fetch(`${config.apiUrl}/api/auth/cli/refresh`, {
118
118
  method: "POST",
119
119
  headers: {
120
120
  "Content-Type": "application/json",
@@ -15,19 +15,19 @@ exports.authApi = {
15
15
  * Exchange OAuth authorization code for tokens
16
16
  */
17
17
  exchangeCode(code) {
18
- return client_1.api.post("/auth/cli/exchange", { code }, { skipAuth: true });
18
+ return client_1.api.post("/api/auth/cli/exchange", { code }, { skipAuth: true });
19
19
  },
20
20
  /**
21
21
  * Get current user profile
22
22
  */
23
23
  getProfile() {
24
- return client_1.api.get("/auth/me");
24
+ return client_1.api.get("/api/auth/me");
25
25
  },
26
26
  /**
27
27
  * Revoke current session
28
28
  */
29
29
  logout() {
30
- return client_1.api.post("/auth/cli/logout");
30
+ return client_1.api.post("/api/auth/cli/logout");
31
31
  },
32
32
  };
33
33
  /**
@@ -164,8 +164,15 @@ export interface UserProfile {
164
164
  export interface TokenExchangeResponse {
165
165
  accessToken: string;
166
166
  refreshToken: string;
167
- expiresIn: number;
168
- tokenType: string;
167
+ /**
168
+ * Token expiration as ISO timestamp string
169
+ */
170
+ expiresAt: string;
171
+ /**
172
+ * Optional: Token expiration in seconds (for compatibility)
173
+ */
174
+ expiresIn?: number;
175
+ tokenType?: string;
169
176
  user: {
170
177
  id: string;
171
178
  email: string;
@@ -30,29 +30,10 @@ type ParsedApsorc = {
30
30
  export declare const parseApsorcV1: (apsorc: ApsorcType) => ParsedApsorcData;
31
31
  export declare const parseApsorcV2: (apsorc: ApsorcType) => ParsedApsorcData;
32
32
  export declare const parseApsorc: () => ParsedApsorc;
33
- /**
34
- * Represents the unified configuration structure after parsing and potential migration.
35
- */
36
- interface UnifiedConfig {
37
- entities: Entity[];
38
- relationships: ApsorcRelationship[];
39
- rootFolder: string;
40
- }
41
33
  /**
42
34
  * Finds the .apsorc configuration file path.
43
35
  * Searches upwards from the current working directory.
44
36
  * @returns The absolute path to the .apsorc file, or null if not found.
45
37
  */
46
38
  export declare const findConfigPath: () => string | null;
47
- /**
48
- * Loads, validates, and potentially migrates the .apsorc configuration.
49
- * Uses the `rc` library to find and load the .apsorc file.
50
- * Detects config version (V1 or V2) and migrates V1 to V2 if necessary.
51
- * Performs basic validation on the final V2 structure.
52
- * @param appName The name of the application (used by `rc`). Defaults to 'apso'.
53
- * @param defaults Default configuration values (used by `rc`).
54
- * @returns The unified configuration (entities, relationships, rootFolder).
55
- * @throws Error if the config file cannot be found, is invalid, or migration fails.
56
- */
57
- export declare const loadConfig: (appName?: string, defaults?: {}) => UnifiedConfig;
58
39
  export {};