@andrestobelem/clone 0.1.3 → 0.2.0
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.
- package/LICENSE +21 -0
- package/README.md +151 -23
- package/app.js +645 -0
- package/bin/clone.js +11 -230
- package/dist/cli.js +565 -0
- package/dist/cli.js.map +1 -0
- package/dist/database.js +42 -0
- package/dist/database.js.map +1 -0
- package/dist/errors.js +46 -0
- package/dist/errors.js.map +1 -0
- package/dist/paths.js +42 -0
- package/dist/paths.js.map +1 -0
- package/dist/schema.js +52 -0
- package/dist/schema.js.map +1 -0
- package/dist/server.js +232 -0
- package/dist/server.js.map +1 -0
- package/dist/sync.js +625 -0
- package/dist/sync.js.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.js +254 -0
- package/dist/validation.js.map +1 -0
- package/dist/workspace.js +1393 -0
- package/dist/workspace.js.map +1 -0
- package/index.html +73 -0
- package/package.json +33 -4
- package/styles.css +108 -0
package/dist/errors.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export class CloneError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
exitCode;
|
|
4
|
+
details;
|
|
5
|
+
constructor(message, code, exitCode, details = {}) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.exitCode = exitCode;
|
|
9
|
+
this.details = details;
|
|
10
|
+
this.name = "CloneError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class InvalidInputError extends CloneError {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message, "invalid_input", 2);
|
|
16
|
+
this.name = "InvalidInputError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class SyncConflictError extends CloneError {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message, "sync_conflict", 3);
|
|
22
|
+
this.name = "SyncConflictError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class RelationshipConflictError extends CloneError {
|
|
26
|
+
constructor(message) {
|
|
27
|
+
super(message, "relationship_conflict", 3);
|
|
28
|
+
this.name = "RelationshipConflictError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class StorageError extends CloneError {
|
|
32
|
+
constructor(message) {
|
|
33
|
+
super(message, "storage_error", 4);
|
|
34
|
+
this.name = "StorageError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export class PendingExportError extends CloneError {
|
|
38
|
+
constructor(message) {
|
|
39
|
+
super(message, "pending_export", 4, {
|
|
40
|
+
committed: true,
|
|
41
|
+
recoveryRequired: true,
|
|
42
|
+
});
|
|
43
|
+
this.name = "PendingExportError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,UAAW,SAAQ,KAAK;IAGxB,IAAI;IACJ,QAAQ;IACR,OAAO;IAJlB,YACE,OAAe,EACN,IAAY,EACZ,QAAgB,EAChB,OAAO,GAA4B,EAAE;QAE9C,KAAK,CAAC,OAAO,CAAC,CAAC;oBAJN,IAAI;wBACJ,QAAQ;uBACR,OAAO;QAGhB,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,UAAU;IAC/C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,UAAU;IAC/C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,UAAU;IACvD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,UAAU;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,UAAU;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,gBAAgB,EAAE,CAAC,EAAE;YAClC,SAAS,EAAE,IAAI;YACf,gBAAgB,EAAE,IAAI;SACvB,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { InvalidInputError } from "./errors.js";
|
|
5
|
+
export const rootDirectory = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
|
+
export function defaultDataDirectory(platform = process.platform, environment = process.env) {
|
|
7
|
+
if (environment.CLONE_DATA_DIR) {
|
|
8
|
+
return path.resolve(environment.CLONE_DATA_DIR);
|
|
9
|
+
}
|
|
10
|
+
if (platform === "darwin") {
|
|
11
|
+
return path.join(os.homedir(), "Library", "Application Support", "Clone");
|
|
12
|
+
}
|
|
13
|
+
if (platform === "win32") {
|
|
14
|
+
return path.join(environment.APPDATA ?? os.homedir(), "Clone");
|
|
15
|
+
}
|
|
16
|
+
return path.join(environment.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share"), "clone");
|
|
17
|
+
}
|
|
18
|
+
export function storagePaths(database, snapshotDirectory) {
|
|
19
|
+
const resolvedDatabase = path.resolve(database);
|
|
20
|
+
const dataDirectory = path.dirname(resolvedDatabase);
|
|
21
|
+
const resolvedSnapshot = path.resolve(snapshotDirectory ?? path.join(dataDirectory, "snapshot"));
|
|
22
|
+
const attachmentsDirectory = path.join(dataDirectory, "attachments");
|
|
23
|
+
const backupsDirectory = path.join(dataDirectory, "backups");
|
|
24
|
+
if (containsPath(resolvedSnapshot, dataDirectory) ||
|
|
25
|
+
containsPath(attachmentsDirectory, resolvedSnapshot) ||
|
|
26
|
+
containsPath(backupsDirectory, resolvedSnapshot)) {
|
|
27
|
+
throw new InvalidInputError("Snapshot directory must be separate from database storage, attachments, and backups");
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
database: resolvedDatabase,
|
|
31
|
+
dataDirectory,
|
|
32
|
+
snapshotDirectory: resolvedSnapshot,
|
|
33
|
+
attachmentsDirectory,
|
|
34
|
+
backupsDirectory,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function containsPath(parent, candidate) {
|
|
38
|
+
const relative = path.relative(parent, candidate);
|
|
39
|
+
return (relative === "" ||
|
|
40
|
+
(!relative.startsWith("..") && !path.isAbsolute(relative)));
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CACvC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAC5C,IAAI,CACL,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAClC,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAC3B,WAAW,GAAG,OAAO,CAAC,GAAG;IAEzB,IAAI,WAAW,CAAC,cAAc,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CACd,WAAW,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,EACvE,OAAO,CACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,QAAgB,EAChB,iBAA0B;IAE1B,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACrD,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CACnC,iBAAiB,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAC1D,CAAC;IACF,MAAM,oBAAoB,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;IACrE,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IAE7D,IACE,YAAY,CAAC,gBAAgB,EAAE,aAAa,CAAC;QAC7C,YAAY,CAAC,oBAAoB,EAAE,gBAAgB,CAAC;QACpD,YAAY,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,EAChD,CAAC;QACD,MAAM,IAAI,iBAAiB,CACzB,qFAAqF,CACtF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,gBAAgB;QAC1B,aAAa;QACb,iBAAiB,EAAE,gBAAgB;QACnC,oBAAoB;QACpB,gBAAgB;KACjB,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,MAAc,EAAE,SAAiB;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClD,OAAO,CACL,QAAQ,KAAK,EAAE;QACf,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAC3D,CAAC;AACJ,CAAC"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const schema = `
|
|
2
|
+
CREATE TABLE IF NOT EXISTS workspace (id INTEGER PRIMARY KEY, name TEXT NOT NULL, icon TEXT NOT NULL DEFAULT 'A', created_at TEXT NOT NULL);
|
|
3
|
+
CREATE TABLE IF NOT EXISTS members (id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT NOT NULL UNIQUE, role TEXT NOT NULL DEFAULT 'Member', avatar_color TEXT NOT NULL DEFAULT '#d8b5a4', active INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL);
|
|
4
|
+
CREATE TABLE IF NOT EXISTS actors (
|
|
5
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, kind TEXT NOT NULL CHECK(kind IN ('member','agent')),
|
|
6
|
+
name TEXT NOT NULL CHECK(length(trim(name)) > 0), active INTEGER NOT NULL DEFAULT 1 CHECK(active IN (0,1)),
|
|
7
|
+
member_id INTEGER UNIQUE REFERENCES members(id), key TEXT UNIQUE, avatar_color TEXT NOT NULL DEFAULT '#8585cc', created_at TEXT NOT NULL,
|
|
8
|
+
CHECK((kind='member' AND member_id IS NOT NULL AND member_id=id AND key IS NULL) OR (kind='agent' AND member_id IS NULL AND key IS NOT NULL AND length(trim(key)) > 0))
|
|
9
|
+
);
|
|
10
|
+
CREATE TABLE IF NOT EXISTS teams (id INTEGER PRIMARY KEY, name TEXT NOT NULL, key TEXT NOT NULL UNIQUE, description TEXT NOT NULL DEFAULT '', icon TEXT NOT NULL DEFAULT '✳', timezone TEXT NOT NULL DEFAULT 'America/Argentina/Buenos_Aires', estimate_type TEXT NOT NULL DEFAULT 'Points', created_at TEXT NOT NULL);
|
|
11
|
+
CREATE TABLE IF NOT EXISTS team_members (team_id INTEGER NOT NULL REFERENCES teams(id), member_id INTEGER NOT NULL REFERENCES actors(id), role TEXT NOT NULL DEFAULT 'Member', PRIMARY KEY(team_id, member_id));
|
|
12
|
+
CREATE TABLE IF NOT EXISTS issue_statuses (id INTEGER PRIMARY KEY, team_id INTEGER NOT NULL REFERENCES teams(id), name TEXT NOT NULL, category TEXT NOT NULL, position INTEGER NOT NULL, color TEXT NOT NULL DEFAULT '#8e8e98', is_default INTEGER NOT NULL DEFAULT 0);
|
|
13
|
+
CREATE TABLE IF NOT EXISTS labels (id INTEGER PRIMARY KEY, name TEXT NOT NULL, color TEXT NOT NULL DEFAULT '#8585cc', team_id INTEGER REFERENCES teams(id), UNIQUE(name, team_id));
|
|
14
|
+
CREATE TABLE IF NOT EXISTS projects (id INTEGER PRIMARY KEY, name TEXT NOT NULL, summary TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', status TEXT NOT NULL DEFAULT 'Backlog', priority INTEGER NOT NULL DEFAULT 4, icon TEXT NOT NULL DEFAULT '◈', lead_id INTEGER REFERENCES actors(id), start_date TEXT, target_date TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, archived INTEGER NOT NULL DEFAULT 0);
|
|
15
|
+
CREATE TABLE IF NOT EXISTS project_teams (project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE, team_id INTEGER NOT NULL REFERENCES teams(id), PRIMARY KEY(project_id, team_id));
|
|
16
|
+
CREATE TABLE IF NOT EXISTS project_members (project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE, member_id INTEGER NOT NULL REFERENCES actors(id), PRIMARY KEY(project_id, member_id));
|
|
17
|
+
CREATE TABLE IF NOT EXISTS project_labels (project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE, label_id INTEGER NOT NULL REFERENCES labels(id), PRIMARY KEY(project_id, label_id));
|
|
18
|
+
CREATE TABLE IF NOT EXISTS project_dependencies (project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE, depends_on_id INTEGER NOT NULL REFERENCES projects(id), dependency_type TEXT NOT NULL DEFAULT 'blocks', PRIMARY KEY(project_id, depends_on_id));
|
|
19
|
+
CREATE TABLE IF NOT EXISTS cycles (id INTEGER PRIMARY KEY, team_id INTEGER NOT NULL REFERENCES teams(id), name TEXT NOT NULL, starts_at TEXT NOT NULL, ends_at TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'Upcoming', capacity REAL NOT NULL DEFAULT 20, created_at TEXT NOT NULL);
|
|
20
|
+
CREATE TABLE IF NOT EXISTS milestones (id INTEGER PRIMARY KEY, project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE, name TEXT NOT NULL, due_date TEXT, status TEXT NOT NULL DEFAULT 'Todo', position INTEGER NOT NULL DEFAULT 0);
|
|
21
|
+
CREATE TABLE IF NOT EXISTS project_updates (id INTEGER PRIMARY KEY, project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE, health TEXT NOT NULL DEFAULT 'On track', body TEXT NOT NULL, author_id INTEGER REFERENCES actors(id), created_at TEXT NOT NULL);
|
|
22
|
+
CREATE TABLE IF NOT EXISTS issues (id INTEGER PRIMARY KEY, identifier TEXT NOT NULL UNIQUE, number INTEGER NOT NULL, team_id INTEGER NOT NULL REFERENCES teams(id), title TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', status_id INTEGER NOT NULL REFERENCES issue_statuses(id), priority INTEGER NOT NULL DEFAULT 4, assignee_id INTEGER REFERENCES actors(id), creator_id INTEGER REFERENCES actors(id), project_id INTEGER REFERENCES projects(id), cycle_id INTEGER REFERENCES cycles(id), milestone_id INTEGER REFERENCES milestones(id), due_date TEXT, estimate REAL, parent_id INTEGER REFERENCES issues(id), recurring_rule TEXT, external_url TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, archived INTEGER NOT NULL DEFAULT 0);
|
|
23
|
+
CREATE TABLE IF NOT EXISTS issue_labels (issue_id INTEGER NOT NULL REFERENCES issues(id) ON DELETE CASCADE, label_id INTEGER NOT NULL REFERENCES labels(id), PRIMARY KEY(issue_id, label_id));
|
|
24
|
+
CREATE TABLE IF NOT EXISTS issue_subscribers (issue_id INTEGER NOT NULL REFERENCES issues(id) ON DELETE CASCADE, member_id INTEGER NOT NULL REFERENCES actors(id), PRIMARY KEY(issue_id, member_id));
|
|
25
|
+
CREATE TABLE IF NOT EXISTS issue_relations (id INTEGER PRIMARY KEY, issue_id INTEGER NOT NULL REFERENCES issues(id) ON DELETE CASCADE, related_issue_id INTEGER REFERENCES issues(id), relation_type TEXT NOT NULL DEFAULT 'relates to', url TEXT);
|
|
26
|
+
CREATE TABLE IF NOT EXISTS comments (id INTEGER PRIMARY KEY, issue_id INTEGER NOT NULL REFERENCES issues(id) ON DELETE CASCADE, author_id INTEGER NOT NULL REFERENCES actors(id), body TEXT NOT NULL, created_at TEXT NOT NULL);
|
|
27
|
+
CREATE TABLE IF NOT EXISTS issue_attachments (id INTEGER PRIMARY KEY, issue_id INTEGER NOT NULL REFERENCES issues(id) ON DELETE CASCADE, name TEXT NOT NULL, content_type TEXT NOT NULL DEFAULT 'application/octet-stream', size INTEGER NOT NULL, storage_name TEXT NOT NULL UNIQUE, created_at TEXT NOT NULL);
|
|
28
|
+
CREATE TABLE IF NOT EXISTS activity_events (id INTEGER PRIMARY KEY, entity_type TEXT NOT NULL, entity_id INTEGER NOT NULL, actor_id INTEGER REFERENCES actors(id), action TEXT NOT NULL, payload TEXT NOT NULL DEFAULT '{}', created_at TEXT NOT NULL);
|
|
29
|
+
CREATE TABLE IF NOT EXISTS views (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', icon TEXT NOT NULL DEFAULT '◈', entity TEXT NOT NULL DEFAULT 'issues', scope TEXT NOT NULL DEFAULT 'Personal', owner_id INTEGER REFERENCES actors(id), team_id INTEGER REFERENCES teams(id), filters_json TEXT NOT NULL DEFAULT '{}', display_json TEXT NOT NULL DEFAULT '{}', is_favorite INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL);
|
|
30
|
+
CREATE TABLE IF NOT EXISTS team_resources (id INTEGER PRIMARY KEY, team_id INTEGER NOT NULL REFERENCES teams(id) ON DELETE CASCADE, section TEXT NOT NULL DEFAULT 'Resources', title TEXT NOT NULL, url TEXT);
|
|
31
|
+
CREATE TABLE IF NOT EXISTS notifications (id INTEGER PRIMARY KEY, recipient_id INTEGER NOT NULL REFERENCES actors(id), kind TEXT NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL DEFAULT '', entity_type TEXT, entity_id INTEGER, is_read INTEGER NOT NULL DEFAULT 0, archived INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL);
|
|
32
|
+
CREATE TABLE IF NOT EXISTS app_settings (key TEXT PRIMARY KEY, value_json TEXT NOT NULL, updated_at TEXT NOT NULL);
|
|
33
|
+
CREATE TABLE IF NOT EXISTS recurring_rules (id INTEGER PRIMARY KEY, team_id INTEGER NOT NULL REFERENCES teams(id), title TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', cadence TEXT NOT NULL, next_run TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL);
|
|
34
|
+
CREATE TABLE IF NOT EXISTS automations (id INTEGER PRIMARY KEY, team_id INTEGER NOT NULL REFERENCES teams(id), name TEXT NOT NULL, trigger_json TEXT NOT NULL, condition_json TEXT NOT NULL DEFAULT '{}', action_json TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL, updated_at TEXT NOT NULL);
|
|
35
|
+
`;
|
|
36
|
+
export const issueStatuses = [
|
|
37
|
+
["Backlog", "Backlog"],
|
|
38
|
+
["Todo", "Unstarted"],
|
|
39
|
+
["In Progress", "Started"],
|
|
40
|
+
["In Review", "Started"],
|
|
41
|
+
["Done", "Completed"],
|
|
42
|
+
["Canceled", "Canceled"],
|
|
43
|
+
["Duplicate", "Duplicate"],
|
|
44
|
+
];
|
|
45
|
+
export const priorities = [
|
|
46
|
+
"Urgent",
|
|
47
|
+
"High",
|
|
48
|
+
"Medium",
|
|
49
|
+
"Low",
|
|
50
|
+
"No priority",
|
|
51
|
+
];
|
|
52
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCrB,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,CAAC,SAAS,EAAE,SAAS,CAAC;IACtB,CAAC,MAAM,EAAE,WAAW,CAAC;IACrB,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,MAAM,EAAE,WAAW,CAAC;IACrB,CAAC,UAAU,EAAE,UAAU,CAAC;IACxB,CAAC,WAAW,EAAE,WAAW,CAAC;CAClB,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,KAAK;IACL,aAAa;CACL,CAAC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import http, {} from "node:http";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { URL } from "node:url";
|
|
5
|
+
import { openDatabase } from "./database.js";
|
|
6
|
+
import { CloneError, InvalidInputError } from "./errors.js";
|
|
7
|
+
import { rootDirectory } from "./paths.js";
|
|
8
|
+
import { initialize, mutate, prepare, withStorageLock } from "./sync.js";
|
|
9
|
+
import { actorRecord, actorRecords, bootstrap, dispatchMutation, issueRow, now, runDueRecurring, search, } from "./workspace.js";
|
|
10
|
+
const staticTypes = {
|
|
11
|
+
"index.html": "text/html; charset=utf-8",
|
|
12
|
+
"styles.css": "text/css; charset=utf-8",
|
|
13
|
+
"app.js": "application/javascript; charset=utf-8",
|
|
14
|
+
};
|
|
15
|
+
export async function startServer(paths, port, open) {
|
|
16
|
+
if (!fs.existsSync(paths.database)) {
|
|
17
|
+
if (fs.existsSync(paths.snapshotDirectory))
|
|
18
|
+
throw new InvalidInputError("Snapshot found. Run clone sync import first.");
|
|
19
|
+
await withStorageLock(paths, () => initialize(paths, false));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
await withStorageLock(paths, () => prepare(paths));
|
|
23
|
+
}
|
|
24
|
+
const host = process.env.CLONE_HOST ?? "127.0.0.1";
|
|
25
|
+
const server = http.createServer((request, response) => void handle(paths, request, response));
|
|
26
|
+
await new Promise((resolve, reject) => {
|
|
27
|
+
server.once("error", reject);
|
|
28
|
+
server.listen(port, host, resolve);
|
|
29
|
+
});
|
|
30
|
+
const url = `http://${host}:${port}`;
|
|
31
|
+
console.log(`Clone running at ${url} (SQLite: ${paths.database})`);
|
|
32
|
+
if (open)
|
|
33
|
+
openBrowser(url);
|
|
34
|
+
const timer = setInterval(() => {
|
|
35
|
+
void withStorageLock(paths, () => mutate(paths, (database) => runDueRecurring(database, paths))).catch((error) => {
|
|
36
|
+
console.error(`Recurring issue scheduler error: ${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
+
});
|
|
38
|
+
}, 30_000);
|
|
39
|
+
timer.unref();
|
|
40
|
+
await new Promise((resolve) => {
|
|
41
|
+
const stop = () => {
|
|
42
|
+
server.close(() => {
|
|
43
|
+
clearInterval(timer);
|
|
44
|
+
resolve();
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
process.once("SIGINT", stop);
|
|
48
|
+
process.once("SIGTERM", stop);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async function handle(paths, request, response) {
|
|
52
|
+
if (process.env.CLONE_ACCESS_LOG === "1")
|
|
53
|
+
console.log(`${request.method} ${request.url}`);
|
|
54
|
+
try {
|
|
55
|
+
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
56
|
+
const route = decodeURIComponent(url.pathname);
|
|
57
|
+
if (!route.startsWith("/api/")) {
|
|
58
|
+
serveStatic(route, response);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (request.method === "GET") {
|
|
62
|
+
const result = await withStorageLock(paths, () => apiRead(paths, route, url.searchParams));
|
|
63
|
+
if (result instanceof AttachmentResponse) {
|
|
64
|
+
sendAttachment(response, result);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
sendJson(response, result.body, result.status);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!["POST", "PUT", "PATCH", "DELETE"].includes(request.method ?? "")) {
|
|
71
|
+
sendJson(response, { error: "Not found" }, 404);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const body = await readBody(request);
|
|
75
|
+
const result = await withStorageLock(paths, () => mutate(paths, (database) => dispatchMutation(database, request.method, route, body, paths)));
|
|
76
|
+
const status = Number(result._status ?? 200);
|
|
77
|
+
delete result._status;
|
|
78
|
+
sendJson(response, result, status);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
const status = error instanceof CloneError
|
|
82
|
+
? error.code === "sync_conflict"
|
|
83
|
+
? 409
|
|
84
|
+
: error.code === "pending_export"
|
|
85
|
+
? 503
|
|
86
|
+
: 400
|
|
87
|
+
: 500;
|
|
88
|
+
const body = {
|
|
89
|
+
error: error instanceof Error ? error.message : String(error),
|
|
90
|
+
};
|
|
91
|
+
if (error instanceof CloneError)
|
|
92
|
+
Object.assign(body, error.details);
|
|
93
|
+
else
|
|
94
|
+
((body.error = "Internal error"),
|
|
95
|
+
(body.detail = error instanceof Error ? error.message : String(error)));
|
|
96
|
+
sendJson(response, body, status);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function apiRead(paths, route, query) {
|
|
100
|
+
const database = openDatabase(paths);
|
|
101
|
+
try {
|
|
102
|
+
if (route === "/api/bootstrap")
|
|
103
|
+
return json(bootstrap(database));
|
|
104
|
+
if (route === "/api/health")
|
|
105
|
+
return json({ ok: true, database: "sqlite", mode: "local-single-user" });
|
|
106
|
+
if (route === "/api/export")
|
|
107
|
+
return json({ ...bootstrap(database), exportedAt: now() });
|
|
108
|
+
if (route === "/api/search")
|
|
109
|
+
return json(search(database, query.get("q") ?? "", query.get("scope") ?? "All"));
|
|
110
|
+
const actor = route.match(/^\/api\/(actors|agents)(?:\/(\d+))?$/);
|
|
111
|
+
if (actor) {
|
|
112
|
+
const kind = actor[1] === "agents" ? "agent" : null;
|
|
113
|
+
if (actor[2]) {
|
|
114
|
+
const record = actorRecord(database, Number(actor[2]));
|
|
115
|
+
return !record || (kind && record.kind !== kind)
|
|
116
|
+
? json({ error: "Actor not found" }, 404)
|
|
117
|
+
: json(record);
|
|
118
|
+
}
|
|
119
|
+
return json(actorRecords(database, kind, query.get("all") === "true"));
|
|
120
|
+
}
|
|
121
|
+
const attachment = route.match(/^\/api\/attachments\/(\d+)$/);
|
|
122
|
+
if (attachment) {
|
|
123
|
+
const row = database
|
|
124
|
+
.prepare("SELECT * FROM issue_attachments WHERE id=?")
|
|
125
|
+
.get(Number(attachment[1]));
|
|
126
|
+
if (!row)
|
|
127
|
+
return json({ error: "Attachment not found" }, 404);
|
|
128
|
+
const content = fs.readFileSync(path.join(paths.attachmentsDirectory, String(row.storage_name)));
|
|
129
|
+
return new AttachmentResponse(content, String(row.name), String(row.content_type));
|
|
130
|
+
}
|
|
131
|
+
const issue = route.match(/^\/api\/issues\/([^/]+)$/);
|
|
132
|
+
if (issue) {
|
|
133
|
+
const row = database
|
|
134
|
+
.prepare("SELECT id FROM issues WHERE identifier=?")
|
|
135
|
+
.get(issue[1]);
|
|
136
|
+
return row
|
|
137
|
+
? json(issueRow(database, row.id))
|
|
138
|
+
: json({ error: "Issue not found" }, 404);
|
|
139
|
+
}
|
|
140
|
+
const project = route.match(/^\/api\/projects\/(\d+)$/);
|
|
141
|
+
if (project) {
|
|
142
|
+
const record = bootstrap(database).projects.find((item) => Number(item.id) === Number(project[1]));
|
|
143
|
+
return record ? json(record) : json({ error: "Project not found" }, 404);
|
|
144
|
+
}
|
|
145
|
+
return json({ error: "Not found" }, 404);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
database.close();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function serveStatic(route, response) {
|
|
152
|
+
const name = route === "/" ? "index.html" : route.slice(1);
|
|
153
|
+
if (!staticTypes[name]) {
|
|
154
|
+
response.writeHead(404);
|
|
155
|
+
response.end();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const target = path.join(rootDirectory, name);
|
|
159
|
+
const content = fs.readFileSync(target);
|
|
160
|
+
response.writeHead(200, {
|
|
161
|
+
"Content-Type": staticTypes[name],
|
|
162
|
+
"Content-Length": content.length,
|
|
163
|
+
});
|
|
164
|
+
response.end(content);
|
|
165
|
+
}
|
|
166
|
+
async function readBody(request) {
|
|
167
|
+
const declared = Number(request.headers["content-length"] ?? 0);
|
|
168
|
+
if (!Number.isFinite(declared) || declared < 0)
|
|
169
|
+
throw new InvalidInputError("Content-Length must not be negative");
|
|
170
|
+
if (declared > 5_000_000)
|
|
171
|
+
throw new InvalidInputError("Request body too large");
|
|
172
|
+
const chunks = [];
|
|
173
|
+
let size = 0;
|
|
174
|
+
for await (const chunk of request) {
|
|
175
|
+
const buffer = Buffer.from(chunk);
|
|
176
|
+
size += buffer.length;
|
|
177
|
+
if (size > 5_000_000)
|
|
178
|
+
throw new InvalidInputError("Request body too large");
|
|
179
|
+
chunks.push(buffer);
|
|
180
|
+
}
|
|
181
|
+
if (!size)
|
|
182
|
+
return {};
|
|
183
|
+
const value = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
184
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
185
|
+
throw new InvalidInputError("Request body must be an object");
|
|
186
|
+
return value;
|
|
187
|
+
}
|
|
188
|
+
function sendJson(response, body, status = 200) {
|
|
189
|
+
const content = Buffer.from(JSON.stringify(body), "utf8");
|
|
190
|
+
response.writeHead(status, {
|
|
191
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
192
|
+
"Content-Length": content.length,
|
|
193
|
+
"Cache-Control": "no-store",
|
|
194
|
+
});
|
|
195
|
+
response.end(content);
|
|
196
|
+
}
|
|
197
|
+
function sendAttachment(response, result) {
|
|
198
|
+
const fallback = result.name.replace(/[^A-Za-z0-9._-]/g, "_") || "attachment";
|
|
199
|
+
response.writeHead(200, {
|
|
200
|
+
"Content-Type": result.type,
|
|
201
|
+
"Content-Length": result.content.length,
|
|
202
|
+
"Content-Disposition": `attachment; filename="${fallback}"; filename*=UTF-8''${encodeURIComponent(result.name)}`,
|
|
203
|
+
"X-Content-Type-Options": "nosniff",
|
|
204
|
+
"Cache-Control": "no-store",
|
|
205
|
+
});
|
|
206
|
+
response.end(result.content);
|
|
207
|
+
}
|
|
208
|
+
function openBrowser(url) {
|
|
209
|
+
const command = process.platform === "darwin"
|
|
210
|
+
? ["open", url]
|
|
211
|
+
: process.platform === "win32"
|
|
212
|
+
? ["cmd", "/d", "/s", "/c", "start", "", url]
|
|
213
|
+
: ["xdg-open", url];
|
|
214
|
+
import("node:child_process").then(({ spawn }) => spawn(command[0], command.slice(1), {
|
|
215
|
+
detached: true,
|
|
216
|
+
stdio: "ignore",
|
|
217
|
+
}).unref());
|
|
218
|
+
}
|
|
219
|
+
class AttachmentResponse {
|
|
220
|
+
content;
|
|
221
|
+
name;
|
|
222
|
+
type;
|
|
223
|
+
constructor(content, name, type) {
|
|
224
|
+
this.content = content;
|
|
225
|
+
this.name = name;
|
|
226
|
+
this.type = type;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function json(body, status = 200) {
|
|
230
|
+
return { body, status };
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|