@intactfile/node-core 0.1.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/dist/api.d.ts +46 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +66 -0
- package/dist/api.js.map +1 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/engine.d.ts +38 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +130 -0
- package/dist/engine.js.map +1 -0
- package/dist/entitlement.d.ts +19 -0
- package/dist/entitlement.d.ts.map +1 -0
- package/dist/entitlement.js +59 -0
- package/dist/entitlement.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/package.json +30 -0
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin client for api.intactfile.com. JSON only — it carries tokens and
|
|
3
|
+
* counters, never file bytes (the whole point: repairs run locally).
|
|
4
|
+
*/
|
|
5
|
+
/** Overridable for dev/tests via INTACTFILE_API_BASE. */
|
|
6
|
+
export declare const API_BASE: string;
|
|
7
|
+
export interface Subscription {
|
|
8
|
+
tier: "pro" | "business";
|
|
9
|
+
activeUntil: string;
|
|
10
|
+
monthlyRemaining: number;
|
|
11
|
+
}
|
|
12
|
+
export interface AuthResult {
|
|
13
|
+
balance: number;
|
|
14
|
+
subscription: Subscription | null;
|
|
15
|
+
token?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ConsumeResult {
|
|
18
|
+
source: "subscription" | "credits";
|
|
19
|
+
balance: number;
|
|
20
|
+
subscription: Subscription | null;
|
|
21
|
+
receipt: string;
|
|
22
|
+
token?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class ApiError extends Error {
|
|
25
|
+
readonly status: number;
|
|
26
|
+
readonly code: string;
|
|
27
|
+
constructor(status: number, code: string, message: string);
|
|
28
|
+
}
|
|
29
|
+
export declare function login(email: string, password: string): Promise<AuthResult & {
|
|
30
|
+
ok: true;
|
|
31
|
+
}>;
|
|
32
|
+
export declare function recover(email: string): Promise<{
|
|
33
|
+
ok: boolean;
|
|
34
|
+
reason?: string;
|
|
35
|
+
message?: string;
|
|
36
|
+
}>;
|
|
37
|
+
export declare function magic(magicToken: string): Promise<AuthResult & {
|
|
38
|
+
ok: true;
|
|
39
|
+
}>;
|
|
40
|
+
export declare function balance(token: string): Promise<AuthResult & {
|
|
41
|
+
ok: true;
|
|
42
|
+
}>;
|
|
43
|
+
export declare function consume(token: string): Promise<ConsumeResult & {
|
|
44
|
+
ok: true;
|
|
45
|
+
}>;
|
|
46
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,yDAAyD;AACzD,eAAO,MAAM,QAAQ,QAA0E,CAAC;AAEhG,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,GAAG,UAAU,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,QAAS,SAAQ,KAAK;IAE/B,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM;gBADZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM;CAKlB;AAwBD,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAMzF;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAMlG;AAED,wBAAgB,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAE5E;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAEzE;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAM5E"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin client for api.intactfile.com. JSON only — it carries tokens and
|
|
3
|
+
* counters, never file bytes (the whole point: repairs run locally).
|
|
4
|
+
*/
|
|
5
|
+
/** Overridable for dev/tests via INTACTFILE_API_BASE. */
|
|
6
|
+
export const API_BASE = process.env.INTACTFILE_API_BASE?.trim() || "https://api.intactfile.com";
|
|
7
|
+
export class ApiError extends Error {
|
|
8
|
+
status;
|
|
9
|
+
code;
|
|
10
|
+
constructor(status, code, message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.status = status;
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.name = "ApiError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function request(path, init) {
|
|
18
|
+
let res;
|
|
19
|
+
try {
|
|
20
|
+
res = await fetch(`${API_BASE}${path}`, init);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new ApiError(0, "offline", "Couldn't reach api.intactfile.com — check your connection.");
|
|
24
|
+
}
|
|
25
|
+
let data = null;
|
|
26
|
+
try {
|
|
27
|
+
data = await res.json();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
/* leave null */
|
|
31
|
+
}
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
const err = data?.error;
|
|
34
|
+
throw new ApiError(res.status, err?.code ?? "error", err?.message ?? `Request failed (${res.status}).`);
|
|
35
|
+
}
|
|
36
|
+
return data;
|
|
37
|
+
}
|
|
38
|
+
const jsonHeaders = { "Content-Type": "application/json" };
|
|
39
|
+
export function login(email, password) {
|
|
40
|
+
return request(`/login`, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: jsonHeaders,
|
|
43
|
+
body: JSON.stringify({ email, password }),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function recover(email) {
|
|
47
|
+
return request(`/recover`, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
headers: jsonHeaders,
|
|
50
|
+
body: JSON.stringify({ email }),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export function magic(magicToken) {
|
|
54
|
+
return request(`/magic?token=${encodeURIComponent(magicToken)}`, { method: "GET" });
|
|
55
|
+
}
|
|
56
|
+
export function balance(token) {
|
|
57
|
+
return request(`/balance`, { method: "GET", headers: { Authorization: `Bearer ${token}` } });
|
|
58
|
+
}
|
|
59
|
+
export function consume(token) {
|
|
60
|
+
return request(`/consume`, {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: { ...jsonHeaders, Authorization: `Bearer ${token}` },
|
|
63
|
+
body: JSON.stringify({ kind: "repair" }),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,yDAAyD;AACzD,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,EAAE,IAAI,4BAA4B,CAAC;AAsBhG,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEtB;IACA;IAFX,YACW,MAAc,EACd,IAAY,EACrB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QAIrB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,KAAK,UAAU,OAAO,CAAI,IAAY,EAAE,IAAiB;IACvD,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,GAAG,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,4DAA4D,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,IAAI,GAAY,IAAI,CAAC;IACzB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,GAAG,GAAI,IAA+D,EAAE,KAAK,CAAC;QACpF,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,IAAI,OAAO,EAAE,GAAG,EAAE,OAAO,IAAI,mBAAmB,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,IAAS,CAAC;AACnB,CAAC;AAED,MAAM,WAAW,GAAG,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;AAE3D,MAAM,UAAU,KAAK,CAAC,KAAa,EAAE,QAAgB;IACnD,OAAO,OAAO,CAAC,QAAQ,EAAE;QACvB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,WAAW;QACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;KAC1C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,OAAO,CAAC,UAAU,EAAE;QACzB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,WAAW;QACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;KAChC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,UAAkB;IACtC,OAAO,OAAO,CAAC,gBAAgB,kBAAkB,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,OAAO,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,OAAO,CAAC,UAAU,EAAE;QACzB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,GAAG,WAAW,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;QAC7D,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;KACzC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface CachedEntitlement {
|
|
2
|
+
tier: "pro" | "business";
|
|
3
|
+
activeUntil: string;
|
|
4
|
+
monthlyRemaining: number;
|
|
5
|
+
checkedAt: number;
|
|
6
|
+
}
|
|
7
|
+
export interface Config {
|
|
8
|
+
token?: string;
|
|
9
|
+
entitlement?: CachedEntitlement;
|
|
10
|
+
}
|
|
11
|
+
/** Overridable for tests via INTACTFILE_CONFIG. */
|
|
12
|
+
export declare function configPath(): string;
|
|
13
|
+
export declare function readConfig(): Config;
|
|
14
|
+
export declare function writeConfig(cfg: Config): void;
|
|
15
|
+
export declare function getToken(): string | undefined;
|
|
16
|
+
export declare function setToken(token: string): void;
|
|
17
|
+
export declare function clearAuth(): void;
|
|
18
|
+
export declare function cacheEntitlement(ent: CachedEntitlement | undefined): void;
|
|
19
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,KAAK,GAAG,UAAU,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC;AAOD,mDAAmD;AACnD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAMnC;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAU7C;AAED,wBAAgB,QAAQ,IAAI,MAAM,GAAG,SAAS,CAE7C;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,SAAS,IAAI,IAAI,CAKhC;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,GAAG,SAAS,GAAG,IAAI,CAEzE"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local config + license-token store for the CLI and MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Lives at $XDG_CONFIG_HOME/intactfile/config.json (default ~/.config/...),
|
|
5
|
+
* written with 0600 perms. Holds the bearer token and a cached entitlement so
|
|
6
|
+
* paying users keep working briefly offline. Never logged, never printed.
|
|
7
|
+
*/
|
|
8
|
+
import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
function configDir() {
|
|
12
|
+
const base = process.env.XDG_CONFIG_HOME?.trim() || join(homedir(), ".config");
|
|
13
|
+
return join(base, "intactfile");
|
|
14
|
+
}
|
|
15
|
+
/** Overridable for tests via INTACTFILE_CONFIG. */
|
|
16
|
+
export function configPath() {
|
|
17
|
+
return process.env.INTACTFILE_CONFIG?.trim() || join(configDir(), "config.json");
|
|
18
|
+
}
|
|
19
|
+
export function readConfig() {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(readFileSync(configPath(), "utf8"));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function writeConfig(cfg) {
|
|
28
|
+
const path = configPath();
|
|
29
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
30
|
+
writeFileSync(path, JSON.stringify(cfg, null, 2), { mode: 0o600 });
|
|
31
|
+
// writeFileSync only applies mode on create; enforce it on an existing file too.
|
|
32
|
+
try {
|
|
33
|
+
chmodSync(path, 0o600);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
/* best effort (e.g. Windows) */
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function getToken() {
|
|
40
|
+
return readConfig().token;
|
|
41
|
+
}
|
|
42
|
+
export function setToken(token) {
|
|
43
|
+
writeConfig({ ...readConfig(), token });
|
|
44
|
+
}
|
|
45
|
+
export function clearAuth() {
|
|
46
|
+
const cfg = readConfig();
|
|
47
|
+
delete cfg.token;
|
|
48
|
+
delete cfg.entitlement;
|
|
49
|
+
writeConfig(cfg);
|
|
50
|
+
}
|
|
51
|
+
export function cacheEntitlement(ent) {
|
|
52
|
+
writeConfig({ ...readConfig(), entitlement: ent });
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAc1C,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC/E,OAAO,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;AAClC,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,UAAU;IACxB,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,CAAW,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,iFAAiF;IACjF,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,UAAU,EAAE,CAAC,KAAK,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,WAAW,CAAC,EAAE,GAAG,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,OAAO,GAAG,CAAC,KAAK,CAAC;IACjB,OAAO,GAAG,CAAC,WAAW,CAAC;IACvB,WAAW,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAkC;IACjE,WAAW,CAAC,EAAE,GAAG,UAAU,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;AACrD,CAAC"}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type Family = "zip" | "pdf" | "video" | "jpeg" | "png" | "sqlite" | "archive";
|
|
2
|
+
export type EngineReport = Record<string, unknown>;
|
|
3
|
+
export type RepairResult = {
|
|
4
|
+
kind: "file";
|
|
5
|
+
family: Family;
|
|
6
|
+
bytes: Uint8Array;
|
|
7
|
+
usable: boolean;
|
|
8
|
+
report: EngineReport;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "archive";
|
|
11
|
+
family: "archive";
|
|
12
|
+
files: {
|
|
13
|
+
name: string;
|
|
14
|
+
data: Uint8Array;
|
|
15
|
+
status: string;
|
|
16
|
+
}[];
|
|
17
|
+
usable: boolean;
|
|
18
|
+
report: EngineReport;
|
|
19
|
+
};
|
|
20
|
+
export interface RepairOptions {
|
|
21
|
+
/** Healthy reference clip/photo for missing-moov video or JPEG donor transplant. */
|
|
22
|
+
referencePath?: string;
|
|
23
|
+
/** Archive password (RAR/7z). */
|
|
24
|
+
password?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare class UnsupportedError extends Error {
|
|
27
|
+
constructor(message: string);
|
|
28
|
+
}
|
|
29
|
+
/** Read-only classification for the free `diagnose` path — never writes/repairs. */
|
|
30
|
+
export declare function diagnosePath(path: string): Promise<{
|
|
31
|
+
family: Family | "unknown";
|
|
32
|
+
format: string;
|
|
33
|
+
confidence: string;
|
|
34
|
+
notes: string[];
|
|
35
|
+
}>;
|
|
36
|
+
/** Repair a file locally. Throws UnsupportedError for formats we can't repair. */
|
|
37
|
+
export declare function repairPath(path: string, opts?: RepairOptions): Promise<RepairResult>;
|
|
38
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;AAErF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnD,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAC1F;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5D,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEN,MAAM,WAAW,aAAa;IAC5B,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAmCD,oFAAoF;AACpF,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAS9F;AAUD,kFAAkF;AAClF,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAwD9F"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local repair dispatch. Opens a file as a Node ByteSource and runs the right
|
|
3
|
+
* IntactFile engine entirely in-process — no bytes ever leave the machine.
|
|
4
|
+
* The engines resolve their own wasm from node_modules (no wiring needed here).
|
|
5
|
+
*/
|
|
6
|
+
import { detectFormat, repairZip } from "@intactfile/engines";
|
|
7
|
+
import { salvageArchive } from "@intactfile/engines/archive";
|
|
8
|
+
import { repairJpeg } from "@intactfile/engines/jpeg";
|
|
9
|
+
import { NodeFileSource } from "@intactfile/engines/node";
|
|
10
|
+
import { repairPdf } from "@intactfile/engines/pdf";
|
|
11
|
+
import { repairPng } from "@intactfile/engines/png";
|
|
12
|
+
import { recoverSqlite } from "@intactfile/engines/sqlite";
|
|
13
|
+
import { remuxVideo, reconstructMoov } from "@intactfile/engines/video";
|
|
14
|
+
export class UnsupportedError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "UnsupportedError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const eq = (a, at, sig) => sig.every((b, i) => a[at + i] === b);
|
|
21
|
+
const SQLITE_MAGIC = [...new TextEncoder().encode("SQLite format 3\0")];
|
|
22
|
+
async function classify(src) {
|
|
23
|
+
const head = await src.read(0, 16);
|
|
24
|
+
if (eq(head, 0, SQLITE_MAGIC))
|
|
25
|
+
return "sqlite";
|
|
26
|
+
if (eq(head, 0, [0x52, 0x61, 0x72, 0x21]))
|
|
27
|
+
return "archive"; // "Rar!"
|
|
28
|
+
if (eq(head, 0, [0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c]))
|
|
29
|
+
return "archive"; // 7z
|
|
30
|
+
// detectFormat covers zip/pdf/jpeg/png/video (with garbage-prefix tolerance).
|
|
31
|
+
const det = await detectFormat(src);
|
|
32
|
+
switch (det.format) {
|
|
33
|
+
case "zip":
|
|
34
|
+
return "zip";
|
|
35
|
+
case "pdf":
|
|
36
|
+
return "pdf";
|
|
37
|
+
case "jpeg":
|
|
38
|
+
return "jpeg";
|
|
39
|
+
case "png":
|
|
40
|
+
return "png";
|
|
41
|
+
case "mp4":
|
|
42
|
+
case "mov":
|
|
43
|
+
case "mkv":
|
|
44
|
+
case "webm":
|
|
45
|
+
case "avi":
|
|
46
|
+
case "riff":
|
|
47
|
+
return "video";
|
|
48
|
+
default:
|
|
49
|
+
return "unknown"; // wav/mp3 (no repair engine yet) or truly unknown
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Read-only classification for the free `diagnose` path — never writes/repairs. */
|
|
53
|
+
export async function diagnosePath(path) {
|
|
54
|
+
const src = await NodeFileSource.open(path);
|
|
55
|
+
try {
|
|
56
|
+
const family = await classify(src);
|
|
57
|
+
const det = await detectFormat(src);
|
|
58
|
+
return { family, format: det.format, confidence: det.confidence, notes: det.notes };
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
await src.close();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function fileResult(family, bytes, reportRaw) {
|
|
65
|
+
const report = reportRaw;
|
|
66
|
+
const usable = bytes.length > 0 &&
|
|
67
|
+
(family === "zip" ? Number(report.entriesIncluded ?? 0) > 0 : report.outcome !== "failed");
|
|
68
|
+
return { kind: "file", family, bytes, usable, report };
|
|
69
|
+
}
|
|
70
|
+
/** Repair a file locally. Throws UnsupportedError for formats we can't repair. */
|
|
71
|
+
export async function repairPath(path, opts = {}) {
|
|
72
|
+
const src = await NodeFileSource.open(path);
|
|
73
|
+
try {
|
|
74
|
+
const family = await classify(src);
|
|
75
|
+
switch (family) {
|
|
76
|
+
case "zip": {
|
|
77
|
+
const { zip, report } = await repairZip(src);
|
|
78
|
+
return fileResult("zip", zip, report);
|
|
79
|
+
}
|
|
80
|
+
case "pdf": {
|
|
81
|
+
const { pdf, report } = await repairPdf(src);
|
|
82
|
+
return fileResult("pdf", pdf, report);
|
|
83
|
+
}
|
|
84
|
+
case "video": {
|
|
85
|
+
if (opts.referencePath) {
|
|
86
|
+
const ref = await NodeFileSource.open(opts.referencePath);
|
|
87
|
+
try {
|
|
88
|
+
const { video, report } = await reconstructMoov(src, ref);
|
|
89
|
+
return fileResult("video", video, report);
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
await ref.close();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const { video, report } = await remuxVideo(src);
|
|
96
|
+
return fileResult("video", video, report);
|
|
97
|
+
}
|
|
98
|
+
case "jpeg": {
|
|
99
|
+
const ref = opts.referencePath ? await NodeFileSource.open(opts.referencePath) : undefined;
|
|
100
|
+
try {
|
|
101
|
+
const r = await repairJpeg(src, ref ? { reference: ref } : {});
|
|
102
|
+
return fileResult("jpeg", r.image ?? r.preview ?? new Uint8Array(0), r.report);
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
if (ref)
|
|
106
|
+
await ref.close();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
case "png": {
|
|
110
|
+
const r = await repairPng(src);
|
|
111
|
+
return fileResult("png", r.image ?? new Uint8Array(0), r.report);
|
|
112
|
+
}
|
|
113
|
+
case "sqlite": {
|
|
114
|
+
const r = await recoverSqlite(src);
|
|
115
|
+
return fileResult("sqlite", r.db ?? new Uint8Array(0), r.report);
|
|
116
|
+
}
|
|
117
|
+
case "archive": {
|
|
118
|
+
const r = await salvageArchive(src, opts.password ? { password: opts.password } : {});
|
|
119
|
+
const usable = r.files.some((f) => f.status === "ok");
|
|
120
|
+
return { kind: "archive", family: "archive", files: r.files, usable, report: r.report };
|
|
121
|
+
}
|
|
122
|
+
default:
|
|
123
|
+
throw new UnsupportedError("This file isn't a format IntactFile can repair (supported: video, ZIP/Office, PDF, JPEG, PNG, SQLite, RAR/7z).");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
await src.close();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAuBxE,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,MAAM,EAAE,GAAG,CAAC,CAAa,EAAE,EAAU,EAAE,GAAa,EAAW,EAAE,CAC/D,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAEvC,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAExE,KAAK,UAAU,QAAQ,CAAC,GAAe;IACrC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,YAAY,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/C,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC,CAAC,SAAS;IACtE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC,CAAC,KAAK;IAC9E,8EAA8E;IAC9E,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IACpC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;QACnB,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,KAAK,KAAK,CAAC;QACX,KAAK,MAAM;YACT,OAAO,OAAO,CAAC;QACjB;YACE,OAAO,SAAS,CAAC,CAAC,kDAAkD;IACxE,CAAC;AACH,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAY;IAEZ,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;IACtF,CAAC;YAAS,CAAC;QACT,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,MAAc,EAAE,KAAiB,EAAE,SAAkB;IACvE,MAAM,MAAM,GAAG,SAAyB,CAAC;IACzC,MAAM,MAAM,GACV,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC;IAC7F,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACzD,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,OAAsB,EAAE;IACrE,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;QACnC,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,KAAK,CAAC,CAAC,CAAC;gBACX,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;gBAC7C,OAAO,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YACxC,CAAC;YACD,KAAK,KAAK,CAAC,CAAC,CAAC;gBACX,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;gBAC7C,OAAO,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YACxC,CAAC;YACD,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBACvB,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;oBAC1D,IAAI,CAAC;wBACH,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;wBAC1D,OAAO,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;oBAC5C,CAAC;4BAAS,CAAC;wBACT,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;oBACpB,CAAC;gBACH,CAAC;gBACD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;gBAChD,OAAO,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;YAC5C,CAAC;YACD,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC3F,IAAI,CAAC;oBACH,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC/D,OAAO,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;gBACjF,CAAC;wBAAS,CAAC;oBACT,IAAI,GAAG;wBAAE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;gBAC7B,CAAC;YACH,CAAC;YACD,KAAK,KAAK,CAAC,CAAC,CAAC;gBACX,MAAM,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;gBAC/B,OAAO,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;YACnE,CAAC;YACD,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;gBACnC,OAAO,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;YACnE,CAAC;YACD,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACtF,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;gBACtD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAiC,EAAE,CAAC;YACrH,CAAC;YACD;gBACE,MAAM,IAAI,gBAAgB,CACxB,gHAAgH,CACjH,CAAC;QACN,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business-tier gate for the CLI/MCP. Source of truth is GET /balance
|
|
3
|
+
* (tier === "business"). A successful check is cached so paying users keep
|
|
4
|
+
* working briefly offline; outside that grace window, or with no cache, the
|
|
5
|
+
* gate is fail-closed — no silent free repairs.
|
|
6
|
+
*/
|
|
7
|
+
import { type Subscription } from "./api.js";
|
|
8
|
+
export type EntitlementCode = "not-logged-in" | "not-business" | "expired" | "offline";
|
|
9
|
+
export declare class EntitlementError extends Error {
|
|
10
|
+
readonly code: EntitlementCode;
|
|
11
|
+
constructor(code: EntitlementCode, message: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the active Business subscription or throw. Refreshes the token if the
|
|
15
|
+
* server rolled it. Falls back to the cached entitlement only within the grace
|
|
16
|
+
* window when the network is unreachable.
|
|
17
|
+
*/
|
|
18
|
+
export declare function requireBusiness(): Promise<Subscription>;
|
|
19
|
+
//# sourceMappingURL=entitlement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entitlement.d.ts","sourceRoot":"","sources":["../src/entitlement.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAW,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAKtD,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;AAEvF,qBAAa,gBAAiB,SAAQ,KAAK;IAEvC,QAAQ,CAAC,IAAI,EAAE,eAAe;gBAArB,IAAI,EAAE,eAAe,EAC9B,OAAO,EAAE,MAAM;CAKlB;AAKD;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAoC7D"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business-tier gate for the CLI/MCP. Source of truth is GET /balance
|
|
3
|
+
* (tier === "business"). A successful check is cached so paying users keep
|
|
4
|
+
* working briefly offline; outside that grace window, or with no cache, the
|
|
5
|
+
* gate is fail-closed — no silent free repairs.
|
|
6
|
+
*/
|
|
7
|
+
import { balance } from "./api.js";
|
|
8
|
+
import { cacheEntitlement, getToken, readConfig, setToken } from "./config.js";
|
|
9
|
+
const GRACE_MS = 72 * 3600 * 1000;
|
|
10
|
+
export class EntitlementError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
constructor(code, message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.name = "EntitlementError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const isActive = (s) => !!s && Date.parse(s.activeUntil) > Date.now();
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the active Business subscription or throw. Refreshes the token if the
|
|
21
|
+
* server rolled it. Falls back to the cached entitlement only within the grace
|
|
22
|
+
* window when the network is unreachable.
|
|
23
|
+
*/
|
|
24
|
+
export async function requireBusiness() {
|
|
25
|
+
const token = getToken();
|
|
26
|
+
if (!token) {
|
|
27
|
+
throw new EntitlementError("not-logged-in", "Not signed in. Run `intactfile login` first.");
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const res = await balance(token);
|
|
31
|
+
if (res.token)
|
|
32
|
+
setToken(res.token);
|
|
33
|
+
const sub = res.subscription;
|
|
34
|
+
if (isActive(sub) && sub.tier === "business") {
|
|
35
|
+
cacheEntitlement({ ...sub, checkedAt: Date.now() });
|
|
36
|
+
return sub;
|
|
37
|
+
}
|
|
38
|
+
// Reached the server: the answer is authoritative — clear any stale cache.
|
|
39
|
+
cacheEntitlement(undefined);
|
|
40
|
+
if (sub && sub.tier !== "business") {
|
|
41
|
+
throw new EntitlementError("not-business", "This account isn't on the Business plan.");
|
|
42
|
+
}
|
|
43
|
+
throw new EntitlementError("expired", "No active Business subscription on this account.");
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
if (e instanceof EntitlementError)
|
|
47
|
+
throw e;
|
|
48
|
+
// Network/other failure: honour a recent cached Business entitlement.
|
|
49
|
+
const cached = readConfig().entitlement;
|
|
50
|
+
if (cached &&
|
|
51
|
+
cached.tier === "business" &&
|
|
52
|
+
Date.now() - cached.checkedAt < GRACE_MS &&
|
|
53
|
+
Date.parse(cached.activeUntil) > Date.now()) {
|
|
54
|
+
return { tier: cached.tier, activeUntil: cached.activeUntil, monthlyRemaining: cached.monthlyRemaining };
|
|
55
|
+
}
|
|
56
|
+
throw new EntitlementError("offline", "Couldn't verify your Business subscription (offline and no recent cached license).");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=entitlement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entitlement.js","sourceRoot":"","sources":["../src/entitlement.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,OAAO,EAAqB,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE/E,MAAM,QAAQ,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAIlC,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAE9B;IADX,YACW,IAAqB,EAC9B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,SAAI,GAAJ,IAAI,CAAiB;QAI9B,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,MAAM,QAAQ,GAAG,CAAC,CAAkC,EAAqB,EAAE,CACzE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,gBAAgB,CAAC,eAAe,EAAE,8CAA8C,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,GAAG,CAAC,KAAK;YAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC;QAC7B,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7C,gBAAgB,CAAC,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACpD,OAAO,GAAG,CAAC;QACb,CAAC;QACD,2EAA2E;QAC3E,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAC5B,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,gBAAgB,CAAC,cAAc,EAAE,0CAA0C,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,IAAI,gBAAgB,CAAC,SAAS,EAAE,kDAAkD,CAAC,CAAC;IAC5F,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,gBAAgB;YAAE,MAAM,CAAC,CAAC;QAC3C,sEAAsE;QACtE,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC,WAAW,CAAC;QACxC,IACE,MAAM;YACN,MAAM,CAAC,IAAI,KAAK,UAAU;YAC1B,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,QAAQ;YACxC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,EAC3C,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC3G,CAAC;QACD,MAAM,IAAI,gBAAgB,CACxB,SAAS,EACT,oFAAoF,CACrF,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @intactfile/node-core — shared building blocks for the CLI and MCP server.
|
|
3
|
+
* Local repair (files never leave the machine) + Business entitlement gate.
|
|
4
|
+
*/
|
|
5
|
+
export * from "./config.js";
|
|
6
|
+
export * from "./api.js";
|
|
7
|
+
export * from "./entitlement.js";
|
|
8
|
+
export * from "./engine.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @intactfile/node-core — shared building blocks for the CLI and MCP server.
|
|
3
|
+
* Local repair (files never leave the machine) + Business entitlement gate.
|
|
4
|
+
*/
|
|
5
|
+
export * from "./config.js";
|
|
6
|
+
export * from "./api.js";
|
|
7
|
+
export * from "./entitlement.js";
|
|
8
|
+
export * from "./engine.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intactfile/node-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared Node core for the IntactFile CLI and MCP server: license/entitlement checks + local repair dispatch. Files never leave the machine.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=22"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@intactfile/engines": "0.1.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.15.0",
|
|
25
|
+
"typescript": "^5.9.3"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -p tsconfig.json"
|
|
29
|
+
}
|
|
30
|
+
}
|