@12-apps/mcp 3.10.0 → 3.12.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/chunk-VDD4YRNP.js +197 -0
- package/dist/chunk-VDD4YRNP.js.map +1 -0
- package/dist/chunk-WUNMAHQG.js +325 -0
- package/dist/chunk-WUNMAHQG.js.map +1 -0
- package/dist/{create-api-mcp-oauth-CwVXKK-A.d.ts → create-api-mcp-oauth-CsC0jlH7.d.ts} +1 -1
- package/dist/hono/index.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +25 -9
- package/dist/index.js.map +1 -1
- package/dist/locales-eKE_OJw4.d.ts +64 -0
- package/dist/manifest/index.d.ts +93 -0
- package/dist/manifest/index.js +22 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/server.d.ts +74 -0
- package/dist/manifest/server.js +41 -0
- package/dist/manifest/server.js.map +1 -0
- package/dist/oauth/index.d.ts +2 -2
- package/dist/oauth/index.js +6 -189
- package/dist/oauth/index.js.map +1 -1
- package/dist/react/index.d.ts +20 -2
- package/dist/react/index.js +129 -1
- package/dist/react/index.js.map +1 -1
- package/package.json +34 -14
- package/src/en-US.ts +204 -0
- package/src/index.ts +12 -0
- package/src/locales.ts +58 -0
- package/src/manifest/index.ts +89 -0
- package/src/manifest/server.ts +94 -0
- package/src/react/en-US.ts +125 -0
- package/src/react/index.ts +18 -0
- package/src/react/locales.ts +17 -0
- package/dist/chunk-HRAQKMDC.js +0 -154
- package/dist/chunk-HRAQKMDC.js.map +0 -1
- package/dist/pt-BR-e1RnV2v8.d.ts +0 -25
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import {
|
|
2
|
+
providerForHostId
|
|
3
|
+
} from "./chunk-FBUSSQSK.js";
|
|
4
|
+
import {
|
|
5
|
+
__name
|
|
6
|
+
} from "./chunk-7QVYU63E.js";
|
|
7
|
+
|
|
8
|
+
// src/oauth/prisma-stores.ts
|
|
9
|
+
function clientStore(getPrisma) {
|
|
10
|
+
return {
|
|
11
|
+
async create(client) {
|
|
12
|
+
const prisma = await getPrisma();
|
|
13
|
+
return prisma.oAuthClient.create({ data: client });
|
|
14
|
+
},
|
|
15
|
+
async findByClientId(clientId) {
|
|
16
|
+
const prisma = await getPrisma();
|
|
17
|
+
return prisma.oAuthClient.findUnique({ where: { clientId } });
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
__name(clientStore, "clientStore");
|
|
22
|
+
function refreshTokenStore(getPrisma) {
|
|
23
|
+
return {
|
|
24
|
+
async create(token) {
|
|
25
|
+
const prisma = await getPrisma();
|
|
26
|
+
await prisma.oAuthRefreshToken.create({ data: token });
|
|
27
|
+
},
|
|
28
|
+
async findByHash(tokenHash) {
|
|
29
|
+
const prisma = await getPrisma();
|
|
30
|
+
return prisma.oAuthRefreshToken.findUnique({ where: { tokenHash } });
|
|
31
|
+
},
|
|
32
|
+
async hasSuccessor(tokenHash) {
|
|
33
|
+
const prisma = await getPrisma();
|
|
34
|
+
const successor = await prisma.oAuthRefreshToken.findFirst({
|
|
35
|
+
where: { rotatedFrom: tokenHash }
|
|
36
|
+
});
|
|
37
|
+
return successor !== null;
|
|
38
|
+
},
|
|
39
|
+
async listFamily(userEmail, clientId) {
|
|
40
|
+
const prisma = await getPrisma();
|
|
41
|
+
return prisma.oAuthRefreshToken.findMany({ where: { userEmail, clientId } });
|
|
42
|
+
},
|
|
43
|
+
async revokeHashes(tokenHashes, at) {
|
|
44
|
+
if (tokenHashes.length === 0) return;
|
|
45
|
+
const prisma = await getPrisma();
|
|
46
|
+
await prisma.oAuthRefreshToken.updateMany({
|
|
47
|
+
where: { tokenHash: { in: [...tokenHashes] } },
|
|
48
|
+
data: { revokedAt: at }
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
async rotate(successor, parentHash, at) {
|
|
52
|
+
const prisma = await getPrisma();
|
|
53
|
+
return prisma.$transaction(async (tx) => {
|
|
54
|
+
const { count } = await tx.oAuthRefreshToken.updateMany({
|
|
55
|
+
where: { tokenHash: parentHash, revokedAt: null },
|
|
56
|
+
data: { revokedAt: at }
|
|
57
|
+
});
|
|
58
|
+
if (count !== 1) return false;
|
|
59
|
+
await tx.oAuthRefreshToken.create({ data: successor });
|
|
60
|
+
return true;
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
async revokeLiveForClient(userEmail, clientId) {
|
|
64
|
+
const prisma = await getPrisma();
|
|
65
|
+
const { count } = await prisma.oAuthRefreshToken.updateMany({
|
|
66
|
+
where: { userEmail, clientId, revokedAt: null },
|
|
67
|
+
data: { revokedAt: /* @__PURE__ */ new Date() }
|
|
68
|
+
});
|
|
69
|
+
return count;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
__name(refreshTokenStore, "refreshTokenStore");
|
|
74
|
+
var CONNECTION_SELECT = {
|
|
75
|
+
oauthClientId: true,
|
|
76
|
+
clientName: true,
|
|
77
|
+
host: true,
|
|
78
|
+
connectedAt: true,
|
|
79
|
+
lastActiveAt: true
|
|
80
|
+
};
|
|
81
|
+
function connectionStore(getPrisma) {
|
|
82
|
+
return {
|
|
83
|
+
async lastActiveAt(userId, oauthClientId) {
|
|
84
|
+
const prisma = await getPrisma();
|
|
85
|
+
const row = await prisma.mcpConnection.findUnique({
|
|
86
|
+
where: { userId_oauthClientId: { userId, oauthClientId } },
|
|
87
|
+
select: { lastActiveAt: true }
|
|
88
|
+
});
|
|
89
|
+
return row?.lastActiveAt ?? null;
|
|
90
|
+
},
|
|
91
|
+
async recordActivity({ userId, oauthClientId, clientName, host, at }) {
|
|
92
|
+
const prisma = await getPrisma();
|
|
93
|
+
await prisma.mcpConnection.upsert({
|
|
94
|
+
where: { userId_oauthClientId: { userId, oauthClientId } },
|
|
95
|
+
create: { userId, oauthClientId, clientName, host, connectedAt: at, lastActiveAt: at },
|
|
96
|
+
// Never blank a known host on refresh — keep the existing attribution
|
|
97
|
+
// when this grant cannot derive one.
|
|
98
|
+
update: {
|
|
99
|
+
clientName,
|
|
100
|
+
lastActiveAt: at,
|
|
101
|
+
revokedAt: null,
|
|
102
|
+
...host ? { host } : {}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
async listActive(userId) {
|
|
107
|
+
const prisma = await getPrisma();
|
|
108
|
+
const rows = await prisma.mcpConnection.findMany({
|
|
109
|
+
where: { userId, revokedAt: null },
|
|
110
|
+
orderBy: { lastActiveAt: "desc" },
|
|
111
|
+
select: { ...CONNECTION_SELECT }
|
|
112
|
+
});
|
|
113
|
+
return rows;
|
|
114
|
+
},
|
|
115
|
+
revokeByHost: /* @__PURE__ */ __name((userId, host) => revokeByHost(getPrisma, userId, host), "revokeByHost"),
|
|
116
|
+
announce: /* @__PURE__ */ __name((userId, host) => announce(getPrisma, userId, host), "announce")
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
__name(connectionStore, "connectionStore");
|
|
120
|
+
async function revokeByHost(getPrisma, userId, host) {
|
|
121
|
+
const prisma = await getPrisma();
|
|
122
|
+
const attributed = await prisma.mcpConnection.findMany({
|
|
123
|
+
where: { userId, revokedAt: null, host },
|
|
124
|
+
select: { id: true, oauthClientId: true }
|
|
125
|
+
});
|
|
126
|
+
const targets = attributed.length > 0 ? attributed : await prisma.mcpConnection.findMany({
|
|
127
|
+
where: { userId, revokedAt: null, host: null },
|
|
128
|
+
select: { id: true, oauthClientId: true }
|
|
129
|
+
});
|
|
130
|
+
if (targets.length === 0) return [];
|
|
131
|
+
await prisma.mcpConnection.updateMany({
|
|
132
|
+
where: { id: { in: targets.map((row) => String(row.id)) } },
|
|
133
|
+
data: { revokedAt: /* @__PURE__ */ new Date() }
|
|
134
|
+
});
|
|
135
|
+
return targets.map((row) => String(row.oauthClientId));
|
|
136
|
+
}
|
|
137
|
+
__name(revokeByHost, "revokeByHost");
|
|
138
|
+
async function announce(getPrisma, userId, host) {
|
|
139
|
+
const prisma = await getPrisma();
|
|
140
|
+
const now = /* @__PURE__ */ new Date();
|
|
141
|
+
const refreshed = await prisma.mcpConnection.updateMany({
|
|
142
|
+
where: { userId, revokedAt: null, host },
|
|
143
|
+
data: { lastActiveAt: now, revokedAt: null }
|
|
144
|
+
});
|
|
145
|
+
if (refreshed.count > 0) return refreshed.count;
|
|
146
|
+
const candidate = await prisma.mcpConnection.findFirst({
|
|
147
|
+
where: { userId, revokedAt: null, host: null },
|
|
148
|
+
orderBy: { lastActiveAt: "desc" },
|
|
149
|
+
select: { id: true }
|
|
150
|
+
});
|
|
151
|
+
if (!candidate) return 0;
|
|
152
|
+
await prisma.mcpConnection.update({
|
|
153
|
+
where: { id: candidate.id },
|
|
154
|
+
data: { host, lastActiveAt: now, revokedAt: null }
|
|
155
|
+
});
|
|
156
|
+
return 1;
|
|
157
|
+
}
|
|
158
|
+
__name(announce, "announce");
|
|
159
|
+
function createPrismaMcpStores(getPrisma) {
|
|
160
|
+
return {
|
|
161
|
+
clients: clientStore(getPrisma),
|
|
162
|
+
refreshTokens: refreshTokenStore(getPrisma),
|
|
163
|
+
connections: connectionStore(getPrisma)
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
__name(createPrismaMcpStores, "createPrismaMcpStores");
|
|
167
|
+
|
|
168
|
+
// src/oauth/connections.ts
|
|
169
|
+
function asProvider(host) {
|
|
170
|
+
return host === null ? null : providerForHostId(host);
|
|
171
|
+
}
|
|
172
|
+
__name(asProvider, "asProvider");
|
|
173
|
+
async function listAiConnections(connections, userId) {
|
|
174
|
+
const rows = await connections.listActive(userId);
|
|
175
|
+
return rows.map((row) => ({ ...row, host: asProvider(row.host) }));
|
|
176
|
+
}
|
|
177
|
+
__name(listAiConnections, "listAiConnections");
|
|
178
|
+
async function disconnectAiHost(stores, caller, host) {
|
|
179
|
+
const disconnectedClientIds = await stores.connections.revokeByHost(caller.userId, host);
|
|
180
|
+
const revoked = await Promise.all(
|
|
181
|
+
disconnectedClientIds.map(
|
|
182
|
+
(clientId) => stores.refreshTokens.revokeLiveForClient(caller.email, clientId)
|
|
183
|
+
)
|
|
184
|
+
);
|
|
185
|
+
return {
|
|
186
|
+
disconnectedClientIds,
|
|
187
|
+
revokedRefreshTokens: revoked.reduce((total, count) => total + count, 0)
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
__name(disconnectAiHost, "disconnectAiHost");
|
|
191
|
+
|
|
192
|
+
export {
|
|
193
|
+
createPrismaMcpStores,
|
|
194
|
+
listAiConnections,
|
|
195
|
+
disconnectAiHost
|
|
196
|
+
};
|
|
197
|
+
//# sourceMappingURL=chunk-VDD4YRNP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/oauth/prisma-stores.ts","../src/oauth/connections.ts"],"sourcesContent":["import type {\n McpConnectionStore,\n McpOauthStores,\n NewOAuthClient,\n NewRefreshToken,\n OAuthClientStore,\n RefreshTokenStore,\n StoredMcpConnection,\n StoredOAuthClient,\n StoredRefreshToken,\n} from \"./stores\";\n\n/**\n * The ports of `./stores.ts`, filled by Prisma (12-23).\n *\n * The package owns the three models (`prisma/mcp.prisma`), so their delegate\n * shapes are known and this adapter can be exact. A host with Prisma therefore\n * writes ONE line —\n *\n * stores: createPrismaMcpStores(async () => getPrismaClient() as unknown as McpOauthPrisma)\n *\n * — and no host code at all beyond it. The client is duck-typed (only the\n * delegates used, only the arguments used) so this file never imports a project's\n * generated client, and a non-Prisma host fills the ports directly instead.\n */\n\n/** A `where` on the composite unique of `mcp_connections`. */\ninterface ConnectionKey {\n userId_oauthClientId: { userId: string; oauthClientId: string };\n}\n\n/** The minimal Prisma surface the AS needs. Every field is one the surface writes. */\nexport interface McpOauthPrisma {\n oAuthClient: {\n create(args: { data: NewOAuthClient }): Promise<StoredOAuthClient>;\n findUnique(args: { where: { clientId: string } }): Promise<StoredOAuthClient | null>;\n };\n oAuthRefreshToken: {\n create(args: { data: NewRefreshToken }): Promise<unknown>;\n findUnique(args: { where: { tokenHash: string } }): Promise<StoredRefreshToken | null>;\n findFirst(args: { where: { rotatedFrom: string } }): Promise<{ tokenHash: string } | null>;\n findMany(args: {\n where: { userEmail: string; clientId: string };\n }): Promise<StoredRefreshToken[]>;\n // No single-row `update`: the rotation used to revoke its parent with one and\n // that was the bug (unconditional, so two concurrent rotations both won). Every\n // revoke here is now an `updateMany` with a predicate that says WHICH rows may\n // move, which is also why this delegate list stays honest about what is written.\n updateMany(args: {\n where:\n | { tokenHash: { in: string[] } }\n | { userEmail: string; clientId: string; revokedAt: null };\n data: { revokedAt: Date };\n }): Promise<{ count: number }>;\n };\n mcpConnection: {\n findUnique(args: {\n where: ConnectionKey;\n select: { lastActiveAt: true };\n }): Promise<{ lastActiveAt: Date } | null>;\n findFirst(args: {\n where: { userId: string; revokedAt: null; host: null };\n orderBy: { lastActiveAt: \"desc\" };\n select: { id: true };\n }): Promise<{ id: string } | null>;\n findMany(args: {\n where: { userId: string; revokedAt: null; host?: string | null };\n orderBy?: { lastActiveAt: \"desc\" };\n select: Record<string, true>;\n }): Promise<Record<string, unknown>[]>;\n upsert(args: {\n where: ConnectionKey;\n create: Record<string, unknown>;\n update: Record<string, unknown>;\n }): Promise<unknown>;\n update(args: { where: { id: string }; data: Record<string, unknown> }): Promise<unknown>;\n updateMany(args: {\n where: { id: { in: string[] } } | { userId: string; revokedAt: null; host: string };\n data: Record<string, unknown>;\n }): Promise<{ count: number }>;\n };\n /**\n * Prisma's INTERACTIVE transaction, used for the rotation's claim + write. The\n * callback form (not the array form) is required: the successor may only be\n * created once the conditional revoke has reported that it, and not a concurrent\n * sibling, claimed the parent — see `RefreshTokenStore.rotate`.\n */\n $transaction<T>(fn: (tx: McpOauthTx) => Promise<T>): Promise<T>;\n}\n\n/**\n * The delegate subset used INSIDE the rotation transaction. Not exported: it is\n * reachable structurally through `McpOauthPrisma.$transaction`, so no host ever\n * needs to name it, and exporting a type nobody imports is what knip flags.\n */\ninterface McpOauthTx {\n oAuthRefreshToken: {\n create(args: { data: NewRefreshToken }): Promise<unknown>;\n updateMany(args: {\n where: { tokenHash: string; revokedAt: null };\n data: { revokedAt: Date };\n }): Promise<{ count: number }>;\n };\n}\n\n/** A lazily-resolved client, so a host's singleton is awaited per call. */\nexport type McpOauthPrismaProvider = () => Promise<McpOauthPrisma>;\n\nfunction clientStore(getPrisma: McpOauthPrismaProvider): OAuthClientStore {\n return {\n async create(client: NewOAuthClient) {\n const prisma = await getPrisma();\n return prisma.oAuthClient.create({ data: client });\n },\n async findByClientId(clientId: string) {\n const prisma = await getPrisma();\n return prisma.oAuthClient.findUnique({ where: { clientId } });\n },\n };\n}\n\nfunction refreshTokenStore(getPrisma: McpOauthPrismaProvider): RefreshTokenStore {\n return {\n async create(token) {\n const prisma = await getPrisma();\n await prisma.oAuthRefreshToken.create({ data: token });\n },\n async findByHash(tokenHash) {\n const prisma = await getPrisma();\n return prisma.oAuthRefreshToken.findUnique({ where: { tokenHash } });\n },\n async hasSuccessor(tokenHash) {\n const prisma = await getPrisma();\n const successor = await prisma.oAuthRefreshToken.findFirst({\n where: { rotatedFrom: tokenHash },\n });\n return successor !== null;\n },\n async listFamily(userEmail, clientId) {\n const prisma = await getPrisma();\n return prisma.oAuthRefreshToken.findMany({ where: { userEmail, clientId } });\n },\n async revokeHashes(tokenHashes, at) {\n if (tokenHashes.length === 0) return;\n const prisma = await getPrisma();\n await prisma.oAuthRefreshToken.updateMany({\n where: { tokenHash: { in: [...tokenHashes] } },\n data: { revokedAt: at },\n });\n },\n async rotate(successor, parentHash, at) {\n const prisma = await getPrisma();\n return prisma.$transaction(async (tx) => {\n // CLAIM-ONCE. The `revokedAt: null` predicate is what makes this safe under\n // concurrency, and it is load-bearing rather than defensive: on Postgres's\n // default READ COMMITTED, a second transaction's `updateMany` blocks on the\n // row lock, then re-evaluates this WHERE against the COMMITTED row — which\n // now has a `revokedAt` — and reports 0 rows. So exactly one caller can ever\n // see count 1, and it is the only one that goes on to create a successor.\n // An unconditional `update` would let both through: two live successors of\n // one parent, and replay detection silently defeated (it waits for a third\n // use of the parent that now never comes).\n const { count } = await tx.oAuthRefreshToken.updateMany({\n where: { tokenHash: parentHash, revokedAt: null },\n data: { revokedAt: at },\n });\n // Lost the claim: write NOTHING. The zero-row update commits as the no-op\n // it is, so there is nothing to roll back.\n if (count !== 1) return false;\n // Same transaction as the claim, so a crash cannot leave a live parent AND\n // a live child either.\n await tx.oAuthRefreshToken.create({ data: successor });\n return true;\n });\n },\n async revokeLiveForClient(userEmail, clientId) {\n const prisma = await getPrisma();\n const { count } = await prisma.oAuthRefreshToken.updateMany({\n where: { userEmail, clientId, revokedAt: null },\n data: { revokedAt: new Date() },\n });\n return count;\n },\n };\n}\n\n/** The connection columns the account surface reads. */\nconst CONNECTION_SELECT = {\n oauthClientId: true,\n clientName: true,\n host: true,\n connectedAt: true,\n lastActiveAt: true,\n} as const;\n\nfunction connectionStore(getPrisma: McpOauthPrismaProvider): McpConnectionStore {\n return {\n async lastActiveAt(userId, oauthClientId) {\n const prisma = await getPrisma();\n const row = await prisma.mcpConnection.findUnique({\n where: { userId_oauthClientId: { userId, oauthClientId } },\n select: { lastActiveAt: true },\n });\n return row?.lastActiveAt ?? null;\n },\n async recordActivity({ userId, oauthClientId, clientName, host, at }) {\n const prisma = await getPrisma();\n await prisma.mcpConnection.upsert({\n where: { userId_oauthClientId: { userId, oauthClientId } },\n create: { userId, oauthClientId, clientName, host, connectedAt: at, lastActiveAt: at },\n // Never blank a known host on refresh — keep the existing attribution\n // when this grant cannot derive one.\n update: {\n clientName,\n lastActiveAt: at,\n revokedAt: null,\n ...(host ? { host } : {}),\n },\n });\n },\n async listActive(userId) {\n const prisma = await getPrisma();\n const rows = await prisma.mcpConnection.findMany({\n where: { userId, revokedAt: null },\n orderBy: { lastActiveAt: \"desc\" },\n select: { ...CONNECTION_SELECT },\n });\n return rows as unknown as StoredMcpConnection[];\n },\n revokeByHost: (userId, host) => revokeByHost(getPrisma, userId, host),\n announce: (userId, host) => announce(getPrisma, userId, host),\n };\n}\n\n/**\n * Disconnect one provider's connections — and ONLY that provider's.\n *\n * Every read and write is scoped by `userId`: a connection is per-user (an MCP\n * bearer is not tenant-scoped), so the user id IS the isolation here, and the\n * `id` list passed to the update comes from a query that already applied it.\n */\nasync function revokeByHost(\n getPrisma: McpOauthPrismaProvider,\n userId: string,\n host: string,\n): Promise<string[]> {\n const prisma = await getPrisma();\n const attributed = await prisma.mcpConnection.findMany({\n where: { userId, revokedAt: null, host },\n select: { id: true, oauthClientId: true },\n });\n // A legacy `host = null` row is claimed only when the provider has no row of\n // its own: pre-attribution connections must stay disconnectable, but a provider\n // that DID attribute can never revoke another assistant's row.\n const targets =\n attributed.length > 0\n ? attributed\n : await prisma.mcpConnection.findMany({\n where: { userId, revokedAt: null, host: null },\n select: { id: true, oauthClientId: true },\n });\n if (targets.length === 0) return [];\n await prisma.mcpConnection.updateMany({\n where: { id: { in: targets.map((row) => String(row.id)) } },\n data: { revokedAt: new Date() },\n });\n return targets.map((row) => String(row.oauthClientId));\n}\n\n/** A provider's self-report: refresh its own row, or claim the unattributed one. */\nasync function announce(\n getPrisma: McpOauthPrismaProvider,\n userId: string,\n host: string,\n): Promise<number> {\n const prisma = await getPrisma();\n const now = new Date();\n const refreshed = await prisma.mcpConnection.updateMany({\n where: { userId, revokedAt: null, host },\n data: { lastActiveAt: now, revokedAt: null },\n });\n if (refreshed.count > 0) return refreshed.count;\n\n // No row for this provider yet — attribute the just-connected one. Scoped by\n // user, so a self-report can never reach another account's connection.\n const candidate = await prisma.mcpConnection.findFirst({\n where: { userId, revokedAt: null, host: null },\n orderBy: { lastActiveAt: \"desc\" },\n select: { id: true },\n });\n if (!candidate) return 0;\n await prisma.mcpConnection.update({\n where: { id: candidate.id },\n data: { host, lastActiveAt: now, revokedAt: null },\n });\n return 1;\n}\n\n/** Every port, over one lazily-resolved Prisma client. */\nexport function createPrismaMcpStores(getPrisma: McpOauthPrismaProvider): McpOauthStores {\n return {\n clients: clientStore(getPrisma),\n refreshTokens: refreshTokenStore(getPrisma),\n connections: connectionStore(getPrisma),\n };\n}\n","import { providerForHostId, type AiProvider } from \"../guide\";\nimport type {\n McpConnectionStore,\n RefreshTokenStore,\n StoredMcpConnection,\n} from \"./stores\";\n\n/**\n * The account surface's connection OPERATIONS (12-48) — the half of the\n * `GET/DELETE /api/account/mcp-connections` endpoints that is contract rather\n * than host vocabulary.\n *\n * The ROUTE stays in the host on purpose: it mixes the host's session\n * resolution, its response envelope, its published plugin URLs and its logger,\n * and injecting all four here would make the config surface bigger than the\n * handler it replaces. What must NOT stay in each host is the disconnect's\n * both-halves rule, because getting it half right LOOKS right:\n *\n * `connections.revokeByHost` ends the connection rows and returns the OAuth\n * client ids behind them — and a host that stops there has revoked nothing that\n * matters. The assistant still holds a live refresh token for each of those\n * clients, rotates it on schedule, and the very next grant records fresh\n * activity: the card the user just disconnected lights green again on its own.\n * So the rule is one function: revoke the rows AND end every live refresh token\n * of each returned client, in the same call, with no way to import one half\n * without the other.\n *\n * Deliberately NOT invalidated here: the assistant's current ACCESS token.\n * Those are self-contained JWTs the server does not track; a just-disconnected\n * host keeps working for at most their TTL (15 minutes by default) and can then\n * obtain nothing further.\n */\n\n/** An active AI connection, narrowed for display. */\nexport interface AiConnectionSnapshot {\n oauthClientId: string;\n clientName: string | null;\n /** The provider this connection is attributed to (`null` = pre-attribution). */\n host: AiProvider | null;\n connectedAt: Date;\n lastActiveAt: Date;\n}\n\n/** The caller the operations act for — always the session's own user. */\nexport interface AiConnectionCaller {\n /** The host's user id — what `mcp_connections` rows are keyed by. */\n userId: string;\n /** The identity refresh tokens are bound to (the AS binds by email). */\n email: string;\n}\n\n/** What one disconnect actually ended, for the host's log and response. */\nexport interface AiDisconnectResult {\n /** OAuth client ids whose connection rows were revoked. */\n disconnectedClientIds: string[];\n /** Live refresh tokens ended across those clients — the half that cuts access. */\n revokedRefreshTokens: number;\n}\n\n/** Narrow a stored `host` string to a known provider, or `null`. */\nfunction asProvider(host: string | null): AiProvider | null {\n return host === null ? null : providerForHostId(host);\n}\n\n/**\n * A user's active connections, most-recently-active first, with the stored open\n * `host` string narrowed to the package's closed {@link AiProvider} union — the\n * store cannot know which assistants have screens, but the union is this\n * package's own vocabulary (`guide.ts`), so the narrowing lives beside it\n * rather than being re-derived in every host.\n */\nexport async function listAiConnections(\n connections: McpConnectionStore,\n userId: string,\n): Promise<AiConnectionSnapshot[]> {\n const rows: StoredMcpConnection[] = await connections.listActive(userId);\n return rows.map((row) => ({ ...row, host: asProvider(row.host) }));\n}\n\n/**\n * Disconnect one provider for this user — BOTH halves, atomically from the\n * caller's point of view (see the module doc for why one half alone is a\n * disconnect that undoes itself).\n *\n * Idempotent: disconnecting a provider that was never connected returns zero\n * counts rather than failing, so a double-click is harmless. Repeat calls also\n * report zero — `revokeLiveForClient` skips already-revoked tokens by contract.\n */\nexport async function disconnectAiHost(\n stores: { connections: McpConnectionStore; refreshTokens: RefreshTokenStore },\n caller: AiConnectionCaller,\n host: AiProvider,\n): Promise<AiDisconnectResult> {\n const disconnectedClientIds = await stores.connections.revokeByHost(caller.userId, host);\n const revoked = await Promise.all(\n disconnectedClientIds.map((clientId) =>\n stores.refreshTokens.revokeLiveForClient(caller.email, clientId),\n ),\n );\n return {\n disconnectedClientIds,\n revokedRefreshTokens: revoked.reduce((total, count) => total + count, 0),\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-7QVYU63E.js";
|
|
4
|
+
|
|
5
|
+
// src/pt-BR.ts
|
|
6
|
+
var CONNECTOR_TAIL = [
|
|
7
|
+
"Deixe OAuth Client ID e Client Secret em branco \u2014 n\xE3o \xE9 preciso gerar credenciais: a loja registra o conector automaticamente no primeiro acesso.",
|
|
8
|
+
"Confirme e clique em Connect: abre a tela de login da loja \u2014 entre com a SUA conta de lojista e autorize o acesso.",
|
|
9
|
+
"Pronto: ative o conector na conversa para o assistente consultar e operar a sua loja."
|
|
10
|
+
];
|
|
11
|
+
function chatgptConfigureStages(platformName) {
|
|
12
|
+
return [
|
|
13
|
+
{
|
|
14
|
+
id: "enable-dev-mode",
|
|
15
|
+
label: "enable developer mode",
|
|
16
|
+
link: {
|
|
17
|
+
url: "https://chatgpt.com/plugins#settings/Security",
|
|
18
|
+
label: "Abrir Seguran\xE7a e login"
|
|
19
|
+
},
|
|
20
|
+
steps: [
|
|
21
|
+
"Ative o Modo desenvolvedor em Settings \u203A Security and login (Seguran\xE7a e login)."
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "configurar",
|
|
26
|
+
label: "configurar",
|
|
27
|
+
link: {
|
|
28
|
+
url: "https://chatgpt.com/plugins#settings/Connectors?create-connector=true&redirectAfter=%2Fplugins",
|
|
29
|
+
label: "Criar o conector"
|
|
30
|
+
},
|
|
31
|
+
steps: [
|
|
32
|
+
"Isso vai abrir um popup para voc\xEA criar um plugin novo. Coloque como nome o nome da sua loja e, no campo MCP, o link copiado no passo anterior.",
|
|
33
|
+
'Marque a caixa "I understand and want to continue" \u2014 a OpenAI n\xE3o revisou este servidor MCP; ela avisa que sites podem tentar roubar seus dados ou induzir o modelo a a\xE7\xF5es indevidas, incluindo destruir dados.',
|
|
34
|
+
`Clique em "Sign in with ${platformName}" e entre com a sua conta de lojista para autorizar o acesso. Pronto: a conex\xE3o \xE9 registrada automaticamente.`
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
__name(chatgptConfigureStages, "chatgptConfigureStages");
|
|
40
|
+
function PT_BR_AI_HOST_GUIDES(platformName) {
|
|
41
|
+
const chatgptStages = chatgptConfigureStages(platformName);
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
id: "claude",
|
|
45
|
+
label: "Claude.ai",
|
|
46
|
+
brand: "claude",
|
|
47
|
+
kind: "No navegador",
|
|
48
|
+
link: {
|
|
49
|
+
url: "https://claude.ai/new?modal=add-custom-connector#settings/customize-connectors",
|
|
50
|
+
label: "Abrir os conectores do Claude"
|
|
51
|
+
},
|
|
52
|
+
docs: {
|
|
53
|
+
url: "https://support.anthropic.com/en/articles/11175166-how-do-i-connect-mcp-servers-to-claude-ai",
|
|
54
|
+
label: "documenta\xE7\xE3o oficial da Anthropic \u2014 conectores personalizados"
|
|
55
|
+
},
|
|
56
|
+
steps: [
|
|
57
|
+
"Clique no bot\xE3o acima (ou v\xE1 em Settings \u203A Customize \u203A Connectors) e escolha Add custom connector.",
|
|
58
|
+
"D\xEA um nome ao conector (ex.: o nome da sua loja) e cole a URL do servidor MCP da sua loja (copie acima) no campo de URL.",
|
|
59
|
+
...CONNECTOR_TAIL
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: "claude-desktop",
|
|
64
|
+
label: "Claude Desktop",
|
|
65
|
+
brand: "claude",
|
|
66
|
+
kind: "Aplicativo (Windows/Mac)",
|
|
67
|
+
docs: {
|
|
68
|
+
url: "https://support.anthropic.com/en/articles/11175166-how-do-i-connect-mcp-servers-to-claude-ai",
|
|
69
|
+
label: "documenta\xE7\xE3o oficial da Anthropic \u2014 conectores personalizados"
|
|
70
|
+
},
|
|
71
|
+
steps: [
|
|
72
|
+
"Abra o Claude Desktop e v\xE1 em Settings (\u2699\uFE0F) \u203A Connectors.",
|
|
73
|
+
"Clique em Add custom connector e cole a URL do servidor MCP da sua loja (copie acima).",
|
|
74
|
+
...CONNECTOR_TAIL
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "chatgpt",
|
|
79
|
+
label: "ChatGPT",
|
|
80
|
+
brand: "openai",
|
|
81
|
+
kind: "No navegador",
|
|
82
|
+
link: {
|
|
83
|
+
url: "https://chatgpt.com/plugins",
|
|
84
|
+
label: "Abrir os plugins do ChatGPT"
|
|
85
|
+
},
|
|
86
|
+
docs: {
|
|
87
|
+
url: "https://developers.openai.com/apps-sdk/deploy/connect-chatgpt",
|
|
88
|
+
label: "documenta\xE7\xE3o oficial da OpenAI \u2014 conectar um servidor MCP ao ChatGPT"
|
|
89
|
+
},
|
|
90
|
+
configureStages: chatgptStages,
|
|
91
|
+
// Mirrors the flattened stage instructions so the MCP connect guide
|
|
92
|
+
// (`connectToChatGpt`) can never drift from what owners see in the wizard.
|
|
93
|
+
steps: chatgptStages.flatMap((stage) => stage.steps)
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "codex",
|
|
97
|
+
label: "Codex",
|
|
98
|
+
brand: "openai",
|
|
99
|
+
kind: "App / CLI de desenvolvedor",
|
|
100
|
+
link: {
|
|
101
|
+
url: "https://developers.openai.com/codex",
|
|
102
|
+
label: "Documenta\xE7\xE3o do Codex"
|
|
103
|
+
},
|
|
104
|
+
docs: {
|
|
105
|
+
url: "https://developers.openai.com/apps-sdk/deploy/connect-chatgpt",
|
|
106
|
+
label: "documenta\xE7\xE3o oficial da OpenAI \u2014 conectar um servidor MCP"
|
|
107
|
+
},
|
|
108
|
+
steps: [
|
|
109
|
+
"No Codex, abra as configura\xE7\xF5es de MCP (Settings \u203A MCP no app, ou o arquivo de configura\xE7\xE3o na CLI).",
|
|
110
|
+
"Adicione um servidor MCP e cole a URL do servidor MCP da sua loja (copie acima) como um conector remoto (HTTP).",
|
|
111
|
+
...CONNECTOR_TAIL
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
__name(PT_BR_AI_HOST_GUIDES, "PT_BR_AI_HOST_GUIDES");
|
|
117
|
+
var PT_BR_AI_CAPABILITIES = [
|
|
118
|
+
{
|
|
119
|
+
id: "orders",
|
|
120
|
+
title: "Acompanhe seus pedidos",
|
|
121
|
+
detail: '"Quais pedidos entraram hoje?"'
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "inventory",
|
|
125
|
+
title: "Controle o estoque",
|
|
126
|
+
detail: '"Quanto ainda tenho do produto X? Registre a entrada de 20 unidades."'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: "catalog",
|
|
130
|
+
title: "Gerencie o cat\xE1logo",
|
|
131
|
+
detail: "Crie e edite produtos e categorias conversando."
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: "sales",
|
|
135
|
+
title: "Entenda suas vendas",
|
|
136
|
+
detail: '"Qual foi o faturamento da semana?"'
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
var PT_BR_AI_PERMISSION_MODEL = "O assistente age em seu nome, com exatamente as suas permiss\xF5es: ele pode fazer o que voc\xEA pode fazer na sua loja \u2014 nada al\xE9m disso. N\xE3o \xE9 preciso criar nenhuma chave ou credencial extra; a autoriza\xE7\xE3o usa o seu pr\xF3prio login.";
|
|
140
|
+
function PT_BR_AI_CONNECT_PROMPT(spec) {
|
|
141
|
+
return `Voc\xEA agora tem acesso ao conector MCP da minha loja. Fa\xE7a, nesta ordem:
|
|
142
|
+
1) Execute a ferramenta ${spec.announceTool} informando qual assistente voc\xEA \xE9 (host: "chatgpt", "claude" ou "codex") para registrar a conex\xE3o com a minha loja.
|
|
143
|
+
2) Execute a ferramenta ${spec.probeTool} para confirmar o acesso a ${spec.probeSubject}.
|
|
144
|
+
Se precisar do identificador da loja, me pergunte o ${spec.identifierName}.`;
|
|
145
|
+
}
|
|
146
|
+
__name(PT_BR_AI_CONNECT_PROMPT, "PT_BR_AI_CONNECT_PROMPT");
|
|
147
|
+
|
|
148
|
+
// src/en-US.ts
|
|
149
|
+
var CONNECTOR_TAIL2 = [
|
|
150
|
+
"Leave OAuth Client ID and Client Secret blank \u2014 there are no credentials to generate: the store registers the connector automatically on first access.",
|
|
151
|
+
"Confirm and click Connect: the store's sign-in screen opens \u2014 sign in with YOUR own owner account and authorise the access.",
|
|
152
|
+
"Done: enable the connector in the chat so the assistant can query and operate your store."
|
|
153
|
+
];
|
|
154
|
+
function chatgptConfigureStages2(platformName) {
|
|
155
|
+
return [
|
|
156
|
+
{
|
|
157
|
+
id: "enable-dev-mode",
|
|
158
|
+
label: "enable developer mode",
|
|
159
|
+
link: {
|
|
160
|
+
url: "https://chatgpt.com/plugins#settings/Security",
|
|
161
|
+
label: "Open Security and login"
|
|
162
|
+
},
|
|
163
|
+
steps: [
|
|
164
|
+
"Turn on Developer mode under Settings \u203A Security and login."
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: "configurar",
|
|
169
|
+
label: "configure",
|
|
170
|
+
link: {
|
|
171
|
+
url: "https://chatgpt.com/plugins#settings/Connectors?create-connector=true&redirectAfter=%2Fplugins",
|
|
172
|
+
label: "Create the connector"
|
|
173
|
+
},
|
|
174
|
+
steps: [
|
|
175
|
+
"That opens a popup to create a new plugin. Give it your store's name, and put the link you copied in the previous step in the MCP field.",
|
|
176
|
+
'Tick "I understand and want to continue" \u2014 OpenAI has not reviewed this MCP server; they warn that sites may try to steal your data or push the model into harmful actions, including destroying data.',
|
|
177
|
+
`Click "Sign in with ${platformName}" and sign in with your owner account to authorise access. That is it: the connection is registered automatically.`
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
__name(chatgptConfigureStages2, "chatgptConfigureStages");
|
|
183
|
+
function EN_US_AI_HOST_GUIDES(platformName) {
|
|
184
|
+
const chatgptStages = chatgptConfigureStages2(platformName);
|
|
185
|
+
return [
|
|
186
|
+
{
|
|
187
|
+
id: "claude",
|
|
188
|
+
label: "Claude.ai",
|
|
189
|
+
brand: "claude",
|
|
190
|
+
kind: "In the browser",
|
|
191
|
+
link: {
|
|
192
|
+
url: "https://claude.ai/new?modal=add-custom-connector#settings/customize-connectors",
|
|
193
|
+
label: "Open Claude's connectors"
|
|
194
|
+
},
|
|
195
|
+
docs: {
|
|
196
|
+
url: "https://support.anthropic.com/en/articles/11175166-how-do-i-connect-mcp-servers-to-claude-ai",
|
|
197
|
+
label: "Anthropic's own documentation \u2014 custom connectors"
|
|
198
|
+
},
|
|
199
|
+
steps: [
|
|
200
|
+
"Click the button above (or go to Settings \u203A Customize \u203A Connectors) and choose Add custom connector.",
|
|
201
|
+
"Name the connector (your store's name works) and paste your store's MCP server URL (copy it above) into the URL field.",
|
|
202
|
+
...CONNECTOR_TAIL2
|
|
203
|
+
]
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: "claude-desktop",
|
|
207
|
+
label: "Claude Desktop",
|
|
208
|
+
brand: "claude",
|
|
209
|
+
kind: "App (Windows/Mac)",
|
|
210
|
+
docs: {
|
|
211
|
+
url: "https://support.anthropic.com/en/articles/11175166-how-do-i-connect-mcp-servers-to-claude-ai",
|
|
212
|
+
label: "Anthropic's own documentation \u2014 custom connectors"
|
|
213
|
+
},
|
|
214
|
+
steps: [
|
|
215
|
+
"Open Claude Desktop and go to Settings (\u2699\uFE0F) \u203A Connectors.",
|
|
216
|
+
"Click Add custom connector and paste your store's MCP server URL (copy it above).",
|
|
217
|
+
...CONNECTOR_TAIL2
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: "chatgpt",
|
|
222
|
+
label: "ChatGPT",
|
|
223
|
+
brand: "openai",
|
|
224
|
+
kind: "In the browser",
|
|
225
|
+
link: {
|
|
226
|
+
url: "https://chatgpt.com/plugins",
|
|
227
|
+
label: "Open ChatGPT's plugins"
|
|
228
|
+
},
|
|
229
|
+
docs: {
|
|
230
|
+
url: "https://developers.openai.com/apps-sdk/deploy/connect-chatgpt",
|
|
231
|
+
label: "OpenAI's own documentation \u2014 connecting an MCP server to ChatGPT"
|
|
232
|
+
},
|
|
233
|
+
configureStages: chatgptStages,
|
|
234
|
+
// Mirrors the flattened stage instructions so the MCP connect guide
|
|
235
|
+
// (`connectToChatGpt`) can never drift from what owners see in the wizard.
|
|
236
|
+
steps: chatgptStages.flatMap((stage) => stage.steps)
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
id: "codex",
|
|
240
|
+
label: "Codex",
|
|
241
|
+
brand: "openai",
|
|
242
|
+
kind: "Developer app / CLI",
|
|
243
|
+
link: {
|
|
244
|
+
url: "https://developers.openai.com/codex",
|
|
245
|
+
label: "Codex documentation"
|
|
246
|
+
},
|
|
247
|
+
docs: {
|
|
248
|
+
url: "https://developers.openai.com/apps-sdk/deploy/connect-chatgpt",
|
|
249
|
+
label: "OpenAI's own documentation \u2014 connecting an MCP server"
|
|
250
|
+
},
|
|
251
|
+
steps: [
|
|
252
|
+
"In Codex, open the MCP settings (Settings \u203A MCP in the app, or the config file on the CLI).",
|
|
253
|
+
"Add an MCP server and paste your store's MCP server URL (copy it above) as a remote (HTTP) connector.",
|
|
254
|
+
...CONNECTOR_TAIL2
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
];
|
|
258
|
+
}
|
|
259
|
+
__name(EN_US_AI_HOST_GUIDES, "EN_US_AI_HOST_GUIDES");
|
|
260
|
+
var EN_US_AI_CAPABILITIES = [
|
|
261
|
+
// The `detail` of each is a QUESTION a reader could paste verbatim, so it is
|
|
262
|
+
// written as one rather than described.
|
|
263
|
+
{
|
|
264
|
+
id: "orders",
|
|
265
|
+
title: "Follow your orders",
|
|
266
|
+
detail: '"Which orders came in today?"'
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
id: "inventory",
|
|
270
|
+
title: "Keep on top of stock",
|
|
271
|
+
detail: '"How much of product X is left? Record 20 units received."'
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
id: "catalog",
|
|
275
|
+
title: "Manage the catalog",
|
|
276
|
+
detail: "Create and edit products and categories by chatting."
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: "sales",
|
|
280
|
+
title: "Understand your sales",
|
|
281
|
+
detail: `"What was this week's revenue?"`
|
|
282
|
+
}
|
|
283
|
+
];
|
|
284
|
+
var EN_US_AI_PERMISSION_MODEL = "The assistant acts on your behalf with exactly your permissions: it can do what you can do in your store \u2014 and nothing beyond that. There is no key or extra credential to create; the authorisation uses your own login.";
|
|
285
|
+
function EN_US_AI_CONNECT_PROMPT(spec) {
|
|
286
|
+
return `You now have access to my store's MCP connector. Do the following, in order:
|
|
287
|
+
1) Run the ${spec.announceTool} tool, saying which assistant you are (host: "chatgpt", "claude" or "codex"), to register the connection with my store.
|
|
288
|
+
2) Run the ${spec.probeTool} tool to confirm access to ${spec.probeSubject}.
|
|
289
|
+
If you need the store identifier, ask me for the ${spec.identifierName}.`;
|
|
290
|
+
}
|
|
291
|
+
__name(EN_US_AI_CONNECT_PROMPT, "EN_US_AI_CONNECT_PROMPT");
|
|
292
|
+
|
|
293
|
+
// src/locales.ts
|
|
294
|
+
var AI_HOST_GUIDES = {
|
|
295
|
+
"pt-BR": PT_BR_AI_HOST_GUIDES,
|
|
296
|
+
"en-US": EN_US_AI_HOST_GUIDES
|
|
297
|
+
};
|
|
298
|
+
var AI_CONNECT_PROMPT = {
|
|
299
|
+
"pt-BR": PT_BR_AI_CONNECT_PROMPT,
|
|
300
|
+
"en-US": EN_US_AI_CONNECT_PROMPT
|
|
301
|
+
};
|
|
302
|
+
var AI_CAPABILITIES = {
|
|
303
|
+
"pt-BR": PT_BR_AI_CAPABILITIES,
|
|
304
|
+
"en-US": EN_US_AI_CAPABILITIES
|
|
305
|
+
};
|
|
306
|
+
var AI_PERMISSION_MODEL = {
|
|
307
|
+
"pt-BR": PT_BR_AI_PERMISSION_MODEL,
|
|
308
|
+
"en-US": EN_US_AI_PERMISSION_MODEL
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
export {
|
|
312
|
+
PT_BR_AI_HOST_GUIDES,
|
|
313
|
+
PT_BR_AI_CAPABILITIES,
|
|
314
|
+
PT_BR_AI_PERMISSION_MODEL,
|
|
315
|
+
PT_BR_AI_CONNECT_PROMPT,
|
|
316
|
+
EN_US_AI_HOST_GUIDES,
|
|
317
|
+
EN_US_AI_CAPABILITIES,
|
|
318
|
+
EN_US_AI_PERMISSION_MODEL,
|
|
319
|
+
EN_US_AI_CONNECT_PROMPT,
|
|
320
|
+
AI_HOST_GUIDES,
|
|
321
|
+
AI_CONNECT_PROMPT,
|
|
322
|
+
AI_CAPABILITIES,
|
|
323
|
+
AI_PERMISSION_MODEL
|
|
324
|
+
};
|
|
325
|
+
//# sourceMappingURL=chunk-WUNMAHQG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pt-BR.ts","../src/en-US.ts","../src/locales.ts"],"sourcesContent":["import type {\n AiCapability,\n AiConnectPromptSpec,\n AiHostConfigureStage,\n AiHostGuide,\n AiPermissionModel,\n} from \"./guide\";\n\n/**\n * The pt-BR pack for the AI-integration surface — NAMED constants a host passes\n * by hand, never defaults (FUT-760).\n *\n * The filename is what exempts this file from the copy-portability gate:\n * Portuguese may ship, it may not be silent. Every sentence here is VERBATIM\n * what `guide.ts` used to compile in, so a host adopting it sees no change on\n * screen — what changes is that the walkthrough is chosen in a diff.\n *\n * The guides are DATA as much as copy: which assistants are offered, their\n * stage ids and brands. Both halves travel together because a step label and\n * the stage it labels are useless apart.\n */\n\nconst CONNECTOR_TAIL: readonly string[] = [\n \"Deixe OAuth Client ID e Client Secret em branco — não é preciso gerar credenciais: a loja registra o conector automaticamente no primeiro acesso.\",\n \"Confirme e clique em Connect: abre a tela de login da loja — entre com a SUA conta de lojista e autorize o acesso.\",\n \"Pronto: ative o conector na conversa para o assistente consultar e operar a sua loja.\",\n];\n\n/**\n * ChatGPT's two-stage configuration (Developer mode is now required before a\n * connector can be created). Stage 1 enables Developer mode in Security & login;\n * stage 2 creates the connector and signs in — which registers the connection on\n * the store side, so no prompt needs to be pasted afterwards.\n */\nfunction chatgptConfigureStages(\n platformName: string,\n): readonly AiHostConfigureStage[] {\n return [\n {\n id: \"enable-dev-mode\",\n label: \"enable developer mode\",\n link: {\n url: \"https://chatgpt.com/plugins#settings/Security\",\n label: \"Abrir Segurança e login\",\n },\n steps: [\n \"Ative o Modo desenvolvedor em Settings › Security and login (Segurança e login).\",\n ],\n },\n {\n id: \"configurar\",\n label: \"configurar\",\n link: {\n url: \"https://chatgpt.com/plugins#settings/Connectors?create-connector=true&redirectAfter=%2Fplugins\",\n label: \"Criar o conector\",\n },\n steps: [\n \"Isso vai abrir um popup para você criar um plugin novo. Coloque como nome o nome da sua loja e, no campo MCP, o link copiado no passo anterior.\",\n 'Marque a caixa \"I understand and want to continue\" — a OpenAI não revisou este servidor MCP; ela avisa que sites podem tentar roubar seus dados ou induzir o modelo a ações indevidas, incluindo destruir dados.',\n `Clique em \"Sign in with ${platformName}\" e entre com a sua conta de lojista para autorizar o acesso. Pronto: a conexão é registrada automaticamente.`,\n ],\n },\n ];\n}\n\n/**\n * The AI hosts a store owner can connect, in recommended order. Same OAuth flow\n * everywhere (the host drives it) — only the menu path differs per app.\n *\n * A FUNCTION of the platform's name, because one step is not generic: the\n * ChatGPT connector's consent screen shows an OAuth button labelled with\n * whoever operates the server, and the owner is told which button to click. It\n * used to name one particular STORE on one particular deployment — not even the\n * product, a tenant of it — so every other adopter instructed its owners to\n * click a button that does not exist.\n */\nexport function PT_BR_AI_HOST_GUIDES(platformName: string): readonly AiHostGuide[] {\n const chatgptStages = chatgptConfigureStages(platformName);\n return [\n {\n id: \"claude\",\n label: \"Claude.ai\",\n brand: \"claude\",\n kind: \"No navegador\",\n link: {\n url: \"https://claude.ai/new?modal=add-custom-connector#settings/customize-connectors\",\n label: \"Abrir os conectores do Claude\",\n },\n docs: {\n url: \"https://support.anthropic.com/en/articles/11175166-how-do-i-connect-mcp-servers-to-claude-ai\",\n label: \"documentação oficial da Anthropic — conectores personalizados\",\n },\n steps: [\n \"Clique no botão acima (ou vá em Settings › Customize › Connectors) e escolha Add custom connector.\",\n \"Dê um nome ao conector (ex.: o nome da sua loja) e cole a URL do servidor MCP da sua loja (copie acima) no campo de URL.\",\n ...CONNECTOR_TAIL,\n ],\n },\n {\n id: \"claude-desktop\",\n label: \"Claude Desktop\",\n brand: \"claude\",\n kind: \"Aplicativo (Windows/Mac)\",\n docs: {\n url: \"https://support.anthropic.com/en/articles/11175166-how-do-i-connect-mcp-servers-to-claude-ai\",\n label: \"documentação oficial da Anthropic — conectores personalizados\",\n },\n steps: [\n \"Abra o Claude Desktop e vá em Settings (⚙️) › Connectors.\",\n \"Clique em Add custom connector e cole a URL do servidor MCP da sua loja (copie acima).\",\n ...CONNECTOR_TAIL,\n ],\n },\n {\n id: \"chatgpt\",\n label: \"ChatGPT\",\n brand: \"openai\",\n kind: \"No navegador\",\n link: {\n url: \"https://chatgpt.com/plugins\",\n label: \"Abrir os plugins do ChatGPT\",\n },\n docs: {\n url: \"https://developers.openai.com/apps-sdk/deploy/connect-chatgpt\",\n label:\n \"documentação oficial da OpenAI — conectar um servidor MCP ao ChatGPT\",\n },\n configureStages: chatgptStages,\n // Mirrors the flattened stage instructions so the MCP connect guide\n // (`connectToChatGpt`) can never drift from what owners see in the wizard.\n steps: chatgptStages.flatMap((stage) => stage.steps),\n },\n {\n id: \"codex\",\n label: \"Codex\",\n brand: \"openai\",\n kind: \"App / CLI de desenvolvedor\",\n link: {\n url: \"https://developers.openai.com/codex\",\n label: \"Documentação do Codex\",\n },\n docs: {\n url: \"https://developers.openai.com/apps-sdk/deploy/connect-chatgpt\",\n label: \"documentação oficial da OpenAI — conectar um servidor MCP\",\n },\n steps: [\n \"No Codex, abra as configurações de MCP (Settings › MCP no app, ou o arquivo de configuração na CLI).\",\n \"Adicione um servidor MCP e cole a URL do servidor MCP da sua loja (copie acima) como um conector remoto (HTTP).\",\n ...CONNECTOR_TAIL,\n ],\n },\n ];\n}\n\nexport const PT_BR_AI_CAPABILITIES: readonly AiCapability[] = [\n {\n id: \"orders\",\n title: \"Acompanhe seus pedidos\",\n detail: '\"Quais pedidos entraram hoje?\"',\n },\n {\n id: \"inventory\",\n title: \"Controle o estoque\",\n detail:\n '\"Quanto ainda tenho do produto X? Registre a entrada de 20 unidades.\"',\n },\n {\n id: \"catalog\",\n title: \"Gerencie o catálogo\",\n detail: \"Crie e edite produtos e categorias conversando.\",\n },\n {\n id: \"sales\",\n title: \"Entenda suas vendas\",\n detail: '\"Qual foi o faturamento da semana?\"',\n },\n];\n\n/**\n * The permission model in one line, shown prominently: the assistant acts AS\n * the signed-in owner (auth-passthrough) — it can do exactly what the owner\n * can, nothing more, and no extra credential/API key is ever created.\n */\nexport const PT_BR_AI_PERMISSION_MODEL: AiPermissionModel =\n \"O assistente age em seu nome, com exatamente as suas permissões: ele pode fazer o que você pode fazer na sua loja — nada além disso. Não é preciso criar nenhuma chave ou credencial extra; a autorização usa o seu próprio login.\";\n\n/** The pt-BR paste-in prompt, built from the host's own tool names. */\nexport function PT_BR_AI_CONNECT_PROMPT(spec: AiConnectPromptSpec): string {\n return (\n \"Você agora tem acesso ao conector MCP da minha loja. Faça, nesta ordem:\\n\" +\n `1) Execute a ferramenta ${spec.announceTool} informando qual assistente você é (host: \"chatgpt\", \"claude\" ou \"codex\") para registrar a conexão com a minha loja.\\n` +\n `2) Execute a ferramenta ${spec.probeTool} para confirmar o acesso a ${spec.probeSubject}.\\n` +\n `Se precisar do identificador da loja, me pergunte o ${spec.identifierName}.`\n );\n}\n","import type {\n AiCapability,\n AiConnectPromptSpec,\n AiHostConfigureStage,\n AiHostGuide,\n AiPermissionModel,\n} from \"./guide\";\n\n/**\n * The en-US pack for the AI-integration surface — NAMED constants a host passes\n * by hand, never defaults.\n *\n * The guides are DATA as much as copy: which assistants are offered, their\n * stage ids, their brands and their LINKS. Both halves travel together because\n * a step label and the stage it labels are useless apart — and the parts that\n * are not words do not change between languages:\n *\n * - `id` and `brand` are the package's own keys, matched on by the component;\n * - the URLs point at Anthropic's and OpenAI's own pages;\n * - the UI labels a reader must FIND in those products stay in the product's\n * own English (`Add custom connector`, `Settings › Security and login`,\n * `Sign in with …`), which is the same rule that keeps a vendor's field name\n * untranslated everywhere else here.\n *\n * The pt-BR pack quotes those same labels in English for exactly this reason;\n * what differs between the two packs is the instruction around them.\n */\n\nconst CONNECTOR_TAIL: readonly string[] = [\n \"Leave OAuth Client ID and Client Secret blank — there are no credentials to generate: the store registers the connector automatically on first access.\",\n \"Confirm and click Connect: the store's sign-in screen opens — sign in with YOUR own owner account and authorise the access.\",\n \"Done: enable the connector in the chat so the assistant can query and operate your store.\",\n];\n\n/**\n * ChatGPT's two-stage configuration (Developer mode is now required before a\n * connector can be created). Stage 1 enables Developer mode in Security & login;\n * stage 2 creates the connector and signs in — which registers the connection on\n * the store side, so no prompt needs to be pasted afterwards.\n */\nfunction chatgptConfigureStages(\n platformName: string,\n): readonly AiHostConfigureStage[] {\n return [\n {\n id: \"enable-dev-mode\",\n label: \"enable developer mode\",\n link: {\n url: \"https://chatgpt.com/plugins#settings/Security\",\n label: \"Open Security and login\",\n },\n steps: [\n \"Turn on Developer mode under Settings › Security and login.\",\n ],\n },\n {\n id: \"configurar\",\n label: \"configure\",\n link: {\n url: \"https://chatgpt.com/plugins#settings/Connectors?create-connector=true&redirectAfter=%2Fplugins\",\n label: \"Create the connector\",\n },\n steps: [\n \"That opens a popup to create a new plugin. Give it your store's name, and put the link you copied in the previous step in the MCP field.\",\n 'Tick \"I understand and want to continue\" — OpenAI has not reviewed this MCP server; they warn that sites may try to steal your data or push the model into harmful actions, including destroying data.',\n `Click \"Sign in with ${platformName}\" and sign in with your owner account to authorise access. That is it: the connection is registered automatically.`,\n ],\n },\n ];\n}\n\n/**\n * The AI hosts a store owner can connect, in recommended order. Same OAuth flow\n * everywhere (the host drives it) — only the menu path differs per app.\n *\n * A FUNCTION of the platform's name, because one step is not generic: the\n * ChatGPT connector's consent screen shows an OAuth button labelled with\n * whoever operates the server, and the owner is told which button to click. It\n * used to name one particular STORE on one particular deployment — not even the\n * product, a tenant of it — so every other adopter instructed its owners to\n * click a button that does not exist.\n */\nexport function EN_US_AI_HOST_GUIDES(platformName: string): readonly AiHostGuide[] {\n const chatgptStages = chatgptConfigureStages(platformName);\n return [\n {\n id: \"claude\",\n label: \"Claude.ai\",\n brand: \"claude\",\n kind: \"In the browser\",\n link: {\n url: \"https://claude.ai/new?modal=add-custom-connector#settings/customize-connectors\",\n label: \"Open Claude's connectors\",\n },\n docs: {\n url: \"https://support.anthropic.com/en/articles/11175166-how-do-i-connect-mcp-servers-to-claude-ai\",\n label: \"Anthropic's own documentation — custom connectors\",\n },\n steps: [\n \"Click the button above (or go to Settings › Customize › Connectors) and choose Add custom connector.\",\n \"Name the connector (your store's name works) and paste your store's MCP server URL (copy it above) into the URL field.\",\n ...CONNECTOR_TAIL,\n ],\n },\n {\n id: \"claude-desktop\",\n label: \"Claude Desktop\",\n brand: \"claude\",\n kind: \"App (Windows/Mac)\",\n docs: {\n url: \"https://support.anthropic.com/en/articles/11175166-how-do-i-connect-mcp-servers-to-claude-ai\",\n label: \"Anthropic's own documentation — custom connectors\",\n },\n steps: [\n \"Open Claude Desktop and go to Settings (⚙️) › Connectors.\",\n \"Click Add custom connector and paste your store's MCP server URL (copy it above).\",\n ...CONNECTOR_TAIL,\n ],\n },\n {\n id: \"chatgpt\",\n label: \"ChatGPT\",\n brand: \"openai\",\n kind: \"In the browser\",\n link: {\n url: \"https://chatgpt.com/plugins\",\n label: \"Open ChatGPT's plugins\",\n },\n docs: {\n url: \"https://developers.openai.com/apps-sdk/deploy/connect-chatgpt\",\n label: \"OpenAI's own documentation — connecting an MCP server to ChatGPT\",\n },\n configureStages: chatgptStages,\n // Mirrors the flattened stage instructions so the MCP connect guide\n // (`connectToChatGpt`) can never drift from what owners see in the wizard.\n steps: chatgptStages.flatMap((stage) => stage.steps),\n },\n {\n id: \"codex\",\n label: \"Codex\",\n brand: \"openai\",\n kind: \"Developer app / CLI\",\n link: {\n url: \"https://developers.openai.com/codex\",\n label: \"Codex documentation\",\n },\n docs: {\n url: \"https://developers.openai.com/apps-sdk/deploy/connect-chatgpt\",\n label: \"OpenAI's own documentation — connecting an MCP server\",\n },\n steps: [\n \"In Codex, open the MCP settings (Settings › MCP in the app, or the config file on the CLI).\",\n \"Add an MCP server and paste your store's MCP server URL (copy it above) as a remote (HTTP) connector.\",\n ...CONNECTOR_TAIL,\n ],\n },\n ];\n}\n\nexport const EN_US_AI_CAPABILITIES: readonly AiCapability[] = [\n // The `detail` of each is a QUESTION a reader could paste verbatim, so it is\n // written as one rather than described.\n {\n id: \"orders\",\n title: \"Follow your orders\",\n detail: '\"Which orders came in today?\"',\n },\n {\n id: \"inventory\",\n title: \"Keep on top of stock\",\n detail: '\"How much of product X is left? Record 20 units received.\"',\n },\n {\n id: \"catalog\",\n title: \"Manage the catalog\",\n detail: \"Create and edit products and categories by chatting.\",\n },\n {\n id: \"sales\",\n title: \"Understand your sales\",\n detail: '\"What was this week\\'s revenue?\"',\n },\n];\n\n/**\n * The permission model in one line, shown prominently: the assistant acts AS\n * the signed-in owner (auth-passthrough) — it can do exactly what the owner\n * can, nothing more, and no extra credential/API key is ever created.\n */\nexport const EN_US_AI_PERMISSION_MODEL: AiPermissionModel =\n \"The assistant acts on your behalf with exactly your permissions: it can do what you can do in your store — and nothing beyond that. There is no key or extra credential to create; the authorisation uses your own login.\";\n\n/** The en-US paste-in prompt, built from the host's own tool names. */\nexport function EN_US_AI_CONNECT_PROMPT(spec: AiConnectPromptSpec): string {\n // The TOOL NAMES are the host's own identifiers and are interpolated, never\n // translated: the assistant has to call them by the name they are registered\n // under, so a translated verb here is a prompt that does nothing.\n return (\n \"You now have access to my store's MCP connector. Do the following, in order:\\n\" +\n `1) Run the ${spec.announceTool} tool, saying which assistant you are (host: \"chatgpt\", \"claude\" or \"codex\"), to register the connection with my store.\\n` +\n `2) Run the ${spec.probeTool} tool to confirm access to ${spec.probeSubject}.\\n` +\n `If you need the store identifier, ask me for the ${spec.identifierName}.`\n );\n}\n","import {\n EN_US_AI_CAPABILITIES,\n EN_US_AI_CONNECT_PROMPT,\n EN_US_AI_HOST_GUIDES,\n EN_US_AI_PERMISSION_MODEL,\n} from \"./en-US\";\nimport type {\n AiCapability,\n AiConnectPromptSpec,\n AiHostGuide,\n AiPermissionModel,\n} from \"./guide\";\nimport {\n PT_BR_AI_CAPABILITIES,\n PT_BR_AI_CONNECT_PROMPT,\n PT_BR_AI_HOST_GUIDES,\n PT_BR_AI_PERMISSION_MODEL,\n} from \"./pt-BR\";\n\n/**\n * The AI-integration surface in both languages, keyed by tag — what a host\n * hands to `@12-apps/i18n` when the reader's language is a property of the\n * request rather than of the deployment.\n *\n * Two of these are FUNCTIONS rather than tables, and stay so:\n *\n * - `AI_HOST_GUIDES` takes the platform's name, because the ChatGPT consent\n * screen shows an OAuth button labelled with whoever operates the server and\n * the owner is told which button to click. It once named one particular\n * tenant of one deployment, so every other adopter instructed its owners to\n * click a button that does not exist.\n * - `AI_CONNECT_PROMPT` takes the host's own tool names, which the assistant\n * must call by the name they are registered under.\n *\n * `LocalePack` is mirrored here rather than imported so the package stays\n * liftable into a repo that has never heard of `@12-apps/i18n`.\n */\ntype LocalePack<T> = { readonly \"pt-BR\": T; readonly \"en-US\": T };\n\nexport const AI_HOST_GUIDES = {\n \"pt-BR\": PT_BR_AI_HOST_GUIDES,\n \"en-US\": EN_US_AI_HOST_GUIDES,\n} as const satisfies LocalePack<(platformName: string) => readonly AiHostGuide[]>;\n\nexport const AI_CONNECT_PROMPT = {\n \"pt-BR\": PT_BR_AI_CONNECT_PROMPT,\n \"en-US\": EN_US_AI_CONNECT_PROMPT,\n} as const satisfies LocalePack<(spec: AiConnectPromptSpec) => string>;\n\nexport const AI_CAPABILITIES = {\n \"pt-BR\": PT_BR_AI_CAPABILITIES,\n \"en-US\": EN_US_AI_CAPABILITIES,\n} as const satisfies LocalePack<readonly AiCapability[]>;\n\nexport const AI_PERMISSION_MODEL = {\n \"pt-BR\": PT_BR_AI_PERMISSION_MODEL,\n \"en-US\": EN_US_AI_PERMISSION_MODEL,\n} as const satisfies LocalePack<AiPermissionModel>;\n"],"mappings":"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","names":["CONNECTOR_TAIL","chatgptConfigureStages"]}
|
|
@@ -644,4 +644,4 @@ interface ApiMcpOauth {
|
|
|
644
644
|
}
|
|
645
645
|
declare function createApiMcpOauth(config: McpOauthConfig): ApiMcpOauth;
|
|
646
646
|
|
|
647
|
-
export { trustedOriginsFromEnv as $, type ApiMcpOauth as A, type StoredMcpConnection as B, type CodeReplayStore as C, DEFAULT_MCP_RESOURCE_PATH as D, type VerifyAccessTokenOptions as E, createApiMcpOauth as F, hashSecret as G, inProcessCodeReplayStore as H, issuer as I, loadSigningKeyFromEnv as J, matchesRedirectUri as K, originFromRequest as L, type McpOauthConfig as M, type NewOAuthClient as N, type OAuthClientStore as O, type ProviderAttributionRule as P, providerFromRedirectUris as Q, type RefreshTokenStore as R, type StoredOAuthClient as S, type TokenEndpointAuthMethod as T, registerClient as U, type VerifiedAccessToken as V, resolveMcpOauthConfig as W, resolveTrustedOrigin as X, resourceAudience as Y, signAccessToken as Z, signingKeyProvider as _, type
|
|
647
|
+
export { trustedOriginsFromEnv as $, type ApiMcpOauth as A, type StoredMcpConnection as B, type CodeReplayStore as C, DEFAULT_MCP_RESOURCE_PATH as D, type VerifyAccessTokenOptions as E, createApiMcpOauth as F, hashSecret as G, inProcessCodeReplayStore as H, issuer as I, loadSigningKeyFromEnv as J, matchesRedirectUri as K, originFromRequest as L, type McpOauthConfig as M, type NewOAuthClient as N, type OAuthClientStore as O, type ProviderAttributionRule as P, providerFromRedirectUris as Q, type RefreshTokenStore as R, type StoredOAuthClient as S, type TokenEndpointAuthMethod as T, registerClient as U, type VerifiedAccessToken as V, resolveMcpOauthConfig as W, resolveTrustedOrigin as X, resourceAudience as Y, signAccessToken as Z, signingKeyProvider as _, type McpOauthRoute as a, verifyAccessToken as a0, type McpSigningKeyProvider as b, type NewRefreshToken as c, type StoredRefreshToken as d, type McpOauthStores as e, type McpConnectionStore as f, ACCESS_TOKEN_TTL_SECONDS as g, AccessTokenError as h, type AccessTokenErrorCode as i, DEFAULT_OAUTH_PATHS as j, DEFAULT_PROVIDER_ROOTS as k, DEFAULT_SIGNING_KEY_ENV as l, DEFAULT_SIGNING_KEY_ID_ENV as m, MCP_SUPPORTED_SCOPES as n, type McpConnectionRecording as o, type McpOauthContext as p, type McpOauthHandlers as q, type McpOauthPaths as r, type McpOauthSession as s, type McpScope as t, type McpSigningKey as u, type PublicSigningJwk as v, type RegisterClientInput as w, type RegisteredClient as x, SIGNING_ALG as y, type SignAccessTokenInput as z };
|
package/dist/hono/index.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { J as JsonSchema, G as GeneratedTool, D as DispatchConfig, a as Dispatch
|
|
|
2
2
|
export { A as AuthResolver, c as GenerateOptions, O as OpenApiDocument, d as OpenApiOperation, e as OpenApiParameter, f as OpenApiRequestBody, g as OpenApiResponse, P as ParameterLocation, h as ToolParameter, i as generateTools } from './generate-Dx3cK8th.js';
|
|
3
3
|
export { A as AiCapability, a as AiConnectPromptCopy, b as AiConnectPromptSpec, c as AiHostBrand, d as AiHostConfigureStage, e as AiHostGuide, f as AiHostLink, g as AiProvider, h as aiConnectPrompt, p as providerForHostId } from './guide-KQNcXlMG.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
export { P as PT_BR_AI_CAPABILITIES,
|
|
5
|
+
export { A as AI_CAPABILITIES, a as AI_CONNECT_PROMPT, b as AI_HOST_GUIDES, c as AI_PERMISSION_MODEL, E as EN_US_AI_CAPABILITIES, d as EN_US_AI_CONNECT_PROMPT, e as EN_US_AI_HOST_GUIDES, f as EN_US_AI_PERMISSION_MODEL, P as PT_BR_AI_CAPABILITIES, g as PT_BR_AI_CONNECT_PROMPT, h as PT_BR_AI_HOST_GUIDES, i as PT_BR_AI_PERMISSION_MODEL } from './locales-eKE_OJw4.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Raised when a JSON Schema cannot be turned into a flat, self-contained tool
|