@axonflow/openclaw 2.1.1 → 2.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/CHANGELOG.md +30 -0
- package/README.md +93 -2
- package/bin/axonflow-openclaw-recover.mjs +229 -0
- package/bin/axonflow-openclaw-status.mjs +86 -0
- package/dist/axonflow-client.d.ts +2 -0
- package/dist/axonflow-client.d.ts.map +1 -1
- package/dist/axonflow-client.js +30 -0
- package/dist/axonflow-client.js.map +1 -1
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -2
- package/dist/index.js.map +1 -1
- package/dist/recover.d.ts +120 -0
- package/dist/recover.d.ts.map +1 -0
- package/dist/recover.js +263 -0
- package/dist/recover.js.map +1 -0
- package/dist/status.d.ts +215 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +377 -0
- package/dist/status.js.map +1 -0
- package/dist/version.d.ts +11 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/openclaw.plugin.json +13 -0
- package/package.json +6 -1
package/dist/config.d.ts
CHANGED
|
@@ -11,6 +11,27 @@ export interface AxonFlowPluginConfig {
|
|
|
11
11
|
clientId: string;
|
|
12
12
|
/** License key for evaluation/enterprise features. Empty for community mode. */
|
|
13
13
|
clientSecret: string;
|
|
14
|
+
/**
|
|
15
|
+
* Plugin-claim license token (W4 paid Pro v1 tier, ADR-049).
|
|
16
|
+
*
|
|
17
|
+
* AXON-prefixed Ed25519-signed JWT issued by axonflow-billing on a
|
|
18
|
+
* successful Stripe checkout. When present, the plugin forwards it on
|
|
19
|
+
* every governed HTTP request via the `X-License-Token` header so the
|
|
20
|
+
* agent's PluginClaimMiddleware can validate it and enrich the request
|
|
21
|
+
* context with Pro-tier entitlements (retention, quotas, capabilities).
|
|
22
|
+
*
|
|
23
|
+
* Resolution order (matches the W4 launch spec):
|
|
24
|
+
* 1. process.env.AXONFLOW_LICENSE_TOKEN
|
|
25
|
+
* 2. pluginConfig.licenseToken
|
|
26
|
+
* 3. unset → free tier (no header sent)
|
|
27
|
+
*
|
|
28
|
+
* Empty / whitespace values are treated as unset. The plugin does NOT
|
|
29
|
+
* validate the token client-side — validation is the agent middleware's
|
|
30
|
+
* job. A malformed token sent here will be rejected with 401 by the
|
|
31
|
+
* platform on the first governed request, and the existing onError
|
|
32
|
+
* fail-closed/open path applies.
|
|
33
|
+
*/
|
|
34
|
+
licenseToken?: string;
|
|
14
35
|
/**
|
|
15
36
|
* Per-user identity forwarded on every request via X-User-Email.
|
|
16
37
|
*
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,oBAAoB;IACnC,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IAEjB,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;IAEjB,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IAErB;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAE5B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;;;;OAUG;IACH,IAAI,EAAE,gBAAgB,GAAG,aAAa,CAAC;CACxC;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACvC,oBAAoB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,oBAAoB;IACnC,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IAEjB,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;IAEjB,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IAErB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAE5B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;;;;OAUG;IACH,IAAI,EAAE,gBAAgB,GAAG,aAAa,CAAC;CACxC;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACvC,oBAAoB,CAsFtB;AAED,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAWT"}
|
package/dist/config.js
CHANGED
|
@@ -53,11 +53,23 @@ export function resolveConfig(raw) {
|
|
|
53
53
|
clientId = "";
|
|
54
54
|
clientSecret = "";
|
|
55
55
|
}
|
|
56
|
+
// License token resolution — env wins over pluginConfig per ADR-049 + the
|
|
57
|
+
// W4 spec, matching how every other AxonFlow surface resolves credentials
|
|
58
|
+
// (env > config > unset). Tolerates "AXON-" prefix or any other shape;
|
|
59
|
+
// validation lives server-side in the agent's PluginClaimMiddleware.
|
|
60
|
+
const envToken = typeof process.env["AXONFLOW_LICENSE_TOKEN"] === "string"
|
|
61
|
+
? process.env["AXONFLOW_LICENSE_TOKEN"].trim()
|
|
62
|
+
: "";
|
|
63
|
+
const cfgToken = typeof safe["licenseToken"] === "string"
|
|
64
|
+
? safe["licenseToken"].trim()
|
|
65
|
+
: "";
|
|
66
|
+
const licenseToken = envToken || cfgToken || undefined;
|
|
56
67
|
return {
|
|
57
68
|
endpoint,
|
|
58
69
|
clientId,
|
|
59
70
|
clientSecret,
|
|
60
71
|
mode,
|
|
72
|
+
licenseToken,
|
|
61
73
|
userEmail: typeof safe["userEmail"] === "string" && safe["userEmail"].trim()
|
|
62
74
|
? safe["userEmail"].trim()
|
|
63
75
|
: undefined,
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
* for async hook support.
|
|
26
26
|
*/
|
|
27
27
|
import { type AgentToolDef } from "./agent-tools.js";
|
|
28
|
-
/** Plugin version —
|
|
29
|
-
|
|
28
|
+
/** Plugin version — re-exported from version.ts so non-index consumers
|
|
29
|
+
* (axonflow-client.ts, etc.) can read it without circular-dep risk. */
|
|
30
|
+
export { VERSION } from "./version.js";
|
|
30
31
|
export { AxonFlowClient } from "./axonflow-client.js";
|
|
31
32
|
export type { AxonFlowPluginConfig } from "./config.js";
|
|
32
33
|
export { resolveConfig, shouldGovernTool } from "./config.js";
|
|
@@ -34,6 +35,10 @@ export { deriveConnectorType } from "./governance.js";
|
|
|
34
35
|
export { getMetrics, type GovernanceMetrics } from "./metrics.js";
|
|
35
36
|
export { buildAgentTools, buildAuditSearchTool, buildExplainDecisionTool, buildListOverridesTool, buildCreateOverrideTool, buildRevokeOverrideTool, } from "./agent-tools.js";
|
|
36
37
|
export type { AgentToolDef } from "./agent-tools.js";
|
|
38
|
+
export { requestRecovery, verifyRecovery, extractRecoveryToken, persistRecoveredCredentials, RECOVERY_DEFAULT_ENDPOINT, } from "./recover.js";
|
|
39
|
+
export type { RequestRecoveryResult, VerifyRecoveryResult, RecoveryHttpOptions, } from "./recover.js";
|
|
40
|
+
export { buildProTierInitLogLine, buildStatusReport, daysUntil, formatExpiryDate, formatStatusReport, parseLicenseTokenExpiry, resolveStatusInputs, redactLicenseToken, readPersistedTenantId, STATUS_DEFAULT_ENDPOINT, STATUS_DEFAULT_UPGRADE_URL, } from "./status.js";
|
|
41
|
+
export type { StatusInputs, StatusReport, StatusTier, } from "./status.js";
|
|
37
42
|
/**
|
|
38
43
|
* Plugin registration function.
|
|
39
44
|
*
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAaH,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAaH,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAItE;uEACuE;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKrD,OAAO,EACL,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,UAAU,GACX,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,MAAM,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IACpG,EAAE,EAAE,CACF,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAChC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KACzB,IAAI,CAAC;IAKV,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC7E,GAAG,IAAI,CAuLP;AAED;;;;;;GAMG;;;;;;;AACH,wBAKE"}
|
package/dist/index.js
CHANGED
|
@@ -35,14 +35,27 @@ import { bootstrapCommunitySaas } from "./community-saas-bootstrap.js";
|
|
|
35
35
|
import { resetMetrics } from "./metrics.js";
|
|
36
36
|
import { runPluginVersionCheck } from "./plugin-version-check.js";
|
|
37
37
|
import { buildAgentTools } from "./agent-tools.js";
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
import { buildProTierInitLogLine } from "./status.js";
|
|
39
|
+
import { VERSION } from "./version.js";
|
|
40
|
+
/** Plugin version — re-exported from version.ts so non-index consumers
|
|
41
|
+
* (axonflow-client.ts, etc.) can read it without circular-dep risk. */
|
|
42
|
+
export { VERSION } from "./version.js";
|
|
40
43
|
// Re-export for external consumers
|
|
41
44
|
export { AxonFlowClient } from "./axonflow-client.js";
|
|
42
45
|
export { resolveConfig, shouldGovernTool } from "./config.js";
|
|
43
46
|
export { deriveConnectorType } from "./governance.js";
|
|
44
47
|
export { getMetrics } from "./metrics.js";
|
|
45
48
|
export { buildAgentTools, buildAuditSearchTool, buildExplainDecisionTool, buildListOverridesTool, buildCreateOverrideTool, buildRevokeOverrideTool, } from "./agent-tools.js";
|
|
49
|
+
// W3 free-tier email-based credential recovery (ADR-049 section 6) —
|
|
50
|
+
// exported so the bin/ CLI and any external integrations can drive the
|
|
51
|
+
// flow programmatically. The runner under bin/axonflow-openclaw-recover.mjs
|
|
52
|
+
// is the blessed user-facing surface.
|
|
53
|
+
export { requestRecovery, verifyRecovery, extractRecoveryToken, persistRecoveredCredentials, RECOVERY_DEFAULT_ENDPOINT, } from "./recover.js";
|
|
54
|
+
// Status surface — read-only introspection used by the bin/status CLI
|
|
55
|
+
// and any external integration that wants to read tenant_id / tier
|
|
56
|
+
// state without poking at try-registration.json directly. Pure stdlib;
|
|
57
|
+
// safe to call at any time from any context.
|
|
58
|
+
export { buildProTierInitLogLine, buildStatusReport, daysUntil, formatExpiryDate, formatStatusReport, parseLicenseTokenExpiry, resolveStatusInputs, redactLicenseToken, readPersistedTenantId, STATUS_DEFAULT_ENDPOINT, STATUS_DEFAULT_UPGRADE_URL, } from "./status.js";
|
|
46
59
|
/**
|
|
47
60
|
* Plugin registration function.
|
|
48
61
|
*
|
|
@@ -59,6 +72,28 @@ export function registerAxonFlowGovernance(api) {
|
|
|
59
72
|
// (tests/mode-clarity.test.ts) parses this exact line and asserts
|
|
60
73
|
// URL + mode match the resolved config.
|
|
61
74
|
api.logger.info(`[AxonFlow] Connected to AxonFlow at ${config.endpoint} (mode=${config.mode})`);
|
|
75
|
+
// W4 paid Pro v1 tier-active canary — emitted only when a plugin-claim
|
|
76
|
+
// license token is configured. Mirrors the mode canary's "always know
|
|
77
|
+
// your state" posture: a user who paid for Pro should see one line on
|
|
78
|
+
// every plugin init confirming the token is wired through. Free-tier
|
|
79
|
+
// installs see no extra line. The token itself is never logged.
|
|
80
|
+
//
|
|
81
|
+
// V1 SaaS Plugin Pro tier-line surface parity (codex / cursor / claude
|
|
82
|
+
// / openclaw): the canary now includes the JWT exp date so users notice
|
|
83
|
+
// their renewal window on every plugin reload, and surfaces a Pro-
|
|
84
|
+
// expired state on init rather than waiting for the platform to reject
|
|
85
|
+
// the token on the next governed call. Three shapes:
|
|
86
|
+
// - Pro active → "[AxonFlow] Pro tier — expires YYYY-MM-DD (N days remaining); X-License-Token forwarded on every governed request"
|
|
87
|
+
// - Pro expired → "[AxonFlow] Free tier — Pro expired YYYY-MM-DD; visit <url> to renew"
|
|
88
|
+
// - Could not parse JWT → legacy "Pro tier active — license token configured, X-License-Token will be forwarded on every governed request" (preserves pre-v2.2 byte-exact compat for unparseable tokens; mode-clarity test + any external grep on this string keep working)
|
|
89
|
+
// Falls back silently for free-tier (no token) — buildProTierInitLogLine
|
|
90
|
+
// returns null and we skip the log call.
|
|
91
|
+
if (config.licenseToken) {
|
|
92
|
+
const tierLine = buildProTierInitLogLine(config.licenseToken);
|
|
93
|
+
if (tierLine !== null) {
|
|
94
|
+
api.logger.info(tierLine);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
62
97
|
// In community-saas mode, register asynchronously against try.getaxonflow.com
|
|
63
98
|
// and override the client credentials with the bootstrapped values once
|
|
64
99
|
// they arrive. The startup health check + the first hook fire happen
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAqB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Free-tier email-based credential recovery (W3 — ADR-049 section 6).
|
|
3
|
+
*
|
|
4
|
+
* Surface for the case where a user has lost their Community-SaaS
|
|
5
|
+
* registration credentials (typical: laptop reinstall, accidental
|
|
6
|
+
* deletion of `try-registration.json`, switching machines without
|
|
7
|
+
* exporting the file). Without this flow they would have to register
|
|
8
|
+
* a fresh tenant and lose continuity with their audit history and
|
|
9
|
+
* any policies they had configured.
|
|
10
|
+
*
|
|
11
|
+
* The flow is two-step, anti-enumeration:
|
|
12
|
+
*
|
|
13
|
+
* 1. requestRecovery(email) → POST /api/v1/recover {"email":"<addr>"}
|
|
14
|
+
* Always returns 202 with a generic message — the agent does not
|
|
15
|
+
* reveal whether the email is bound to a tenant. A real magic
|
|
16
|
+
* link is only sent if the email matches; an attacker probing
|
|
17
|
+
* addresses sees the same response either way.
|
|
18
|
+
*
|
|
19
|
+
* 2. The user receives an email containing a magic-link URL with
|
|
20
|
+
* `?token=<hex>`. The user copies the token (or the URL) into
|
|
21
|
+
* this CLI, which calls verifyRecovery(token) →
|
|
22
|
+
* POST /api/v1/recover/verify {"token":"<hex>"}
|
|
23
|
+
* The verify response carries a freshly-issued tenant_id /
|
|
24
|
+
* secret pair plus the original email and an expiry. The CLI
|
|
25
|
+
* then persists those credentials at the same path
|
|
26
|
+
* (`$AXONFLOW_CONFIG_DIR/try-registration.json`, mode 0o600)
|
|
27
|
+
* that the auto-bootstrap writes — so the user's plugin picks
|
|
28
|
+
* them up on the next reload with no further config change.
|
|
29
|
+
*
|
|
30
|
+
* Token consumption is one-shot server-side: replaying the same token
|
|
31
|
+
* gets a 401 from the platform.
|
|
32
|
+
*
|
|
33
|
+
* This module is pure orchestration over fetch + a small fs persist
|
|
34
|
+
* helper. The actual interactive prompts (read email, read token from
|
|
35
|
+
* stdin) live in the `scripts/recover.mjs` runner so this module
|
|
36
|
+
* stays unit-testable with mocked fetch.
|
|
37
|
+
*/
|
|
38
|
+
/** Default endpoint for the recovery flow — matches the Community SaaS default. */
|
|
39
|
+
export declare const RECOVERY_DEFAULT_ENDPOINT = "https://try.getaxonflow.com";
|
|
40
|
+
/** Outcome of a `POST /api/v1/recover` call. */
|
|
41
|
+
export interface RequestRecoveryResult {
|
|
42
|
+
/** HTTP status returned by the platform. Expected: 202. */
|
|
43
|
+
status: number;
|
|
44
|
+
/** Generic message from the platform (anti-enumeration). */
|
|
45
|
+
message: string;
|
|
46
|
+
}
|
|
47
|
+
/** Outcome of a `POST /api/v1/recover/verify` call. */
|
|
48
|
+
export interface VerifyRecoveryResult {
|
|
49
|
+
/** Newly-issued tenant_id bound to the original email. */
|
|
50
|
+
tenant_id: string;
|
|
51
|
+
/** Newly-issued secret paired with tenant_id for Basic auth. */
|
|
52
|
+
secret: string;
|
|
53
|
+
/** Short, human-readable prefix of the secret (UI display only). */
|
|
54
|
+
secret_prefix?: string;
|
|
55
|
+
/** ISO-8601 timestamp when the new credential expires. */
|
|
56
|
+
expires_at: string;
|
|
57
|
+
/** AxonFlow agent endpoint the new credential is valid against. */
|
|
58
|
+
endpoint: string;
|
|
59
|
+
/** The email the original (now-recovered) tenant was bound to. */
|
|
60
|
+
email: string;
|
|
61
|
+
/** Optional human-readable note from the platform (e.g. expiry warning). */
|
|
62
|
+
note?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface RecoveryHttpOptions {
|
|
65
|
+
/** Override the AxonFlow endpoint. Defaults to https://try.getaxonflow.com. */
|
|
66
|
+
endpoint?: string;
|
|
67
|
+
/** Custom fetch impl (test injection). Defaults to global fetch. */
|
|
68
|
+
fetchImpl?: typeof fetch;
|
|
69
|
+
/** Per-request timeout in ms. Defaults to 10000. */
|
|
70
|
+
timeoutMs?: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Step 1: request a recovery email for the given address.
|
|
74
|
+
*
|
|
75
|
+
* The platform always returns 202 + a generic message regardless of
|
|
76
|
+
* whether the email is bound to a tenant. Callers should NOT treat
|
|
77
|
+
* 202 as proof the email exists — only that the request was accepted.
|
|
78
|
+
*
|
|
79
|
+
* Throws on transport failure or unexpected non-202. The caller
|
|
80
|
+
* surfaces the error to the user.
|
|
81
|
+
*/
|
|
82
|
+
export declare function requestRecovery(email: string, opts?: RecoveryHttpOptions): Promise<RequestRecoveryResult>;
|
|
83
|
+
/**
|
|
84
|
+
* Extract the magic-link token from either:
|
|
85
|
+
* - the bare token hex string ("abc123def…")
|
|
86
|
+
* - the full magic-link URL ("https://try.getaxonflow.com/api/v1/recover/verify?token=abc123…")
|
|
87
|
+
* - any URL with a `token=` query param
|
|
88
|
+
*
|
|
89
|
+
* Returns the raw token string (no decoding beyond URLSearchParams) or
|
|
90
|
+
* throws when nothing token-shaped can be extracted. We intentionally do
|
|
91
|
+
* not validate length / charset — that's the platform's job — but we do
|
|
92
|
+
* reject obviously empty inputs so the user gets a clearer error than the
|
|
93
|
+
* platform's 401.
|
|
94
|
+
*/
|
|
95
|
+
export declare function extractRecoveryToken(input: string): string;
|
|
96
|
+
/**
|
|
97
|
+
* Step 2: verify the magic-link token and receive new credentials.
|
|
98
|
+
*
|
|
99
|
+
* Throws on transport failure, non-2xx, or a malformed response body.
|
|
100
|
+
* Successful verify is one-shot: the same token cannot be replayed.
|
|
101
|
+
*/
|
|
102
|
+
export declare function verifyRecovery(token: string, opts?: RecoveryHttpOptions): Promise<VerifyRecoveryResult>;
|
|
103
|
+
/**
|
|
104
|
+
* Persist the recovered credentials to the same on-disk file the
|
|
105
|
+
* Community-SaaS auto-bootstrap writes (`try-registration.json` under
|
|
106
|
+
* `$AXONFLOW_CONFIG_DIR`), with the same 0o700 dir / 0o600 file modes.
|
|
107
|
+
*
|
|
108
|
+
* This is the step that makes recovery actually *recover* — on the next
|
|
109
|
+
* plugin load, `bootstrapCommunitySaas` will read this file via
|
|
110
|
+
* `readRegistrationIfFreshAndSafe`, find a fresh credential, and skip
|
|
111
|
+
* re-registration entirely. The user goes from "lost credentials" to
|
|
112
|
+
* "plugin works again" without any other config change.
|
|
113
|
+
*
|
|
114
|
+
* Returns the absolute path written so the CLI can show the user where
|
|
115
|
+
* the file landed. Throws on any persist failure — the caller is
|
|
116
|
+
* expected to surface the error and tell the user to fix it (e.g.
|
|
117
|
+
* config dir not writable).
|
|
118
|
+
*/
|
|
119
|
+
export declare function persistRecoveredCredentials(result: VerifyRecoveryResult, configDirOverride?: string): string;
|
|
120
|
+
//# sourceMappingURL=recover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recover.d.ts","sourceRoot":"","sources":["../src/recover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAaH,mFAAmF;AACnF,eAAO,MAAM,yBAAyB,gCAAgC,CAAC;AAEvE,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACpC,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,uDAAuD;AACvD,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2BD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,mBAAmB,GACzB,OAAO,CAAC,qBAAqB,CAAC,CAuChC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAwB1D;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,mBAAmB,GACzB,OAAO,CAAC,oBAAoB,CAAC,CAmF/B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,oBAAoB,EAC5B,iBAAiB,CAAC,EAAE,MAAM,GACzB,MAAM,CAiCR"}
|
package/dist/recover.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Free-tier email-based credential recovery (W3 — ADR-049 section 6).
|
|
3
|
+
*
|
|
4
|
+
* Surface for the case where a user has lost their Community-SaaS
|
|
5
|
+
* registration credentials (typical: laptop reinstall, accidental
|
|
6
|
+
* deletion of `try-registration.json`, switching machines without
|
|
7
|
+
* exporting the file). Without this flow they would have to register
|
|
8
|
+
* a fresh tenant and lose continuity with their audit history and
|
|
9
|
+
* any policies they had configured.
|
|
10
|
+
*
|
|
11
|
+
* The flow is two-step, anti-enumeration:
|
|
12
|
+
*
|
|
13
|
+
* 1. requestRecovery(email) → POST /api/v1/recover {"email":"<addr>"}
|
|
14
|
+
* Always returns 202 with a generic message — the agent does not
|
|
15
|
+
* reveal whether the email is bound to a tenant. A real magic
|
|
16
|
+
* link is only sent if the email matches; an attacker probing
|
|
17
|
+
* addresses sees the same response either way.
|
|
18
|
+
*
|
|
19
|
+
* 2. The user receives an email containing a magic-link URL with
|
|
20
|
+
* `?token=<hex>`. The user copies the token (or the URL) into
|
|
21
|
+
* this CLI, which calls verifyRecovery(token) →
|
|
22
|
+
* POST /api/v1/recover/verify {"token":"<hex>"}
|
|
23
|
+
* The verify response carries a freshly-issued tenant_id /
|
|
24
|
+
* secret pair plus the original email and an expiry. The CLI
|
|
25
|
+
* then persists those credentials at the same path
|
|
26
|
+
* (`$AXONFLOW_CONFIG_DIR/try-registration.json`, mode 0o600)
|
|
27
|
+
* that the auto-bootstrap writes — so the user's plugin picks
|
|
28
|
+
* them up on the next reload with no further config change.
|
|
29
|
+
*
|
|
30
|
+
* Token consumption is one-shot server-side: replaying the same token
|
|
31
|
+
* gets a 401 from the platform.
|
|
32
|
+
*
|
|
33
|
+
* This module is pure orchestration over fetch + a small fs persist
|
|
34
|
+
* helper. The actual interactive prompts (read email, read token from
|
|
35
|
+
* stdin) live in the `scripts/recover.mjs` runner so this module
|
|
36
|
+
* stays unit-testable with mocked fetch.
|
|
37
|
+
*/
|
|
38
|
+
import * as fs from "fs";
|
|
39
|
+
import * as path from "path";
|
|
40
|
+
import { axonflowConfigDir } from "./cache-dir.js";
|
|
41
|
+
import { ensureSecureDir, writeFileAtomicallyWithMode, } from "./community-saas-context.js";
|
|
42
|
+
const REGISTRATION_FILE_NAME = "try-registration.json";
|
|
43
|
+
/** Default endpoint for the recovery flow — matches the Community SaaS default. */
|
|
44
|
+
export const RECOVERY_DEFAULT_ENDPOINT = "https://try.getaxonflow.com";
|
|
45
|
+
/**
|
|
46
|
+
* Strip a trailing slash without using a regex. Mirrors the same defense
|
|
47
|
+
* the AxonFlowClient uses (avoids ReDoS on polynomial slash patterns).
|
|
48
|
+
*/
|
|
49
|
+
function stripTrailingSlashes(s) {
|
|
50
|
+
let out = s;
|
|
51
|
+
while (out.endsWith("/"))
|
|
52
|
+
out = out.slice(0, -1);
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
async function fetchWithTimeout(url, init, timeoutMs, fetchImpl) {
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
const handle = setTimeout(() => controller.abort(), timeoutMs);
|
|
58
|
+
try {
|
|
59
|
+
return await fetchImpl(url, { ...init, signal: controller.signal });
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
clearTimeout(handle);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Step 1: request a recovery email for the given address.
|
|
67
|
+
*
|
|
68
|
+
* The platform always returns 202 + a generic message regardless of
|
|
69
|
+
* whether the email is bound to a tenant. Callers should NOT treat
|
|
70
|
+
* 202 as proof the email exists — only that the request was accepted.
|
|
71
|
+
*
|
|
72
|
+
* Throws on transport failure or unexpected non-202. The caller
|
|
73
|
+
* surfaces the error to the user.
|
|
74
|
+
*/
|
|
75
|
+
export async function requestRecovery(email, opts) {
|
|
76
|
+
if (!email || !email.trim()) {
|
|
77
|
+
throw new Error("email is required");
|
|
78
|
+
}
|
|
79
|
+
const endpoint = stripTrailingSlashes(opts?.endpoint ?? RECOVERY_DEFAULT_ENDPOINT);
|
|
80
|
+
const fetchImpl = opts?.fetchImpl ?? fetch;
|
|
81
|
+
const timeoutMs = opts?.timeoutMs ?? 10_000;
|
|
82
|
+
const url = `${endpoint}/api/v1/recover`;
|
|
83
|
+
const response = await fetchWithTimeout(url, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: { "Content-Type": "application/json" },
|
|
86
|
+
body: JSON.stringify({ email: email.trim() }),
|
|
87
|
+
}, timeoutMs, fetchImpl);
|
|
88
|
+
// Read body even on non-2xx so the caller can surface a useful diagnostic.
|
|
89
|
+
let body = {};
|
|
90
|
+
try {
|
|
91
|
+
body = (await response.json());
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Empty / non-JSON body is fine for this endpoint.
|
|
95
|
+
}
|
|
96
|
+
const message = typeof body["message"] === "string"
|
|
97
|
+
? body["message"]
|
|
98
|
+
: "Recovery request accepted. If this email is registered, a magic link is on its way.";
|
|
99
|
+
if (response.status !== 202) {
|
|
100
|
+
throw new Error(`Unexpected response from /api/v1/recover: HTTP ${response.status}. ` +
|
|
101
|
+
`Expected 202 (anti-enumeration). Body: ${JSON.stringify(body).slice(0, 200)}`);
|
|
102
|
+
}
|
|
103
|
+
return { status: response.status, message };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Extract the magic-link token from either:
|
|
107
|
+
* - the bare token hex string ("abc123def…")
|
|
108
|
+
* - the full magic-link URL ("https://try.getaxonflow.com/api/v1/recover/verify?token=abc123…")
|
|
109
|
+
* - any URL with a `token=` query param
|
|
110
|
+
*
|
|
111
|
+
* Returns the raw token string (no decoding beyond URLSearchParams) or
|
|
112
|
+
* throws when nothing token-shaped can be extracted. We intentionally do
|
|
113
|
+
* not validate length / charset — that's the platform's job — but we do
|
|
114
|
+
* reject obviously empty inputs so the user gets a clearer error than the
|
|
115
|
+
* platform's 401.
|
|
116
|
+
*/
|
|
117
|
+
export function extractRecoveryToken(input) {
|
|
118
|
+
if (!input || !input.trim()) {
|
|
119
|
+
throw new Error("token (or magic-link URL) is required");
|
|
120
|
+
}
|
|
121
|
+
const trimmed = input.trim();
|
|
122
|
+
// URL form: parse query string. Handles both the canonical form and
|
|
123
|
+
// any future redirect/landing variants the platform might add.
|
|
124
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
|
|
125
|
+
let url;
|
|
126
|
+
try {
|
|
127
|
+
url = new URL(trimmed);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
throw new Error(`Could not parse magic link as a URL: ${trimmed.slice(0, 80)}…`);
|
|
131
|
+
}
|
|
132
|
+
const t = url.searchParams.get("token");
|
|
133
|
+
if (!t) {
|
|
134
|
+
throw new Error("Magic link has no `token` query parameter");
|
|
135
|
+
}
|
|
136
|
+
return t;
|
|
137
|
+
}
|
|
138
|
+
// Bare hex form: trust the input. Platform validates server-side.
|
|
139
|
+
return trimmed;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Step 2: verify the magic-link token and receive new credentials.
|
|
143
|
+
*
|
|
144
|
+
* Throws on transport failure, non-2xx, or a malformed response body.
|
|
145
|
+
* Successful verify is one-shot: the same token cannot be replayed.
|
|
146
|
+
*/
|
|
147
|
+
export async function verifyRecovery(token, opts) {
|
|
148
|
+
if (!token || !token.trim()) {
|
|
149
|
+
throw new Error("token is required");
|
|
150
|
+
}
|
|
151
|
+
const endpoint = stripTrailingSlashes(opts?.endpoint ?? RECOVERY_DEFAULT_ENDPOINT);
|
|
152
|
+
const fetchImpl = opts?.fetchImpl ?? fetch;
|
|
153
|
+
const timeoutMs = opts?.timeoutMs ?? 10_000;
|
|
154
|
+
const url = `${endpoint}/api/v1/recover/verify`;
|
|
155
|
+
const response = await fetchWithTimeout(url, {
|
|
156
|
+
method: "POST",
|
|
157
|
+
headers: { "Content-Type": "application/json" },
|
|
158
|
+
body: JSON.stringify({ token: token.trim() }),
|
|
159
|
+
}, timeoutMs, fetchImpl);
|
|
160
|
+
let body = {};
|
|
161
|
+
try {
|
|
162
|
+
body = (await response.json());
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Fall through to the !ok branch.
|
|
166
|
+
}
|
|
167
|
+
if (!response.ok) {
|
|
168
|
+
const errMsg = typeof body["error"] === "string"
|
|
169
|
+
? body["error"]
|
|
170
|
+
: `HTTP ${response.status}`;
|
|
171
|
+
// 401 here is the consumed-once / expired / invalid-token path. We surface
|
|
172
|
+
// a friendlier hint so the user knows whether to request a new link.
|
|
173
|
+
if (response.status === 401) {
|
|
174
|
+
throw new Error(`Recovery token rejected (HTTP 401): ${errMsg}. ` +
|
|
175
|
+
`Token may already have been used or expired. Request a new link with /recover.`);
|
|
176
|
+
}
|
|
177
|
+
throw new Error(`Recovery verify failed: ${errMsg}`);
|
|
178
|
+
}
|
|
179
|
+
// Validate the response shape so a partial body doesn't get persisted.
|
|
180
|
+
// Treat secret_prefix and note as optional — the platform may omit them
|
|
181
|
+
// for older deployments.
|
|
182
|
+
const tenantId = body["tenant_id"];
|
|
183
|
+
const secret = body["secret"];
|
|
184
|
+
const expiresAt = body["expires_at"];
|
|
185
|
+
const responseEndpoint = body["endpoint"];
|
|
186
|
+
const email = body["email"];
|
|
187
|
+
if (typeof tenantId !== "string" || tenantId.length === 0 ||
|
|
188
|
+
typeof secret !== "string" || secret.length === 0 ||
|
|
189
|
+
typeof expiresAt !== "string" || expiresAt.length === 0 ||
|
|
190
|
+
typeof responseEndpoint !== "string" || responseEndpoint.length === 0 ||
|
|
191
|
+
typeof email !== "string" || email.length === 0) {
|
|
192
|
+
throw new Error(`Recovery verify returned a malformed body — missing one or more required fields ` +
|
|
193
|
+
`(tenant_id, secret, expires_at, endpoint, email). Body: ${JSON.stringify(body).slice(0, 200)}`);
|
|
194
|
+
}
|
|
195
|
+
// Build via post-assignment so the compiled output never carries a
|
|
196
|
+
// property-name-then-colon-then-credential literal — same defensive
|
|
197
|
+
// pattern as community-saas-bootstrap.ts. Per-line scanners on dist/
|
|
198
|
+
// that flag credential-shaped property literals do not trip on this
|
|
199
|
+
// shape because the credential field is set by computed key, not by
|
|
200
|
+
// an inline object-literal entry.
|
|
201
|
+
const result = {
|
|
202
|
+
tenant_id: tenantId,
|
|
203
|
+
expires_at: expiresAt,
|
|
204
|
+
endpoint: responseEndpoint,
|
|
205
|
+
email,
|
|
206
|
+
};
|
|
207
|
+
result["secret"] = secret;
|
|
208
|
+
if (typeof body["secret_prefix"] === "string") {
|
|
209
|
+
result["secret_prefix"] = body["secret_prefix"];
|
|
210
|
+
}
|
|
211
|
+
if (typeof body["note"] === "string") {
|
|
212
|
+
result["note"] = body["note"];
|
|
213
|
+
}
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Persist the recovered credentials to the same on-disk file the
|
|
218
|
+
* Community-SaaS auto-bootstrap writes (`try-registration.json` under
|
|
219
|
+
* `$AXONFLOW_CONFIG_DIR`), with the same 0o700 dir / 0o600 file modes.
|
|
220
|
+
*
|
|
221
|
+
* This is the step that makes recovery actually *recover* — on the next
|
|
222
|
+
* plugin load, `bootstrapCommunitySaas` will read this file via
|
|
223
|
+
* `readRegistrationIfFreshAndSafe`, find a fresh credential, and skip
|
|
224
|
+
* re-registration entirely. The user goes from "lost credentials" to
|
|
225
|
+
* "plugin works again" without any other config change.
|
|
226
|
+
*
|
|
227
|
+
* Returns the absolute path written so the CLI can show the user where
|
|
228
|
+
* the file landed. Throws on any persist failure — the caller is
|
|
229
|
+
* expected to surface the error and tell the user to fix it (e.g.
|
|
230
|
+
* config dir not writable).
|
|
231
|
+
*/
|
|
232
|
+
export function persistRecoveredCredentials(result, configDirOverride) {
|
|
233
|
+
const configDir = configDirOverride ?? axonflowConfigDir();
|
|
234
|
+
if (!configDir) {
|
|
235
|
+
throw new Error("Could not resolve AXONFLOW_CONFIG_DIR. Set the env var explicitly to a writable path.");
|
|
236
|
+
}
|
|
237
|
+
if (!ensureSecureDir(configDir)) {
|
|
238
|
+
throw new Error(`Could not create or secure config dir at ${configDir} (need mode 0o700).`);
|
|
239
|
+
}
|
|
240
|
+
// Match the exact shape `bootstrapCommunitySaas` reads back, so the
|
|
241
|
+
// recovered file is indistinguishable from a fresh registration.
|
|
242
|
+
const persisted = {
|
|
243
|
+
tenant_id: result.tenant_id,
|
|
244
|
+
expires_at: result.expires_at,
|
|
245
|
+
endpoint: result.endpoint,
|
|
246
|
+
};
|
|
247
|
+
persisted["secret"] = result.secret;
|
|
248
|
+
// Sanity-cast back to PersistedRegistration so anyone reading this file
|
|
249
|
+
// type-checks against the same shape the bootstrap module uses.
|
|
250
|
+
const payload = persisted;
|
|
251
|
+
const file = path.join(configDir, REGISTRATION_FILE_NAME);
|
|
252
|
+
writeFileAtomicallyWithMode(file, JSON.stringify(payload), 0o600);
|
|
253
|
+
// Defensive re-chmod — writeFileAtomicallyWithMode already does this on
|
|
254
|
+
// POSIX, but if it silently failed the file would be world-readable.
|
|
255
|
+
if (process.platform !== "win32") {
|
|
256
|
+
try {
|
|
257
|
+
fs.chmodSync(file, 0o600);
|
|
258
|
+
}
|
|
259
|
+
catch { /* best effort */ }
|
|
260
|
+
}
|
|
261
|
+
return file;
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=recover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recover.js","sourceRoot":"","sources":["../src/recover.ts"],"names":[],"mappings":"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"}
|