@micropage-sh/mcp 0.1.1 → 0.1.3
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/README.md +11 -0
- package/dist/client/assets.d.ts +26 -8
- package/dist/client/assets.js +54 -116
- package/dist/client/assets.js.map +1 -1
- package/dist/client/auth-provider.d.ts +9 -3
- package/dist/client/auth-provider.js +11 -0
- package/dist/client/auth-provider.js.map +1 -1
- package/dist/client/bearer-auth.d.ts +16 -0
- package/dist/client/bearer-auth.js +24 -0
- package/dist/client/bearer-auth.js.map +1 -0
- package/dist/client/deploy-token.d.ts +6 -0
- package/dist/client/deploy-token.js +17 -5
- package/dist/client/deploy-token.js.map +1 -1
- package/dist/client/errors.d.ts +9 -1
- package/dist/client/errors.js +23 -0
- package/dist/client/errors.js.map +1 -1
- package/dist/client/http.d.ts +4 -0
- package/dist/client/http.js +11 -5
- package/dist/client/http.js.map +1 -1
- package/dist/client/ip.d.ts +12 -0
- package/dist/client/ip.js +93 -0
- package/dist/client/ip.js.map +1 -0
- package/dist/client/posts.js +4 -0
- package/dist/client/posts.js.map +1 -1
- package/dist/client/session-store.d.ts +3 -2
- package/dist/client/session-store.js +5 -1
- package/dist/client/session-store.js.map +1 -1
- package/dist/client/tier.d.ts +29 -6
- package/dist/client/tier.js +62 -21
- package/dist/client/tier.js.map +1 -1
- package/dist/context.d.ts +43 -7
- package/dist/guards.d.ts +11 -10
- package/dist/guards.js +21 -19
- package/dist/guards.js.map +1 -1
- package/dist/hints.d.ts +46 -0
- package/dist/hints.js +70 -0
- package/dist/hints.js.map +1 -0
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/node/deps.d.ts +26 -0
- package/dist/node/deps.js +51 -0
- package/dist/node/deps.js.map +1 -0
- package/dist/node/host-lookup.d.ts +3 -0
- package/dist/node/host-lookup.js +4 -0
- package/dist/node/host-lookup.js.map +1 -0
- package/dist/node/path-source.d.ts +3 -0
- package/dist/node/path-source.js +28 -0
- package/dist/node/path-source.js.map +1 -0
- package/dist/reference/prompts.d.ts +2 -1
- package/dist/reference/prompts.js +4 -3
- package/dist/reference/prompts.js.map +1 -1
- package/dist/reference.d.ts +1 -1
- package/dist/reference.js +2 -2
- package/dist/reference.js.map +1 -1
- package/dist/server.d.ts +4 -19
- package/dist/server.js +27 -33
- package/dist/server.js.map +1 -1
- package/dist/tools/account.d.ts +3 -2
- package/dist/tools/account.js +8 -8
- package/dist/tools/account.js.map +1 -1
- package/dist/tools/builds.d.ts +2 -2
- package/dist/tools/builds.js +56 -16
- package/dist/tools/builds.js.map +1 -1
- package/dist/tools/files.d.ts +15 -6
- package/dist/tools/files.js +63 -45
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/forms.js +1 -1
- package/dist/tools/forms.js.map +1 -1
- package/dist/tools/posts.d.ts +2 -3
- package/dist/tools/posts.js +15 -16
- package/dist/tools/posts.js.map +1 -1
- package/dist/tools/projects.js +6 -2
- package/dist/tools/projects.js.map +1 -1
- package/dist/tools/shared.d.ts +1 -1
- package/dist/tools/shared.js +1 -1
- package/dist/tools/shared.js.map +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +6 -7
- package/dist/version.js.map +1 -1
- package/package.json +6 -3
package/dist/client/tier.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { currentUserId } from "./auth-provider.js";
|
|
2
|
+
import { MicropageError, PRICING_URL } from "./errors.js";
|
|
2
3
|
import { eq } from "./http.js";
|
|
3
|
-
|
|
4
|
-
export const PRICING_URL = "https://micropage.sh/pricing";
|
|
4
|
+
export { PRICING_URL };
|
|
5
5
|
/** Same wording as the CLI (cli/src/plan.js), addressed to the model. */
|
|
6
6
|
export const UPGRADE_MESSAGE = "The micropage MCP server, like the micropage CLI, is available on paid plans only. " +
|
|
7
7
|
`This account is on the free plan. Tell the user they can upgrade at ${PRICING_URL}, then retry.`;
|
|
@@ -9,6 +9,43 @@ export const PLAN_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
|
9
9
|
export function isPaidTier(tier) {
|
|
10
10
|
return tier === "pro" || tier === "pro_plus";
|
|
11
11
|
}
|
|
12
|
+
/** Bound on cached users; past it, expired entries are dropped before adding one. */
|
|
13
|
+
export const PLAN_CACHE_MAX_USERS = 1000;
|
|
14
|
+
/**
|
|
15
|
+
* Tier lookups keyed by user id. A PlanGate owns one by default; the remote
|
|
16
|
+
* server builds a gate per request and passes one long-lived cache to all of
|
|
17
|
+
* them, so the cache outlives the request without sharing anything else.
|
|
18
|
+
*/
|
|
19
|
+
export class PlanTierCache {
|
|
20
|
+
entries = new Map();
|
|
21
|
+
inflight = new Map();
|
|
22
|
+
get(userId, now, ttlMs) {
|
|
23
|
+
const hit = this.entries.get(userId);
|
|
24
|
+
return hit && now - hit.at < ttlMs ? hit.tier : null;
|
|
25
|
+
}
|
|
26
|
+
set(userId, tier, now, ttlMs) {
|
|
27
|
+
if (this.entries.size >= PLAN_CACHE_MAX_USERS && !this.entries.has(userId)) {
|
|
28
|
+
for (const [id, entry] of this.entries) {
|
|
29
|
+
if (now - entry.at >= ttlMs)
|
|
30
|
+
this.entries.delete(id);
|
|
31
|
+
}
|
|
32
|
+
// Still full of live entries: drop the oldest insertion.
|
|
33
|
+
if (this.entries.size >= PLAN_CACHE_MAX_USERS) {
|
|
34
|
+
const oldest = this.entries.keys().next();
|
|
35
|
+
if (!oldest.done)
|
|
36
|
+
this.entries.delete(oldest.value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
this.entries.delete(userId);
|
|
40
|
+
this.entries.set(userId, { tier, at: now });
|
|
41
|
+
}
|
|
42
|
+
get size() {
|
|
43
|
+
return this.entries.size;
|
|
44
|
+
}
|
|
45
|
+
clear() {
|
|
46
|
+
this.entries.clear();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
12
49
|
/**
|
|
13
50
|
* The CLI's client-side Pro gate: reads customers.plan_tier under RLS and
|
|
14
51
|
* caches it for 5 minutes per user. A product gate, not a security boundary;
|
|
@@ -19,21 +56,19 @@ export class PlanGate {
|
|
|
19
56
|
auth;
|
|
20
57
|
now;
|
|
21
58
|
ttlMs;
|
|
22
|
-
cache
|
|
23
|
-
|
|
59
|
+
cache;
|
|
60
|
+
hints;
|
|
24
61
|
constructor(options) {
|
|
25
62
|
this.http = options.http;
|
|
26
63
|
this.auth = options.auth;
|
|
27
64
|
this.now = options.now ?? Date.now;
|
|
28
65
|
this.ttlMs = options.ttlMs ?? PLAN_CACHE_TTL_MS;
|
|
66
|
+
this.cache = options.cache ?? new PlanTierCache();
|
|
67
|
+
this.hints = options.hints;
|
|
29
68
|
}
|
|
30
69
|
/** The signed-in user's id, read from the access token's `sub`. */
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (typeof sub !== "string" || !sub) {
|
|
34
|
-
throw new MicropageError("SESSION_EXPIRED", "The micropage access token has no user id. Run `micropage login` in a terminal, then retry.");
|
|
35
|
-
}
|
|
36
|
-
return sub;
|
|
70
|
+
currentUserId() {
|
|
71
|
+
return currentUserId(this.auth, this.hints);
|
|
37
72
|
}
|
|
38
73
|
/**
|
|
39
74
|
* Missing customer row means free, as in the CLI. A failed lookup is not
|
|
@@ -41,26 +76,32 @@ export class PlanGate {
|
|
|
41
76
|
*/
|
|
42
77
|
async getPlanTier() {
|
|
43
78
|
const userId = await this.currentUserId();
|
|
44
|
-
const hit = this.cache;
|
|
45
|
-
if (hit
|
|
46
|
-
return hit
|
|
47
|
-
this.inflight
|
|
79
|
+
const hit = this.cache.get(userId, this.now(), this.ttlMs);
|
|
80
|
+
if (hit)
|
|
81
|
+
return hit;
|
|
82
|
+
const pending = this.cache.inflight.get(userId);
|
|
83
|
+
if (pending)
|
|
84
|
+
return pending;
|
|
85
|
+
const lookup = (async () => {
|
|
48
86
|
const row = await this.http.selectOne("customers", {
|
|
49
87
|
select: "plan_tier",
|
|
50
88
|
filters: { user_id: eq(userId) },
|
|
51
89
|
});
|
|
52
90
|
const tier = isPaidTier(row?.plan_tier) ? row.plan_tier : "free";
|
|
53
|
-
this.cache
|
|
91
|
+
this.cache.set(userId, tier, this.now(), this.ttlMs);
|
|
54
92
|
return tier;
|
|
55
93
|
})().finally(() => {
|
|
56
|
-
this.inflight
|
|
94
|
+
this.cache.inflight.delete(userId);
|
|
57
95
|
});
|
|
58
|
-
|
|
96
|
+
this.cache.inflight.set(userId, lookup);
|
|
97
|
+
return lookup;
|
|
59
98
|
}
|
|
60
99
|
/**
|
|
61
100
|
* Throws PLAN_REQUIRED unless the account is pro or pro_plus. Deploy-token
|
|
62
|
-
* mode skips the lookup: deploy
|
|
63
|
-
*
|
|
101
|
+
* mode skips the lookup: exchange-deploy-token refuses the exchange with
|
|
102
|
+
* `plan_required` unless the token owner is Pro+ at that moment, so a
|
|
103
|
+
* working deploy-token session already implies a paid plan (and a downgrade
|
|
104
|
+
* takes effect at the next exchange).
|
|
64
105
|
*/
|
|
65
106
|
async requirePaidPlan() {
|
|
66
107
|
if (this.auth.mode === "deploy_token")
|
|
@@ -70,7 +111,7 @@ export class PlanGate {
|
|
|
70
111
|
throw new MicropageError("PLAN_REQUIRED", UPGRADE_MESSAGE);
|
|
71
112
|
}
|
|
72
113
|
clearCache() {
|
|
73
|
-
this.cache
|
|
114
|
+
this.cache.clear();
|
|
74
115
|
}
|
|
75
116
|
}
|
|
76
117
|
//# sourceMappingURL=tier.js.map
|
package/dist/client/tier.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tier.js","sourceRoot":"","sources":["../../src/client/tier.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"tier.js","sourceRoot":"","sources":["../../src/client/tier.ts"],"names":[],"mappings":"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"}
|
package/dist/context.d.ts
CHANGED
|
@@ -1,28 +1,64 @@
|
|
|
1
1
|
import type { ClientCapabilities, ProtocolEra, ServerContext } from "@modelcontextprotocol/server";
|
|
2
|
+
import type { HostDenylist, HostLookup, PathLoader } from "./client/assets.js";
|
|
2
3
|
import type { AuthProvider } from "./client/auth-provider.js";
|
|
3
4
|
import type { MicropageConfig } from "./client/config.js";
|
|
4
|
-
import type { Http } from "./client/http.js";
|
|
5
|
+
import type { FetchLike, Http } from "./client/http.js";
|
|
5
6
|
import type { PlanGate } from "./client/tier.js";
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
import type { ConfirmationTokens } from "./guards.js";
|
|
8
|
+
import type { ModeHints } from "./hints.js";
|
|
9
|
+
/**
|
|
10
|
+
* What the user allowed this connection to do. Each defaults off. Stdio reads
|
|
11
|
+
* them from env switches the user sets in their MCP config; the remote server
|
|
12
|
+
* reads the per-connection row the user set on the consent page.
|
|
13
|
+
*/
|
|
14
|
+
export interface Permissions {
|
|
8
15
|
/** MICROPAGE_MCP_ALLOW_SEND: publish_post may email the subscriber list. */
|
|
9
16
|
allowSend: boolean;
|
|
10
17
|
/** MICROPAGE_MCP_ALLOW_DELETE: delete_project is registered at all. */
|
|
11
18
|
allowDelete: boolean;
|
|
12
19
|
/** MICROPAGE_MCP_SUBMISSIONS: form submission (PII) tools are registered. */
|
|
13
|
-
|
|
20
|
+
allowSubmissions: boolean;
|
|
14
21
|
}
|
|
15
|
-
/**
|
|
22
|
+
/** Where upload_asset may read bytes from; differs between a local and a hosted server. */
|
|
23
|
+
export interface UploadDeps {
|
|
24
|
+
/** Reads `{path}` sources. Absent on a hosted server, which then does not offer `{path}` at all. */
|
|
25
|
+
pathLoader?: PathLoader;
|
|
26
|
+
/**
|
|
27
|
+
* Resolves `{url}` hostnames so private addresses are refused before the
|
|
28
|
+
* fetch. Null only where the runtime's fetch cannot reach private networks
|
|
29
|
+
* anyway; IP-literal hosts and the denylist are checked either way.
|
|
30
|
+
*/
|
|
31
|
+
lookupHost: HostLookup | null;
|
|
32
|
+
/** Hostnames `{url}` must never fetch (our own infrastructure on a hosted server). */
|
|
33
|
+
deniedHosts?: HostDenylist;
|
|
34
|
+
/** fetch for `{url}` sources; never the micropage-authenticated client. Defaults to global fetch. */
|
|
35
|
+
fetchExternal?: FetchLike;
|
|
36
|
+
/** Largest asset upload_asset accepts, in bytes; also what its description states. Defaults to MAX_ASSET_BYTES. */
|
|
37
|
+
maxBytes?: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Dependencies for serving one user. Stdio builds them once per process;
|
|
41
|
+
* the remote server builds them per request (with long-lived pieces such as
|
|
42
|
+
* the plan-tier cache and the token key passed in).
|
|
43
|
+
*/
|
|
16
44
|
export interface ServerDeps {
|
|
17
45
|
config: MicropageConfig;
|
|
18
46
|
auth: AuthProvider;
|
|
19
47
|
http: Http;
|
|
20
|
-
/** Paid-plan gate with its 5-minute plan_tier cache; call through gateTool() in tools. */
|
|
48
|
+
/** Paid-plan gate with its 5-minute per-user plan_tier cache; call through gateTool() in tools. */
|
|
21
49
|
tier: PlanGate;
|
|
22
|
-
|
|
50
|
+
permissions: Permissions;
|
|
51
|
+
/** Signs preview_post_send tokens; its key decides which servers accept them. */
|
|
52
|
+
confirmationTokens: ConfirmationTokens;
|
|
53
|
+
uploads: UploadDeps;
|
|
54
|
+
/** Wording that names how the user changes a setting or fixes a login. Defaults to the stdio wording. */
|
|
55
|
+
hints?: ModeHints;
|
|
56
|
+
/** Called with each error a tool handler throws, before the SDK turns it into an isError result (logging). */
|
|
57
|
+
onToolError?: (tool: string, error: unknown) => void;
|
|
23
58
|
}
|
|
24
59
|
/** What every register* function receives: the deps plus per-instance protocol facts. */
|
|
25
60
|
export interface ToolContext extends ServerDeps {
|
|
61
|
+
hints: ModeHints;
|
|
26
62
|
/** Protocol era this server instance serves (fixed per instance by the factory). */
|
|
27
63
|
era: ProtocolEra;
|
|
28
64
|
/** The calling client's declared capabilities for this request, era-correct. */
|
package/dist/guards.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ClientCapabilities, type InputRequiredResult, type ServerContext } from "@modelcontextprotocol/server";
|
|
2
2
|
import type { AuthProvider } from "./client/auth-provider.js";
|
|
3
|
-
import type {
|
|
4
|
-
export declare function
|
|
3
|
+
import type { Permissions } from "./context.js";
|
|
4
|
+
export declare function envPermissions(env?: Readonly<Record<string, string | undefined>>): Permissions;
|
|
5
|
+
export declare const NO_PERMISSIONS: Readonly<Permissions>;
|
|
5
6
|
export declare function requireConfirm(args: {
|
|
6
7
|
confirm?: boolean | undefined;
|
|
7
8
|
}, action: string): void;
|
|
@@ -15,20 +16,20 @@ export type TokenCheck = {
|
|
|
15
16
|
reason: "malformed" | "expired" | "mismatch";
|
|
16
17
|
};
|
|
17
18
|
export declare const DEFAULT_TOKEN_TTL_MS: number;
|
|
19
|
+
/** HMAC key: random bytes per stdio process, a Worker secret remotely. */
|
|
20
|
+
export type TokenKey = Uint8Array | string;
|
|
18
21
|
export declare class ConfirmationTokens {
|
|
19
22
|
private readonly key;
|
|
20
23
|
private readonly now;
|
|
21
|
-
constructor(options
|
|
22
|
-
key
|
|
24
|
+
constructor(options: {
|
|
25
|
+
key: TokenKey;
|
|
23
26
|
now?: () => number;
|
|
24
27
|
});
|
|
25
|
-
mint(payload: TokenPayload, ttlMs?: number): string;
|
|
26
|
-
verify(token: string, payload: TokenPayload): TokenCheck;
|
|
28
|
+
mint(sub: string, payload: TokenPayload, ttlMs?: number): string;
|
|
29
|
+
verify(token: string, sub: string, payload: TokenPayload): TokenCheck;
|
|
27
30
|
private sign;
|
|
28
31
|
}
|
|
29
|
-
|
|
30
|
-
export declare const confirmationTokens: ConfirmationTokens;
|
|
31
|
-
export declare function requireConfirmationToken(tokens: ConfirmationTokens, token: string | undefined, payload: TokenPayload, previewTool: string): void;
|
|
32
|
+
export declare function requireConfirmationToken(tokens: ConfirmationTokens, token: string | undefined, sub: string, payload: TokenPayload, previewTool: string): void;
|
|
32
33
|
/** Stable JSON: object keys sorted at every depth, so equal payloads sign equally. */
|
|
33
34
|
export declare function canonicalJson(value: unknown): string;
|
|
34
35
|
export type ElicitOutcome = {
|
|
@@ -52,4 +53,4 @@ export interface ConfirmElicitation {
|
|
|
52
53
|
export declare function supportsFormElicitation(caps: ClientCapabilities | undefined): boolean;
|
|
53
54
|
export declare function elicitConfirmation(handlerCtx: ServerContext, caps: ClientCapabilities | undefined, request: ConfirmElicitation): ElicitOutcome;
|
|
54
55
|
export declare const DEPLOY_TOKEN_TOOLS: ReadonlySet<string>;
|
|
55
|
-
export declare function assertDeployTokenAllows(auth: Pick<AuthProvider, "mode" | "pinnedProjectUuid">, tool: string, projectUuid?: string): void;
|
|
56
|
+
export declare function assertDeployTokenAllows(auth: Pick<AuthProvider, "mode" | "pinnedProjectUuid">, tool: string, projectUuid?: string, elsewhere?: string): void;
|
package/dist/guards.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { createHmac,
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { inputRequired, inputResponse, } from "@modelcontextprotocol/server";
|
|
3
3
|
import { MicropageError } from "./client/errors.js";
|
|
4
|
+
import { STDIO_HINTS } from "./hints.js";
|
|
4
5
|
// ---------------------------------------------------------------------------
|
|
5
|
-
// Env switches
|
|
6
|
+
// Env switches (stdio's source of Permissions)
|
|
6
7
|
// ---------------------------------------------------------------------------
|
|
7
8
|
const truthy = (v) => /^(1|true|yes|on)$/i.test(v?.trim() ?? "");
|
|
8
|
-
export function
|
|
9
|
+
export function envPermissions(env = process.env) {
|
|
9
10
|
return {
|
|
10
11
|
allowSend: truthy(env.MICROPAGE_MCP_ALLOW_SEND),
|
|
11
12
|
allowDelete: truthy(env.MICROPAGE_MCP_ALLOW_DELETE),
|
|
12
|
-
|
|
13
|
+
allowSubmissions: truthy(env.MICROPAGE_MCP_SUBMISSIONS),
|
|
13
14
|
};
|
|
14
15
|
}
|
|
16
|
+
export const NO_PERMISSIONS = Object.freeze({ allowSend: false, allowDelete: false, allowSubmissions: false });
|
|
15
17
|
// ---------------------------------------------------------------------------
|
|
16
18
|
// Confirm arguments
|
|
17
19
|
//
|
|
@@ -36,15 +38,17 @@ export const DEFAULT_TOKEN_TTL_MS = 15 * 60 * 1000;
|
|
|
36
38
|
export class ConfirmationTokens {
|
|
37
39
|
key;
|
|
38
40
|
now;
|
|
39
|
-
constructor(options
|
|
40
|
-
|
|
41
|
+
constructor(options) {
|
|
42
|
+
if (options.key.length < 32)
|
|
43
|
+
throw new Error("ConfirmationTokens needs a key of at least 32 bytes.");
|
|
44
|
+
this.key = options.key;
|
|
41
45
|
this.now = options.now ?? Date.now;
|
|
42
46
|
}
|
|
43
|
-
mint(payload, ttlMs = DEFAULT_TOKEN_TTL_MS) {
|
|
47
|
+
mint(sub, payload, ttlMs = DEFAULT_TOKEN_TTL_MS) {
|
|
44
48
|
const expiresAt = this.now() + ttlMs;
|
|
45
|
-
return `${expiresAt.toString(36)}.${this.sign(expiresAt, payload)}`;
|
|
49
|
+
return `${expiresAt.toString(36)}.${this.sign(expiresAt, sub, payload)}`;
|
|
46
50
|
}
|
|
47
|
-
verify(token, payload) {
|
|
51
|
+
verify(token, sub, payload) {
|
|
48
52
|
const match = /^([0-9a-z]+)\.([A-Za-z0-9_-]+)$/.exec(token.trim());
|
|
49
53
|
if (!match)
|
|
50
54
|
return { ok: false, reason: "malformed" };
|
|
@@ -56,7 +60,7 @@ export class ConfirmationTokens {
|
|
|
56
60
|
// strings can decode to the same bytes; only accept the canonical one.
|
|
57
61
|
if (given.toString("base64url") !== match[2])
|
|
58
62
|
return { ok: false, reason: "mismatch" };
|
|
59
|
-
const expected = Buffer.from(this.sign(expiresAt, payload), "base64url");
|
|
63
|
+
const expected = Buffer.from(this.sign(expiresAt, sub, payload), "base64url");
|
|
60
64
|
// Signature is checked before expiry so a forged timestamp reads as a
|
|
61
65
|
// mismatch rather than leaking which part was wrong.
|
|
62
66
|
if (given.length !== expected.length || !timingSafeEqual(given, expected)) {
|
|
@@ -66,16 +70,14 @@ export class ConfirmationTokens {
|
|
|
66
70
|
return { ok: false, reason: "expired" };
|
|
67
71
|
return { ok: true };
|
|
68
72
|
}
|
|
69
|
-
sign(expiresAt, payload) {
|
|
73
|
+
sign(expiresAt, sub, payload) {
|
|
70
74
|
return createHmac("sha256", this.key)
|
|
71
|
-
.update(`${expiresAt}\n${canonicalJson(payload)}`)
|
|
75
|
+
.update(`${expiresAt}\n${canonicalJson({ sub, payload })}`)
|
|
72
76
|
.digest("base64url");
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
export function requireConfirmationToken(tokens, token, payload, previewTool) {
|
|
78
|
-
const check = token ? tokens.verify(token, payload) : { ok: false, reason: "malformed" };
|
|
79
|
+
export function requireConfirmationToken(tokens, token, sub, payload, previewTool) {
|
|
80
|
+
const check = token ? tokens.verify(token, sub, payload) : { ok: false, reason: "malformed" };
|
|
79
81
|
if (check.ok)
|
|
80
82
|
return;
|
|
81
83
|
const why = !token
|
|
@@ -83,7 +85,7 @@ export function requireConfirmationToken(tokens, token, payload, previewTool) {
|
|
|
83
85
|
: check.reason === "expired"
|
|
84
86
|
? "The confirmation_token has expired."
|
|
85
87
|
: check.reason === "mismatch"
|
|
86
|
-
? "The confirmation_token does not match the current state (it changed since the preview, or the token came from another session)."
|
|
88
|
+
? "The confirmation_token does not match the current state (it changed since the preview, or the token came from another session or account)."
|
|
87
89
|
: "The confirmation_token is not one this server issued.";
|
|
88
90
|
throw new MicropageError("CONFIRM_INVALID", `${why} Call ${previewTool} again, show the user what it reports, and pass its new confirmation_token. Nothing was changed.`);
|
|
89
91
|
}
|
|
@@ -153,12 +155,12 @@ export const DEPLOY_TOKEN_TOOLS = new Set([
|
|
|
153
155
|
"list_builds",
|
|
154
156
|
"list_files",
|
|
155
157
|
]);
|
|
156
|
-
export function assertDeployTokenAllows(auth, tool, projectUuid) {
|
|
158
|
+
export function assertDeployTokenAllows(auth, tool, projectUuid, elsewhere = STDIO_HINTS.deployTokenElsewhere) {
|
|
157
159
|
if (auth.mode !== "deploy_token")
|
|
158
160
|
return;
|
|
159
161
|
if (!DEPLOY_TOKEN_TOOLS.has(tool)) {
|
|
160
162
|
throw new MicropageError("NOT_ALLOWED_IN_DEPLOY_TOKEN_MODE", `${tool} is not available with a deploy token. This server is limited to: ` +
|
|
161
|
-
`${[...DEPLOY_TOKEN_TOOLS].join(", ")}.
|
|
163
|
+
`${[...DEPLOY_TOKEN_TOOLS].join(", ")}. ${elsewhere}`);
|
|
162
164
|
}
|
|
163
165
|
if (projectUuid !== undefined && projectUuid !== auth.pinnedProjectUuid) {
|
|
164
166
|
throw new MicropageError("NOT_ALLOWED_IN_DEPLOY_TOKEN_MODE", `This deploy token is pinned to project ${auth.pinnedProjectUuid ?? "(unset)"}; ` +
|
package/dist/guards.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"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"}
|
package/dist/hints.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing wording that names how the user changes a setting or fixes a
|
|
3
|
+
* login. The stdio server points at env switches and `micropage login`; a
|
|
4
|
+
* hosted connection has neither, so it points at the micropage account page
|
|
5
|
+
* or the MCP client's reconnect instead.
|
|
6
|
+
*/
|
|
7
|
+
export interface ModeHints {
|
|
8
|
+
/** Completes "...whether this server is allowed to send email (<here>)." */
|
|
9
|
+
sendSwitchName: string;
|
|
10
|
+
/** Completes "...refused unless <here>;". */
|
|
11
|
+
sendEnabledBy: string;
|
|
12
|
+
/** Output field description of preview_post_send's send_allowed. */
|
|
13
|
+
sendAllowedField: string;
|
|
14
|
+
/** Why an emailing post was refused, and what the user can do about it. */
|
|
15
|
+
sendDisabled: string;
|
|
16
|
+
/** Last sentence of delete_project's description. */
|
|
17
|
+
deleteAvailable: string;
|
|
18
|
+
/** write_post prompt: the line about emailing subscribers. */
|
|
19
|
+
promptSendRule: string;
|
|
20
|
+
/** review_submissions prompt: the line about list_submissions being absent. */
|
|
21
|
+
promptSubmissionsRule: string;
|
|
22
|
+
/** whoami description: which kinds of credentials it reports. */
|
|
23
|
+
whoamiModes: string;
|
|
24
|
+
/** whoami description: what the note usually tells the user to do. */
|
|
25
|
+
whoamiFix: string;
|
|
26
|
+
/** whoami note when the token is rejected by the API. */
|
|
27
|
+
loginInvalid: string;
|
|
28
|
+
/** Appended to the deploy-token refusal: where the other tools are. */
|
|
29
|
+
deployTokenElsewhere: string;
|
|
30
|
+
/** Error when the API answers 401 even after a forced token refresh. */
|
|
31
|
+
sessionInvalid: string;
|
|
32
|
+
/** Error when the access token carries no user id. */
|
|
33
|
+
tokenNoUser: string;
|
|
34
|
+
/** Follows "The deploy token was rejected (<detail>)." on a refused exchange. */
|
|
35
|
+
deployTokenCheck: string;
|
|
36
|
+
/** Follows "No project with uuid <uuid> exists (<detail>)." on a refused exchange. */
|
|
37
|
+
deployProjectCheck: string;
|
|
38
|
+
/** upload_asset description: which source to prefer; empty when there is no preference. */
|
|
39
|
+
uploadSourceNote: string;
|
|
40
|
+
}
|
|
41
|
+
export declare const STDIO_HINTS: ModeHints;
|
|
42
|
+
export declare const CONNECTED_APPS_URL = "https://app.micropage.sh/account/connected-apps";
|
|
43
|
+
/** A hosted connection authorized through OAuth: permissions live on the user's Connected AI apps page. */
|
|
44
|
+
export declare const REMOTE_OAUTH_HINTS: ModeHints;
|
|
45
|
+
/** A hosted connection on a project deploy token: no account-level settings apply. */
|
|
46
|
+
export declare const REMOTE_DEPLOY_TOKEN_HINTS: ModeHints;
|
package/dist/hints.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export const STDIO_HINTS = Object.freeze({
|
|
2
|
+
sendSwitchName: "MICROPAGE_MCP_ALLOW_SEND",
|
|
3
|
+
sendEnabledBy: "the user has set MICROPAGE_MCP_ALLOW_SEND=1 in this server's config",
|
|
4
|
+
sendAllowedField: "MICROPAGE_MCP_ALLOW_SEND is set, so this server may email subscribers.",
|
|
5
|
+
sendDisabled: "Emailing from the MCP server is turned off. The user can turn it on by adding MICROPAGE_MCP_ALLOW_SEND=1 to this server's env in their MCP client config " +
|
|
6
|
+
"and restarting it, or publish from the micropage editor or with `micropage posts publish`. To publish on the web only, save the post with email: false " +
|
|
7
|
+
"(upsert_post), then call preview_post_send again.",
|
|
8
|
+
deleteAvailable: "Available only because MICROPAGE_MCP_ALLOW_DELETE is set.",
|
|
9
|
+
promptSendRule: "- Emailing subscribers needs MICROPAGE_MCP_ALLOW_SEND=1 in my MCP server config. If publish_post refuses to send because it is off, tell me; do not try to work around it.",
|
|
10
|
+
promptSubmissionsRule: "If list_submissions is not available, submission access is off: it needs MICROPAGE_MCP_SUBMISSIONS=1 in my MCP server config. Tell me that rather than looking for another way in.",
|
|
11
|
+
whoamiModes: "whether it runs on the user's `micropage login` session or on a project deploy token (and if so, which project it is pinned to)",
|
|
12
|
+
whoamiFix: "usually run `micropage login` in a terminal",
|
|
13
|
+
loginInvalid: "The micropage login session is no longer valid. Run `micropage login` in a terminal, then retry.",
|
|
14
|
+
deployTokenElsewhere: "Use a full `micropage login` session for anything else.",
|
|
15
|
+
sessionInvalid: "The micropage session is no longer valid. Ask the user to run `micropage login` in a terminal, then retry.",
|
|
16
|
+
tokenNoUser: "The micropage access token has no user id. Run `micropage login` in a terminal, then retry.",
|
|
17
|
+
deployTokenCheck: "Ask the user to check MICROPAGE_DEPLOY_TOKEN, or to create a new token in the micropage editor under Settings > Deploy tokens.",
|
|
18
|
+
deployProjectCheck: "Ask the user to check MICROPAGE_DEPLOY_PROJECT.",
|
|
19
|
+
uploadSourceNote: "",
|
|
20
|
+
});
|
|
21
|
+
export const CONNECTED_APPS_URL = "https://app.micropage.sh/account/connected-apps";
|
|
22
|
+
const CONNECTED_APPS = `Micropage → Connected AI apps (${CONNECTED_APPS_URL})`;
|
|
23
|
+
const RECONNECT = "Ask the user to reconnect (re-authenticate) the micropage connector in their AI app, then retry.";
|
|
24
|
+
const CHECK_CONNECTOR = "Ask the user to check the deploy token and the X-Micropage-Project header in the connector settings, then retry.";
|
|
25
|
+
const REMOTE_DEPLOY_TOKEN_CHECK = "Ask the user to check the deploy token in the AI app's connector settings, or to create a new token in the micropage editor under Settings > Deploy tokens.";
|
|
26
|
+
const REMOTE_DEPLOY_PROJECT_CHECK = "Ask the user to check the X-Micropage-Project header in the AI app's connector settings.";
|
|
27
|
+
// Base64 travels through the model's context and the request body, which is
|
|
28
|
+
// capped well below what a fetched URL may be.
|
|
29
|
+
const REMOTE_UPLOAD_SOURCE_NOTE = "Prefer source.url whenever the image is on a public https host; use source.base64 only for an image that is not hosted anywhere.";
|
|
30
|
+
/** A hosted connection authorized through OAuth: permissions live on the user's Connected AI apps page. */
|
|
31
|
+
export const REMOTE_OAUTH_HINTS = Object.freeze({
|
|
32
|
+
sendSwitchName: "the 'Let it send newsletter emails' setting for this app",
|
|
33
|
+
sendEnabledBy: `the user has turned on 'Let it send newsletter emails' for this app in ${CONNECTED_APPS}`,
|
|
34
|
+
sendAllowedField: "The user turned on 'Let it send newsletter emails' for this app, so it may email subscribers.",
|
|
35
|
+
sendDisabled: `Emailing from this app is turned off. The user can turn on 'Let it send newsletter emails' for this app in ${CONNECTED_APPS}, ` +
|
|
36
|
+
"or publish from the micropage editor. To publish on the web only, save the post with email: false (upsert_post), then call preview_post_send again.",
|
|
37
|
+
deleteAvailable: `Available only because the user turned on 'Let it delete projects' for this app in ${CONNECTED_APPS}.`,
|
|
38
|
+
promptSendRule: `- Emailing subscribers needs 'Let it send newsletter emails' turned on for this app in ${CONNECTED_APPS}. If publish_post refuses to send because it is off, tell me; do not try to work around it.`,
|
|
39
|
+
promptSubmissionsRule: `If list_submissions is not available, submission access is off: it needs 'Let it read form submissions' turned on for this app in ${CONNECTED_APPS}. Tell me that rather than looking for another way in.`,
|
|
40
|
+
whoamiModes: "whether it runs on the user's connected-app authorization (OAuth) or on a project deploy token (and if so, which project it is pinned to)",
|
|
41
|
+
whoamiFix: "usually reconnect the micropage connector in their AI app",
|
|
42
|
+
loginInvalid: `The micropage authorization for this connection is no longer valid. ${RECONNECT}`,
|
|
43
|
+
deployTokenElsewhere: "Connect micropage to the AI app with the user's micropage account for anything else.",
|
|
44
|
+
sessionInvalid: `The micropage authorization for this connection is no longer valid. ${RECONNECT}`,
|
|
45
|
+
tokenNoUser: `The micropage authorization for this connection has no user id. ${RECONNECT}`,
|
|
46
|
+
deployTokenCheck: REMOTE_DEPLOY_TOKEN_CHECK,
|
|
47
|
+
deployProjectCheck: REMOTE_DEPLOY_PROJECT_CHECK,
|
|
48
|
+
uploadSourceNote: REMOTE_UPLOAD_SOURCE_NOTE,
|
|
49
|
+
});
|
|
50
|
+
/** A hosted connection on a project deploy token: no account-level settings apply. */
|
|
51
|
+
export const REMOTE_DEPLOY_TOKEN_HINTS = Object.freeze({
|
|
52
|
+
sendSwitchName: "not available with a deploy token",
|
|
53
|
+
sendEnabledBy: "the connection uses the user's micropage account (emailing is not available with a deploy token)",
|
|
54
|
+
sendAllowedField: "Always false with a deploy token: emailing is not available with a deploy token.",
|
|
55
|
+
sendDisabled: "Emailing subscribers is not available with a deploy token. The user can publish from the micropage editor. To publish on the web only, " +
|
|
56
|
+
"save the post with email: false (upsert_post), then call preview_post_send again.",
|
|
57
|
+
deleteAvailable: "Deleting projects is not available with a deploy token.",
|
|
58
|
+
promptSendRule: "- Emailing subscribers is not available with a deploy token. If publish_post refuses to send, tell me; do not try to work around it.",
|
|
59
|
+
promptSubmissionsRule: "If list_submissions is not available, that is because reading form submissions is not available with a deploy token. Tell me that rather than looking for another way in.",
|
|
60
|
+
whoamiModes: "whether it runs on the user's connected-app authorization (OAuth) or on a project deploy token (and if so, which project it is pinned to)",
|
|
61
|
+
whoamiFix: "usually check the deploy token and the X-Micropage-Project header in the AI app's connector settings",
|
|
62
|
+
loginInvalid: `The deploy token was rejected. ${CHECK_CONNECTOR}`,
|
|
63
|
+
deployTokenElsewhere: "Connect micropage to the AI app with the user's micropage account for anything else.",
|
|
64
|
+
sessionInvalid: `The deploy-token session is no longer valid. ${CHECK_CONNECTOR}`,
|
|
65
|
+
tokenNoUser: `The deploy-token session has no user id. ${CHECK_CONNECTOR}`,
|
|
66
|
+
deployTokenCheck: REMOTE_DEPLOY_TOKEN_CHECK,
|
|
67
|
+
deployProjectCheck: REMOTE_DEPLOY_PROJECT_CHECK,
|
|
68
|
+
uploadSourceNote: REMOTE_UPLOAD_SOURCE_NOTE,
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=hints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hints.js","sourceRoot":"","sources":["../src/hints.ts"],"names":[],"mappings":"AAyCA,MAAM,CAAC,MAAM,WAAW,GAAc,MAAM,CAAC,MAAM,CAAC;IAClD,cAAc,EAAE,0BAA0B;IAC1C,aAAa,EAAE,qEAAqE;IACpF,gBAAgB,EAAE,wEAAwE;IAC1F,YAAY,EACV,2JAA2J;QAC3J,yJAAyJ;QACzJ,mDAAmD;IACrD,eAAe,EAAE,2DAA2D;IAC5E,cAAc,EACZ,4KAA4K;IAC9K,qBAAqB,EACnB,oLAAoL;IACtL,WAAW,EAAE,iIAAiI;IAC9I,SAAS,EAAE,6CAA6C;IACxD,YAAY,EAAE,kGAAkG;IAChH,oBAAoB,EAAE,yDAAyD;IAC/E,cAAc,EAAE,4GAA4G;IAC5H,WAAW,EAAE,6FAA6F;IAC1G,gBAAgB,EACd,gIAAgI;IAClI,kBAAkB,EAAE,iDAAiD;IACrE,gBAAgB,EAAE,EAAE;CACrB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,iDAAiD,CAAC;AACpF,MAAM,cAAc,GAAG,kCAAkC,kBAAkB,GAAG,CAAC;AAC/E,MAAM,SAAS,GACb,kGAAkG,CAAC;AACrG,MAAM,eAAe,GACnB,kHAAkH,CAAC;AACrH,MAAM,yBAAyB,GAC7B,6JAA6J,CAAC;AAChK,MAAM,2BAA2B,GAAG,0FAA0F,CAAC;AAC/H,4EAA4E;AAC5E,+CAA+C;AAC/C,MAAM,yBAAyB,GAC7B,kIAAkI,CAAC;AAErI,2GAA2G;AAC3G,MAAM,CAAC,MAAM,kBAAkB,GAAc,MAAM,CAAC,MAAM,CAAC;IACzD,cAAc,EAAE,0DAA0D;IAC1E,aAAa,EAAE,0EAA0E,cAAc,EAAE;IACzG,gBAAgB,EAAE,+FAA+F;IACjH,YAAY,EACV,8GAA8G,cAAc,IAAI;QAChI,qJAAqJ;IACvJ,eAAe,EAAE,sFAAsF,cAAc,GAAG;IACxH,cAAc,EACZ,0FAA0F,cAAc,6FAA6F;IACvM,qBAAqB,EACnB,qIAAqI,cAAc,wDAAwD;IAC7M,WAAW,EAAE,2IAA2I;IACxJ,SAAS,EAAE,2DAA2D;IACtE,YAAY,EAAE,uEAAuE,SAAS,EAAE;IAChG,oBAAoB,EAAE,sFAAsF;IAC5G,cAAc,EAAE,uEAAuE,SAAS,EAAE;IAClG,WAAW,EAAE,mEAAmE,SAAS,EAAE;IAC3F,gBAAgB,EAAE,yBAAyB;IAC3C,kBAAkB,EAAE,2BAA2B;IAC/C,gBAAgB,EAAE,yBAAyB;CAC5C,CAAC,CAAC;AAEH,sFAAsF;AACtF,MAAM,CAAC,MAAM,yBAAyB,GAAc,MAAM,CAAC,MAAM,CAAC;IAChE,cAAc,EAAE,mCAAmC;IACnD,aAAa,EAAE,kGAAkG;IACjH,gBAAgB,EAAE,kFAAkF;IACpG,YAAY,EACV,yIAAyI;QACzI,mFAAmF;IACrF,eAAe,EAAE,yDAAyD;IAC1E,cAAc,EAAE,sIAAsI;IACtJ,qBAAqB,EACnB,2KAA2K;IAC7K,WAAW,EAAE,2IAA2I;IACxJ,SAAS,EAAE,sGAAsG;IACjH,YAAY,EAAE,kCAAkC,eAAe,EAAE;IACjE,oBAAoB,EAAE,sFAAsF;IAC5G,cAAc,EAAE,gDAAgD,eAAe,EAAE;IACjF,WAAW,EAAE,4CAA4C,eAAe,EAAE;IAC1E,gBAAgB,EAAE,yBAAyB;IAC3C,kBAAkB,EAAE,2BAA2B;IAC/C,gBAAgB,EAAE,yBAAyB;CAC5C,CAAC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
3
|
-
import { createDeps
|
|
3
|
+
import { createDeps } from "./node/deps.js";
|
|
4
|
+
import { createServerFactory } from "./server.js";
|
|
4
5
|
// stdout carries the protocol; diagnostics must go to stderr or the client
|
|
5
6
|
// sees a corrupted JSON-RPC stream.
|
|
6
7
|
const logError = (err) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,2EAA2E;AAC3E,oCAAoC;AACpC,MAAM,QAAQ,GAAG,CAAC,GAAY,EAAQ,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;AACxC,CAAC,CAAC;AAEF,IAAI,CAAC;IACH,UAAU,CAAC,mBAAmB,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;AACvE,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { HostLookup } from "../client/assets.js";
|
|
2
|
+
import type { AuthProvider } from "../client/auth-provider.js";
|
|
3
|
+
import { type MicropageConfig } from "../client/config.js";
|
|
4
|
+
import { type FetchLike } from "../client/http.js";
|
|
5
|
+
import type { ServerDeps } from "../context.js";
|
|
6
|
+
export interface CreateDepsOptions {
|
|
7
|
+
/** Replaces global fetch for every outbound call (tests). */
|
|
8
|
+
fetch?: FetchLike;
|
|
9
|
+
now?: () => number;
|
|
10
|
+
/** Replaces the system resolver for `{url}` uploads (tests). */
|
|
11
|
+
lookupHost?: HostLookup;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Picks where tokens come from: a deploy token when MICROPAGE_DEPLOY_TOKEN and
|
|
15
|
+
* MICROPAGE_DEPLOY_PROJECT are both set (only one set throws), else the CLI
|
|
16
|
+
* session file. The session provider is used even when the file does not
|
|
17
|
+
* exist yet, so a `micropage login` after the server started takes effect
|
|
18
|
+
* without a restart; until then every call fails with NOT_LOGGED_IN.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createAuthProvider(env: NodeJS.ProcessEnv, config: MicropageConfig, options?: CreateDepsOptions): AuthProvider;
|
|
21
|
+
/**
|
|
22
|
+
* The stdio server's deps, built once per process from the environment. The
|
|
23
|
+
* confirmation-token key is random per process, so restarting the server
|
|
24
|
+
* invalidates every outstanding preview token.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createDeps(env?: NodeJS.ProcessEnv, options?: CreateDepsOptions): ServerDeps;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { loadConfig } from "../client/config.js";
|
|
3
|
+
import { DeployTokenAuthProvider, readDeployTokenEnv } from "../client/deploy-token.js";
|
|
4
|
+
import { Http } from "../client/http.js";
|
|
5
|
+
import { SessionAuthProvider, sessionFilePath } from "../client/session-store.js";
|
|
6
|
+
import { PlanGate } from "../client/tier.js";
|
|
7
|
+
import { ConfirmationTokens, envPermissions } from "../guards.js";
|
|
8
|
+
import { nodeHostLookup } from "./host-lookup.js";
|
|
9
|
+
import { nodePathLoader } from "./path-source.js";
|
|
10
|
+
/**
|
|
11
|
+
* Picks where tokens come from: a deploy token when MICROPAGE_DEPLOY_TOKEN and
|
|
12
|
+
* MICROPAGE_DEPLOY_PROJECT are both set (only one set throws), else the CLI
|
|
13
|
+
* session file. The session provider is used even when the file does not
|
|
14
|
+
* exist yet, so a `micropage login` after the server started takes effect
|
|
15
|
+
* without a restart; until then every call fails with NOT_LOGGED_IN.
|
|
16
|
+
*/
|
|
17
|
+
export function createAuthProvider(env, config, options = {}) {
|
|
18
|
+
const shared = {
|
|
19
|
+
config,
|
|
20
|
+
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
21
|
+
...(options.now ? { now: options.now } : {}),
|
|
22
|
+
};
|
|
23
|
+
const deploy = readDeployTokenEnv(env);
|
|
24
|
+
if (deploy)
|
|
25
|
+
return new DeployTokenAuthProvider({ ...shared, ...deploy });
|
|
26
|
+
return new SessionAuthProvider({ ...shared, path: sessionFilePath(env) });
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The stdio server's deps, built once per process from the environment. The
|
|
30
|
+
* confirmation-token key is random per process, so restarting the server
|
|
31
|
+
* invalidates every outstanding preview token.
|
|
32
|
+
*/
|
|
33
|
+
export function createDeps(env = process.env, options = {}) {
|
|
34
|
+
const config = loadConfig(env);
|
|
35
|
+
const auth = createAuthProvider(env, config, options);
|
|
36
|
+
const http = new Http({ config, auth, ...(options.fetch ? { fetch: options.fetch } : {}) });
|
|
37
|
+
const tier = new PlanGate({ http, auth, ...(options.now ? { now: options.now } : {}) });
|
|
38
|
+
return {
|
|
39
|
+
config,
|
|
40
|
+
auth,
|
|
41
|
+
http,
|
|
42
|
+
tier,
|
|
43
|
+
permissions: envPermissions(env),
|
|
44
|
+
confirmationTokens: new ConfirmationTokens({ key: randomBytes(32), ...(options.now ? { now: options.now } : {}) }),
|
|
45
|
+
uploads: {
|
|
46
|
+
pathLoader: nodePathLoader,
|
|
47
|
+
lookupHost: options.lookupHost ?? nodeHostLookup,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=deps.js.map
|