estela 0.1.3 → 0.1.6

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 (76) hide show
  1. package/dist/billing/sessionize.d.ts +10 -1
  2. package/dist/billing/sessionize.d.ts.map +1 -1
  3. package/dist/billing/sessionize.js +0 -0
  4. package/dist/billing/sessionize.js.map +1 -1
  5. package/dist/billing/sessionize.test.js +28 -0
  6. package/dist/billing/sessionize.test.js.map +1 -1
  7. package/dist/billing.d.ts +16 -0
  8. package/dist/billing.d.ts.map +1 -0
  9. package/dist/billing.js +71 -0
  10. package/dist/billing.js.map +1 -0
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +345 -93
  13. package/dist/cli.js.map +1 -1
  14. package/dist/cloud/client.d.ts +6 -0
  15. package/dist/cloud/client.d.ts.map +1 -1
  16. package/dist/cloud/client.js +26 -0
  17. package/dist/cloud/client.js.map +1 -1
  18. package/dist/db/store.d.ts +56 -0
  19. package/dist/db/store.d.ts.map +1 -1
  20. package/dist/db/store.js +101 -0
  21. package/dist/db/store.js.map +1 -1
  22. package/dist/export/panel.d.ts +3 -1
  23. package/dist/export/panel.d.ts.map +1 -1
  24. package/dist/export/panel.js +24 -19
  25. package/dist/export/panel.js.map +1 -1
  26. package/dist/export/panel.test.js +46 -5
  27. package/dist/export/panel.test.js.map +1 -1
  28. package/dist/metrics/team.d.ts +9 -0
  29. package/dist/metrics/team.d.ts.map +1 -1
  30. package/dist/metrics/team.js +0 -0
  31. package/dist/metrics/team.js.map +1 -1
  32. package/dist/publish.d.ts +37 -0
  33. package/dist/publish.d.ts.map +1 -0
  34. package/dist/publish.js +185 -0
  35. package/dist/publish.js.map +1 -0
  36. package/dist/publish.test.d.ts +2 -0
  37. package/dist/publish.test.d.ts.map +1 -0
  38. package/dist/publish.test.js +91 -0
  39. package/dist/publish.test.js.map +1 -0
  40. package/dist/server.d.ts.map +1 -1
  41. package/dist/server.js +88 -58
  42. package/dist/server.js.map +1 -1
  43. package/dist/sync/team.d.ts +21 -0
  44. package/dist/sync/team.d.ts.map +1 -0
  45. package/dist/sync/team.js +68 -0
  46. package/dist/sync/team.js.map +1 -0
  47. package/dist/sync/team.test.d.ts +2 -0
  48. package/dist/sync/team.test.d.ts.map +1 -0
  49. package/dist/sync/team.test.js +102 -0
  50. package/dist/sync/team.test.js.map +1 -0
  51. package/dist/sync.d.ts +20 -0
  52. package/dist/sync.d.ts.map +1 -0
  53. package/dist/sync.js +79 -0
  54. package/dist/sync.js.map +1 -0
  55. package/dist/sync.test.d.ts +2 -0
  56. package/dist/sync.test.d.ts.map +1 -0
  57. package/dist/sync.test.js +151 -0
  58. package/dist/sync.test.js.map +1 -0
  59. package/dist/team.d.ts +51 -0
  60. package/dist/team.d.ts.map +1 -0
  61. package/dist/team.js +122 -0
  62. package/dist/team.js.map +1 -0
  63. package/dist/team.test.d.ts +2 -0
  64. package/dist/team.test.d.ts.map +1 -0
  65. package/dist/team.test.js +163 -0
  66. package/dist/team.test.js.map +1 -0
  67. package/dist/web-ui.test.js +14 -1
  68. package/dist/web-ui.test.js.map +1 -1
  69. package/package.json +1 -1
  70. package/web/app.css +74 -16
  71. package/web/app.js +198 -38
  72. package/web/apple-touch-icon.png +0 -0
  73. package/web/favicon.png +0 -0
  74. package/web/index.html +18 -2
  75. package/web/logo.png +0 -0
  76. package/web/logo-mark.png +0 -0
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const strict_1 = __importDefault(require("node:assert/strict"));
40
+ const node_test_1 = require("node:test");
41
+ const schema_js_1 = require("../db/schema.js");
42
+ const store = __importStar(require("../db/store.js"));
43
+ const team_js_1 = require("./team.js");
44
+ function fresh() {
45
+ const db = (0, schema_js_1.openDatabase)(":memory:");
46
+ store.upsertClient(db, { id: "team", name: "Proyectos de equipo", currency: "USD" });
47
+ store.upsertProject(db, {
48
+ id: "euro-blazor-accuro", clientId: "team", name: "Servicios socios cartera", repoPaths: [],
49
+ billable: false, roundingMinutes: 0, aiCostPolicy: "absorbed", kind: "employment",
50
+ });
51
+ return db;
52
+ }
53
+ (0, node_test_1.test)("sin cuenta vinculada, pide login con el comando exacto", async () => {
54
+ const db = fresh();
55
+ try {
56
+ await strict_1.default.rejects((0, team_js_1.syncTeamProject)(db, "euro-blazor-accuro"), (error) => {
57
+ strict_1.default.ok(error instanceof team_js_1.NoAccountError);
58
+ strict_1.default.match(error.message, /estela login --email/);
59
+ return true;
60
+ });
61
+ }
62
+ finally {
63
+ db.close();
64
+ }
65
+ });
66
+ (0, node_test_1.test)("con cuenta pero sin project_sync de equipo, pide aceptar la invitación", async () => {
67
+ const db = fresh();
68
+ try {
69
+ store.setCloudAccount(db, {
70
+ accountId: "acc_1", email: "dev@accuro.com", plan: "free",
71
+ deviceToken: "tok", apiBaseUrl: "http://127.0.0.1:1", linkedAt: new Date(),
72
+ });
73
+ await strict_1.default.rejects((0, team_js_1.syncTeamProject)(db, "euro-blazor-accuro"), (error) => {
74
+ strict_1.default.ok(error instanceof team_js_1.NotSyncedError);
75
+ strict_1.default.match(error.message, /estela team accept/);
76
+ return true;
77
+ });
78
+ }
79
+ finally {
80
+ db.close();
81
+ }
82
+ });
83
+ (0, node_test_1.test)("con project_sync personal (no team) en ese proyecto, también pide aceptar", async () => {
84
+ // Guarda: syncTeamProject nunca debe intentar mandar horas de equipo desde
85
+ // una fila que en realidad es de sync personal.
86
+ const db = fresh();
87
+ try {
88
+ store.setCloudAccount(db, {
89
+ accountId: "acc_1", email: "dev@accuro.com", plan: "pro",
90
+ deviceToken: "tok", apiBaseUrl: "http://127.0.0.1:1", linkedAt: new Date(),
91
+ });
92
+ store.setProjectSync(db, {
93
+ projectId: "euro-blazor-accuro", scope: "personal",
94
+ remoteProjectId: "euro-blazor-accuro", remoteOrgId: null, inviteToken: null,
95
+ });
96
+ await strict_1.default.rejects((0, team_js_1.syncTeamProject)(db, "euro-blazor-accuro"), team_js_1.NotSyncedError);
97
+ }
98
+ finally {
99
+ db.close();
100
+ }
101
+ });
102
+ //# sourceMappingURL=team.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.test.js","sourceRoot":"","sources":["../../src/sync/team.test.ts"],"names":[],"mappings":"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"}
package/dist/sync.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import { NoAccountError } from "./publish.js";
3
+ /**
4
+ * Sync personal (Pro): las máquinas de una misma cuenta sincronizan las
5
+ * imputaciones de un proyecto entre sí.
6
+ *
7
+ * No inventa ningún concepto de "proyecto remoto": `project_id` es la misma
8
+ * cadena que elegiste al crear el proyecto (`estela project add --id ...`) —
9
+ * si usas el mismo id en la segunda máquina, es el mismo proyecto.
10
+ */
11
+ export { NoAccountError };
12
+ export declare class NotSyncedError extends Error {
13
+ }
14
+ export interface SyncOutcome {
15
+ readonly projectId: string;
16
+ readonly pushed: number;
17
+ readonly pulled: number;
18
+ }
19
+ export declare function syncProject(db: DatabaseSync, projectId: string): Promise<SyncOutcome>;
20
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;GAOG;AAEH,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,qBAAa,cAAe,SAAQ,KAAK;CAAG;AAE5C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAOD,wBAAsB,WAAW,CAAC,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAyC3F"}
package/dist/sync.js ADDED
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.NotSyncedError = exports.NoAccountError = void 0;
37
+ exports.syncProject = syncProject;
38
+ const client_js_1 = require("./cloud/client.js");
39
+ const store = __importStar(require("./db/store.js"));
40
+ const publish_js_1 = require("./publish.js");
41
+ Object.defineProperty(exports, "NoAccountError", { enumerable: true, get: function () { return publish_js_1.NoAccountError; } });
42
+ class NotSyncedError extends Error {
43
+ }
44
+ exports.NotSyncedError = NotSyncedError;
45
+ async function syncProject(db, projectId) {
46
+ const account = store.getCloudAccount(db);
47
+ if (!account) {
48
+ throw new publish_js_1.NoAccountError(`Necesitas una cuenta para sincronizar. Vincúlala con:\n\n` +
49
+ ` estela login --email tu@correo.com\n`);
50
+ }
51
+ const sync = store.getProjectSync(db, projectId);
52
+ if (!sync) {
53
+ throw new NotSyncedError(`Este proyecto no sincroniza. Actívalo con:\n\n` +
54
+ ` estela sync enable --project ${projectId}\n`);
55
+ }
56
+ const since = store.getSyncCursor(db, projectId);
57
+ const push = store.listEntriesUpdatedSince(db, projectId, since);
58
+ let result;
59
+ try {
60
+ result = await (0, client_js_1.cloudPost)(account.apiBaseUrl, "/sync/entries", { projectId, since, push }, { deviceToken: account.deviceToken });
61
+ }
62
+ catch (error) {
63
+ if (error instanceof client_js_1.CloudError && error.status === 402) {
64
+ // Mismo motivo que en publish.ts: el mensaje de cuota/plan vive en el
65
+ // servidor (sync.ts de la API), no se duplica aquí.
66
+ throw new Error(error.message);
67
+ }
68
+ if (error instanceof client_js_1.CloudError && error.status === 401) {
69
+ throw new publish_js_1.NoAccountError(`Tu sesión ya no vale. Vuelve a vincular la máquina:\n\n` +
70
+ ` estela login --email tu@correo.com\n`);
71
+ }
72
+ throw error;
73
+ }
74
+ for (const entry of result.entries)
75
+ store.applySyncedEntry(db, entry, projectId);
76
+ store.recordSyncCursor(db, projectId, result.syncedUpTo);
77
+ return { projectId, pushed: push.length, pulled: result.entries.length };
78
+ }
79
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,kCAyCC;AAtED,iDAA0D;AAC1D,qDAAuC;AAEvC,6CAA8C;AAWrC,+FAXA,2BAAc,OAWA;AAEvB,MAAa,cAAe,SAAQ,KAAK;CAAG;AAA5C,wCAA4C;AAarC,KAAK,UAAU,WAAW,CAAC,EAAgB,EAAE,SAAiB;IACnE,MAAM,OAAO,GAAG,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,2BAAc,CACtB,2DAA2D;YAC3D,wCAAwC,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IACjD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,cAAc,CACtB,gDAAgD;YAChD,kCAAkC,SAAS,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,KAAK,CAAC,uBAAuB,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IAEjE,IAAI,MAAoB,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,IAAA,qBAAS,EAAC,OAAO,CAAC,UAAU,EAAE,eAAe,EAC1D,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,EAC1B,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,sBAAU,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACxD,sEAAsE;YACtE,oDAAoD;YACpD,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;QACD,IAAI,KAAK,YAAY,sBAAU,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACxD,MAAM,IAAI,2BAAc,CACtB,yDAAyD;gBACzD,wCAAwC,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,OAAO;QAAE,KAAK,CAAC,gBAAgB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACjF,KAAK,CAAC,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAEzD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sync.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.test.d.ts","sourceRoot":"","sources":["../src/sync.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const strict_1 = __importDefault(require("node:assert/strict"));
40
+ const node_test_1 = require("node:test");
41
+ const schema_js_1 = require("./db/schema.js");
42
+ const store = __importStar(require("./db/store.js"));
43
+ const sync_js_1 = require("./sync.js");
44
+ /**
45
+ * Igual que `publish.test.ts`: aquí solo lo que falla ANTES de tocar la red
46
+ * (sin cuenta, sin proyecto activado). El round-trip real de push/pull ya lo
47
+ * cubren los tests de `packages/api` — es donde vive esa lógica — y el
48
+ * merge local (`applySyncedEntry`) se prueba aquí directo contra la base,
49
+ * sin pasar por la red en absoluto.
50
+ */
51
+ function fresh() {
52
+ const db = (0, schema_js_1.openDatabase)(":memory:");
53
+ store.upsertClient(db, { id: "acme", name: "ACME", currency: "EUR" });
54
+ store.upsertProject(db, {
55
+ id: "web", clientId: "acme", name: "Web de ACME", repoPaths: [],
56
+ billable: true, roundingMinutes: 0, aiCostPolicy: "absorbed", kind: "client",
57
+ });
58
+ return db;
59
+ }
60
+ (0, node_test_1.test)("sin cuenta vinculada, pide login con el comando exacto", async () => {
61
+ const db = fresh();
62
+ try {
63
+ await strict_1.default.rejects((0, sync_js_1.syncProject)(db, "web"), (error) => {
64
+ strict_1.default.ok(error instanceof sync_js_1.NoAccountError);
65
+ strict_1.default.match(error.message, /estela login --email/);
66
+ return true;
67
+ });
68
+ }
69
+ finally {
70
+ db.close();
71
+ }
72
+ });
73
+ (0, node_test_1.test)("con cuenta pero sin activar, pide el comando exacto de activación", async () => {
74
+ const db = fresh();
75
+ try {
76
+ store.setCloudAccount(db, {
77
+ accountId: "acc_1", email: "yo@test.com", plan: "pro",
78
+ deviceToken: "tok", apiBaseUrl: "http://127.0.0.1:1", linkedAt: new Date(),
79
+ });
80
+ await strict_1.default.rejects((0, sync_js_1.syncProject)(db, "web"), (error) => {
81
+ strict_1.default.ok(error instanceof sync_js_1.NotSyncedError);
82
+ strict_1.default.match(error.message, /estela sync enable --project web/);
83
+ return true;
84
+ });
85
+ }
86
+ finally {
87
+ db.close();
88
+ }
89
+ });
90
+ (0, node_test_1.test)("listPersonalSyncCandidates excluye un proyecto ya enlazado a un equipo", () => {
91
+ const db = fresh();
92
+ try {
93
+ store.setProjectSync(db, {
94
+ projectId: "web", scope: "team", remoteProjectId: "web",
95
+ remoteOrgId: "org_1", inviteToken: "inv_1",
96
+ });
97
+ strict_1.default.ok(!store.listPersonalSyncCandidates(db).includes("web"));
98
+ }
99
+ finally {
100
+ db.close();
101
+ }
102
+ });
103
+ (0, node_test_1.test)("applySyncedEntry: una fila más reciente de otra máquina gana sobre la local", () => {
104
+ const db = fresh();
105
+ try {
106
+ store.saveTimeEntry(db, {
107
+ id: "te_1", projectId: "web",
108
+ startedAt: new Date("2026-01-01T09:00:00Z"), endedAt: new Date("2026-01-01T10:00:00Z"),
109
+ seconds: 3600, description: "vieja", billable: true, invoiceId: null,
110
+ aiCost: { microUsd: 1000 }, agentSeconds: 3600, commitHashes: [], agents: [],
111
+ source: "manual", kind: "development", branch: null,
112
+ }, new Date("2026-01-01T10:00:00Z"));
113
+ store.applySyncedEntry(db, {
114
+ id: "te_1", startedAt: "2026-01-01T09:00:00.000Z", localDate: "2026-01-01",
115
+ endedAt: "2026-01-01T11:00:00.000Z", seconds: 7200, description: "nueva de otra máquina",
116
+ billable: true, aiMicroUsd: 2000, agentSeconds: 7200, commitHashes: "", agents: "",
117
+ source: "manual", kind: "development", branch: null,
118
+ updatedAt: "2026-01-02T00:00:00.000Z",
119
+ }, "web");
120
+ const [saved] = store.getTimeEntries(db, "web");
121
+ strict_1.default.equal(saved.description, "nueva de otra máquina");
122
+ }
123
+ finally {
124
+ db.close();
125
+ }
126
+ });
127
+ (0, node_test_1.test)("applySyncedEntry: una fila más vieja que la local no la pisa", () => {
128
+ const db = fresh();
129
+ try {
130
+ store.saveTimeEntry(db, {
131
+ id: "te_1", projectId: "web",
132
+ startedAt: new Date("2026-01-01T09:00:00Z"), endedAt: new Date("2026-01-01T10:00:00Z"),
133
+ seconds: 3600, description: "actual", billable: true, invoiceId: null,
134
+ aiCost: { microUsd: 1000 }, agentSeconds: 3600, commitHashes: [], agents: [],
135
+ source: "manual", kind: "development", branch: null,
136
+ }, new Date("2026-01-02T00:00:00Z"));
137
+ store.applySyncedEntry(db, {
138
+ id: "te_1", startedAt: "2026-01-01T09:00:00.000Z", localDate: "2026-01-01",
139
+ endedAt: "2026-01-01T10:00:00.000Z", seconds: 3600, description: "vieja de otra máquina",
140
+ billable: true, aiMicroUsd: 500, agentSeconds: 3600, commitHashes: "", agents: "",
141
+ source: "manual", kind: "development", branch: null,
142
+ updatedAt: "2026-01-01T10:00:00.000Z",
143
+ }, "web");
144
+ const [saved] = store.getTimeEntries(db, "web");
145
+ strict_1.default.equal(saved.description, "actual");
146
+ }
147
+ finally {
148
+ db.close();
149
+ }
150
+ });
151
+ //# sourceMappingURL=sync.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.test.js","sourceRoot":"","sources":["../src/sync.test.ts"],"names":[],"mappings":"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"}
package/dist/team.d.ts ADDED
@@ -0,0 +1,51 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import { NoAccountError } from "./publish.js";
3
+ /**
4
+ * Teams: invitar a un compañero a un proyecto, y que sus horas pasen de
5
+ * estimadas (por commits) a medidas (por su propio Estela).
6
+ *
7
+ * Mismo patrón que `publish.ts`: requiere cuenta vinculada, y un 402 del
8
+ * servidor (aquí, "esto es Teams") se relanza tal cual — el mensaje vive en
9
+ * `packages/api/src/team.ts`, no se duplica aquí.
10
+ */
11
+ export { NoAccountError };
12
+ export interface InviteOptions {
13
+ readonly projectId: string;
14
+ readonly emails: readonly string[];
15
+ readonly inviteeKind: "employee" | "freelancer";
16
+ }
17
+ export declare function inviteTeamMember(db: DatabaseSync, options: InviteOptions): Promise<{
18
+ token: string;
19
+ }>;
20
+ export interface AcceptOptions {
21
+ readonly token: string;
22
+ readonly localProjectId: string;
23
+ }
24
+ export interface AcceptOutcome {
25
+ readonly projectName: string;
26
+ readonly emails: readonly string[];
27
+ readonly inviteeKind: string;
28
+ }
29
+ /**
30
+ * Acepta una invitación y monta lo mínimo local para que el proyecto exista:
31
+ * un cliente placeholder ("team"), el proyecto en sí, y el `project_sync`
32
+ * de alcance 'team' que `estela sync` ya sabe recorrer.
33
+ *
34
+ * El id local lo elige quien acepta, a propósito — nunca el id del dueño
35
+ * tal cual: si ya tuviera un proyecto propio con ese mismo id, reusarlo sin
36
+ * más lo habría pisado en silencio (`upsertProject` hace `ON CONFLICT DO
37
+ * UPDATE`). Por eso se comprueba antes de tocar nada.
38
+ */
39
+ export declare function acceptTeamInvite(db: DatabaseSync, options: AcceptOptions): Promise<AcceptOutcome>;
40
+ export interface TeamMemberSummary {
41
+ readonly emails: readonly string[];
42
+ readonly inviteeKind: string;
43
+ readonly seconds: number;
44
+ readonly syncedAt: string | null;
45
+ readonly acceptedAt: string | null;
46
+ }
47
+ /** Solo la usa el dueño: `estela team list`, y `buildTeam()` al publicar. */
48
+ export declare function listTeamMembers(db: DatabaseSync, projectId: string): Promise<TeamMemberSummary[]>;
49
+ /** `estela team revoke --token <token>`. Baja también la cantidad de la suscripción de Teams. */
50
+ export declare function revokeTeamMember(db: DatabaseSync, token: string): Promise<void>;
51
+ //# sourceMappingURL=team.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.d.ts","sourceRoot":"","sources":["../src/team.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;GAOG;AAEH,OAAO,EAAE,cAAc,EAAE,CAAC;AA0B1B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,UAAU,GAAG,YAAY,CAAC;CACjD;AAED,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAS3G;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAgCvG;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,6EAA6E;AAC7E,wBAAsB,eAAe,CAAC,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAMvG;AAED,iGAAiG;AACjG,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIrF"}
package/dist/team.js ADDED
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.NoAccountError = void 0;
37
+ exports.inviteTeamMember = inviteTeamMember;
38
+ exports.acceptTeamInvite = acceptTeamInvite;
39
+ exports.listTeamMembers = listTeamMembers;
40
+ exports.revokeTeamMember = revokeTeamMember;
41
+ const client_js_1 = require("./cloud/client.js");
42
+ const store = __importStar(require("./db/store.js"));
43
+ const publish_js_1 = require("./publish.js");
44
+ Object.defineProperty(exports, "NoAccountError", { enumerable: true, get: function () { return publish_js_1.NoAccountError; } });
45
+ function requireAccount(db) {
46
+ const account = store.getCloudAccount(db);
47
+ if (!account) {
48
+ throw new publish_js_1.NoAccountError(`Necesitas una cuenta para esto. Vincúlala con:\n\n` +
49
+ ` estela login --email tu@correo.com\n`);
50
+ }
51
+ return account;
52
+ }
53
+ async function unwrap(call) {
54
+ try {
55
+ return await call;
56
+ }
57
+ catch (error) {
58
+ if (error instanceof client_js_1.CloudError && error.status === 402)
59
+ throw new Error(error.message);
60
+ if (error instanceof client_js_1.CloudError && error.status === 401) {
61
+ throw new publish_js_1.NoAccountError(`Tu sesión ya no vale. Vuelve a vincular la máquina:\n\n` +
62
+ ` estela login --email tu@correo.com\n`);
63
+ }
64
+ throw error;
65
+ }
66
+ }
67
+ async function inviteTeamMember(db, options) {
68
+ const account = requireAccount(db);
69
+ const project = store.getProject(db, options.projectId);
70
+ if (!project)
71
+ throw new Error(`No existe el proyecto "${options.projectId}".`);
72
+ return unwrap((0, client_js_1.cloudPost)(account.apiBaseUrl, "/team/invite", {
73
+ projectId: options.projectId, projectName: project.name,
74
+ emails: options.emails, inviteeKind: options.inviteeKind,
75
+ }, { deviceToken: account.deviceToken }));
76
+ }
77
+ /**
78
+ * Acepta una invitación y monta lo mínimo local para que el proyecto exista:
79
+ * un cliente placeholder ("team"), el proyecto en sí, y el `project_sync`
80
+ * de alcance 'team' que `estela sync` ya sabe recorrer.
81
+ *
82
+ * El id local lo elige quien acepta, a propósito — nunca el id del dueño
83
+ * tal cual: si ya tuviera un proyecto propio con ese mismo id, reusarlo sin
84
+ * más lo habría pisado en silencio (`upsertProject` hace `ON CONFLICT DO
85
+ * UPDATE`). Por eso se comprueba antes de tocar nada.
86
+ */
87
+ async function acceptTeamInvite(db, options) {
88
+ const account = requireAccount(db);
89
+ const existing = store.getProject(db, options.localProjectId);
90
+ const existingSync = existing ? store.getProjectSync(db, options.localProjectId) : null;
91
+ if (existing && existingSync?.inviteToken !== options.token) {
92
+ throw new Error(`Ya existe un proyecto local con el id "${options.localProjectId}". ` +
93
+ `Elige otro con --as-id.`);
94
+ }
95
+ const result = await unwrap((0, client_js_1.cloudPost)(account.apiBaseUrl, "/team/accept", { token: options.token }, { deviceToken: account.deviceToken }));
96
+ if (!store.getClient(db, "team")) {
97
+ store.upsertClient(db, { id: "team", name: "Proyectos de equipo", currency: "USD" });
98
+ }
99
+ store.upsertProject(db, {
100
+ id: options.localProjectId, clientId: "team", name: result.projectName,
101
+ repoPaths: [], billable: false, roundingMinutes: 0, aiCostPolicy: "absorbed",
102
+ kind: "employment",
103
+ });
104
+ store.setProjectSync(db, {
105
+ projectId: options.localProjectId, scope: "team",
106
+ remoteProjectId: result.projectId, remoteOrgId: result.ownerAccountId,
107
+ inviteToken: options.token,
108
+ });
109
+ return { projectName: result.projectName, emails: result.emails, inviteeKind: result.inviteeKind };
110
+ }
111
+ /** Solo la usa el dueño: `estela team list`, y `buildTeam()` al publicar. */
112
+ async function listTeamMembers(db, projectId) {
113
+ const account = requireAccount(db);
114
+ const result = await unwrap((0, client_js_1.cloudGet)(account.apiBaseUrl, `/team/members?projectId=${encodeURIComponent(projectId)}`, { deviceToken: account.deviceToken }));
115
+ return result.members;
116
+ }
117
+ /** `estela team revoke --token <token>`. Baja también la cantidad de la suscripción de Teams. */
118
+ async function revokeTeamMember(db, token) {
119
+ const account = requireAccount(db);
120
+ await unwrap((0, client_js_1.cloudPost)(account.apiBaseUrl, "/team/revoke", { token }, { deviceToken: account.deviceToken }));
121
+ }
122
+ //# sourceMappingURL=team.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.js","sourceRoot":"","sources":["../src/team.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=team.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.test.d.ts","sourceRoot":"","sources":["../src/team.test.ts"],"names":[],"mappings":""}