@geekapps/auth-nextjs 0.11.0 → 0.13.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.
@@ -1,163 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/cli/generate-connections.ts
4
- import { writeFileSync } from "fs";
5
- import { basename, resolve } from "path";
6
- var DEFAULT_ISSUER = "https://accounts-api.geekapps.com.br";
7
- function env(name) {
8
- const value = process.env[name];
9
- return value && value.trim().length > 0 ? value : void 0;
10
- }
11
- function fail(message) {
12
- console.error(`
13
- \u2717 ${message}
14
- `);
15
- process.exit(1);
16
- }
17
- function toIdentifier(raw, fallback) {
18
- const cleaned = raw.normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-zA-Z0-9]+/g, " ").trim();
19
- if (!cleaned) return fallback;
20
- const [first, ...rest] = cleaned.split(" ");
21
- const name = first.toLowerCase() + rest.map((w) => w[0].toUpperCase() + w.slice(1).toLowerCase()).join("");
22
- return /^[0-9]/.test(name) ? `app${name[0].toUpperCase()}${name.slice(1)}` : name;
23
- }
24
- function actionIdentifier(key, appPrefix) {
25
- const withoutPrefix = key.startsWith(`${appPrefix}.`) ? key.slice(appPrefix.length + 1) : key;
26
- return toIdentifier(withoutPrefix, "action");
27
- }
28
- function quoteKey(key) {
29
- return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
30
- }
31
- function toTypeScript(schema, indent) {
32
- if (!schema) return "unknown";
33
- switch (schema.type) {
34
- case "string":
35
- return schema.enum?.length ? schema.enum.map((v) => JSON.stringify(v)).join(" | ") : "string";
36
- case "number":
37
- case "integer":
38
- return "number";
39
- case "boolean":
40
- return "boolean";
41
- case "array":
42
- return `Array<${toTypeScript(schema.items, indent)}>`;
43
- case "object": {
44
- const entries = Object.entries(schema.properties ?? {});
45
- if (entries.length === 0) {
46
- return schema.additionalProperties === false ? "Record<string, never>" : "Record<string, unknown>";
47
- }
48
- const required = new Set(schema.required ?? []);
49
- const inner = `${indent} `;
50
- const lines = entries.map(([name, prop]) => {
51
- const doc = prop.description ? `${inner}/** ${prop.description} */
52
- ` : "";
53
- const optional = required.has(name) ? "" : "?";
54
- return `${doc}${inner}${quoteKey(name)}${optional}: ${toTypeScript(prop, inner)};`;
55
- });
56
- return `{
57
- ${lines.join("\n")}
58
- ${indent}}`;
59
- }
60
- }
61
- }
62
- async function main() {
63
- const issuer = (env("GEEKAPPS_AUTH_SERVER_ISSUER") ?? env("GEEKAPPS_AUTH_SERVER_URL") ?? DEFAULT_ISSUER).replace(/\/$/, "");
64
- const clientId = env("GEEKAPPS_AUTH_CLIENT_ID");
65
- const clientSecret = env("GEEKAPPS_AUTH_CLIENT_SECRET");
66
- if (!clientId || !clientSecret) {
67
- fail(
68
- "GEEKAPPS_AUTH_CLIENT_ID e GEEKAPPS_AUTH_CLIENT_SECRET precisam estar definidos \u2014 o gerador busca as conex\xF5es desta app com essas credenciais."
69
- );
70
- }
71
- const outArg = process.argv.indexOf("--out");
72
- const outPath = resolve(
73
- process.cwd(),
74
- outArg !== -1 && process.argv[outArg + 1] ? process.argv[outArg + 1] : "geekapps-connections.ts"
75
- );
76
- const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
77
- const response = await fetch(`${issuer}/connections/catalog`, {
78
- headers: { authorization: `Basic ${credentials}` }
79
- }).catch((error) => fail(`nao consegui falar com o auth-server em ${issuer}: ${error.message}`));
80
- if (!response.ok) {
81
- const detail = await response.text().catch(() => "");
82
- fail(`auth-server respondeu ${response.status} ao listar as conexoes. ${detail}`);
83
- }
84
- const connections = await response.json();
85
- const active = connections.filter((c) => c.status === "active");
86
- if (active.length === 0) {
87
- console.warn(
88
- "\n! Nenhuma conexao ativa encontrada para esta app. O arquivo sera gerado vazio \u2014 peca ao admin para aprovar uma conexao no dashboard."
89
- );
90
- }
91
- const typeBlocks = [];
92
- const interfaceEntries = [];
93
- const registryEntries = [];
94
- const usedNames = /* @__PURE__ */ new Map();
95
- for (const connection of active) {
96
- const base = toIdentifier(connection.targetApp.name, "app");
97
- const seen = usedNames.get(base) ?? 0;
98
- usedNames.set(base, seen + 1);
99
- const appName = seen === 0 ? base : `${base}${seen + 1}`;
100
- const granted = connection.actions.filter((a) => connection.scopes.includes(a.key));
101
- const methods = [];
102
- const actionMap = [];
103
- for (const action of granted) {
104
- const name = actionIdentifier(action.key, base);
105
- const payload = toTypeScript(action.payloadSchema, " ");
106
- const result = toTypeScript(action.responseSchema, " ");
107
- const arg = action.payloadSchema ? `payload: ${payload}` : "payload?: unknown";
108
- methods.push(
109
- ` /**
110
- * ${action.label}
111
- *
112
- * \`${action.method} ${action.path}\` \u2014 ${action.key}
113
- */
114
- ${name}(${arg}): Promise<${result}>;`
115
- );
116
- actionMap.push(` ${quoteKey(name)}: ${JSON.stringify(action.key)},`);
117
- }
118
- const typeName = `${appName[0].toUpperCase()}${appName.slice(1)}Connection`;
119
- typeBlocks.push(
120
- `/** ${connection.targetApp.name} \u2014 ${granted.length} acao(oes) liberada(s) nesta conexao. */
121
- export interface ${typeName} {
122
- ${methods.join("\n\n") || " // nenhuma acao liberada"}
123
- }`
124
- );
125
- interfaceEntries.push(` ${quoteKey(appName)}: ${typeName};`);
126
- registryEntries.push(
127
- ` ${quoteKey(appName)}: {
128
- appId: ${JSON.stringify(connection.targetAppId)},
129
- actions: {
130
- ${actionMap.join("\n")}
131
- },
132
- },`
133
- );
134
- console.log(`\u2713 ${connection.targetApp.name} \u2192 ${appName} (${granted.length} acoes)`);
135
- }
136
- const file = `// Gerado por \`npx geekapps-connections\`. Nao edite a mao.
137
- // Rode de novo quando uma conexao for aprovada ou as acoes da app alvo mudarem.
138
- // Gerado em ${(/* @__PURE__ */ new Date()).toISOString()}
139
-
140
- import { registerConnections } from "@geekapps/auth-nextjs/connections";
141
-
142
- ${typeBlocks.join("\n\n")}
143
-
144
- declare module "@geekapps/auth-nextjs/connections" {
145
- interface GeekappsConnections {
146
- ${interfaceEntries.join("\n")}
147
- }
148
- }
149
-
150
- registerConnections({
151
- ${registryEntries.join("\n")}
152
- });
153
- `;
154
- writeFileSync(outPath, file, "utf-8");
155
- console.log(`
156
- \u2192 ${outPath}
157
- `);
158
- console.log("Importe o arquivo uma vez no boot da app (ex: instrumentation.ts ou o layout raiz):");
159
- console.log(` import "./${basename(outPath)}";
160
- `);
161
- }
162
- main().catch((error) => fail(error.message));
163
- //# sourceMappingURL=generate-connections.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/cli/generate-connections.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `npx geekapps-connections` — gera o catálogo tipado de App Connections.\n *\n * Busca no auth-server as conexões ativas em que esta app é a consumidora,\n * junto das ações liberadas em cada uma, e escreve UM arquivo .ts contendo:\n * - os tipos de payload/retorno de cada ação (a partir dos JSON Schemas que\n * a app alvo declarou);\n * - a interface GeekappsConnections, por declaration merging;\n * - o registry runtime (nome amigável → client_id / AppAction.key).\n *\n * O arquivo é gerado, não editado à mão: rode de novo quando o admin aprovar\n * uma conexão nova ou a app alvo mudar suas ações.\n */\n\nimport { writeFileSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\n\ntype JsonSchema =\n | { type: \"string\"; enum?: string[]; description?: string }\n | { type: \"number\" | \"integer\" | \"boolean\"; description?: string }\n | { type: \"array\"; items: JsonSchema; description?: string }\n | {\n type: \"object\";\n properties?: Record<string, JsonSchema>;\n required?: string[];\n additionalProperties?: boolean;\n description?: string;\n };\n\ntype RemoteAction = {\n key: string;\n label: string;\n method: string;\n path: string;\n payloadSchema: JsonSchema | null;\n responseSchema: JsonSchema | null;\n};\n\ntype RemoteConnection = {\n targetAppId: string;\n targetApp: { name: string };\n status: string;\n scopes: string[];\n actions: RemoteAction[];\n};\n\nconst DEFAULT_ISSUER = \"https://accounts-api.geekapps.com.br\";\n\nfunction env(name: string) {\n const value = process.env[name];\n return value && value.trim().length > 0 ? value : undefined;\n}\n\nfunction fail(message: string): never {\n console.error(`\\n✗ ${message}\\n`);\n process.exit(1);\n}\n\n/** `Billing App` / `billing-api` → `billingApp` / `billingApi`. */\nfunction toIdentifier(raw: string, fallback: string) {\n const cleaned = raw\n .normalize(\"NFD\")\n .replace(/[̀-ͯ]/g, \"\")\n .replace(/[^a-zA-Z0-9]+/g, \" \")\n .trim();\n if (!cleaned) return fallback;\n\n const [first, ...rest] = cleaned.split(\" \");\n const name = first.toLowerCase() + rest.map((w) => w[0].toUpperCase() + w.slice(1).toLowerCase()).join(\"\");\n return /^[0-9]/.test(name) ? `app${name[0].toUpperCase()}${name.slice(1)}` : name;\n}\n\n/**\n * `billing.charges.create` → `chargesCreate`. O prefixo da app (convenção das\n * AppAction.key) sai fora porque o nome já vem qualificado pela app na cadeia:\n * `billing.chargesCreate`, não `billing.billingChargesCreate`.\n */\nfunction actionIdentifier(key: string, appPrefix: string) {\n const withoutPrefix = key.startsWith(`${appPrefix}.`) ? key.slice(appPrefix.length + 1) : key;\n return toIdentifier(withoutPrefix, \"action\");\n}\n\nfunction quoteKey(key: string) {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key);\n}\n\n/** JSON Schema → tipo TypeScript. Espelha o subset aceito em app-action-schema.ts. */\nfunction toTypeScript(schema: JsonSchema | null, indent: string): string {\n if (!schema) return \"unknown\";\n\n switch (schema.type) {\n case \"string\":\n return schema.enum?.length ? schema.enum.map((v) => JSON.stringify(v)).join(\" | \") : \"string\";\n case \"number\":\n case \"integer\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"array\":\n return `Array<${toTypeScript(schema.items, indent)}>`;\n case \"object\": {\n const entries = Object.entries(schema.properties ?? {});\n if (entries.length === 0) {\n return schema.additionalProperties === false ? \"Record<string, never>\" : \"Record<string, unknown>\";\n }\n const required = new Set(schema.required ?? []);\n const inner = `${indent} `;\n const lines = entries.map(([name, prop]) => {\n const doc = prop.description ? `${inner}/** ${prop.description} */\\n` : \"\";\n const optional = required.has(name) ? \"\" : \"?\";\n return `${doc}${inner}${quoteKey(name)}${optional}: ${toTypeScript(prop, inner)};`;\n });\n return `{\\n${lines.join(\"\\n\")}\\n${indent}}`;\n }\n }\n}\n\nasync function main() {\n const issuer = (\n env(\"GEEKAPPS_AUTH_SERVER_ISSUER\") ??\n env(\"GEEKAPPS_AUTH_SERVER_URL\") ??\n DEFAULT_ISSUER\n ).replace(/\\/$/, \"\");\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\");\n const clientSecret = env(\"GEEKAPPS_AUTH_CLIENT_SECRET\");\n\n if (!clientId || !clientSecret) {\n fail(\n \"GEEKAPPS_AUTH_CLIENT_ID e GEEKAPPS_AUTH_CLIENT_SECRET precisam estar definidos — o gerador busca as conexões desta app com essas credenciais.\",\n );\n }\n\n const outArg = process.argv.indexOf(\"--out\");\n const outPath = resolve(\n process.cwd(),\n outArg !== -1 && process.argv[outArg + 1] ? process.argv[outArg + 1] : \"geekapps-connections.ts\",\n );\n\n const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString(\"base64\");\n const response = await fetch(`${issuer}/connections/catalog`, {\n headers: { authorization: `Basic ${credentials}` },\n }).catch((error) => fail(`nao consegui falar com o auth-server em ${issuer}: ${(error as Error).message}`));\n\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n fail(`auth-server respondeu ${response.status} ao listar as conexoes. ${detail}`);\n }\n\n const connections = (await response.json()) as RemoteConnection[];\n const active = connections.filter((c) => c.status === \"active\");\n\n if (active.length === 0) {\n console.warn(\n \"\\n! Nenhuma conexao ativa encontrada para esta app. O arquivo sera gerado vazio — peca ao admin para aprovar uma conexao no dashboard.\",\n );\n }\n\n const typeBlocks: string[] = [];\n const interfaceEntries: string[] = [];\n const registryEntries: string[] = [];\n const usedNames = new Map<string, number>();\n\n for (const connection of active) {\n const base = toIdentifier(connection.targetApp.name, \"app\");\n // Dois apps podem ter nomes que colapsam no mesmo identificador; sufixa\n // para nao gerar propriedades duplicadas na interface.\n const seen = usedNames.get(base) ?? 0;\n usedNames.set(base, seen + 1);\n const appName = seen === 0 ? base : `${base}${seen + 1}`;\n\n // So as acoes efetivamente liberadas na aprovacao da conexao entram no\n // catalogo — o que o SDK oferece e o que de fato vai passar no proxy.\n const granted = connection.actions.filter((a) => connection.scopes.includes(a.key));\n\n const methods: string[] = [];\n const actionMap: string[] = [];\n\n for (const action of granted) {\n const name = actionIdentifier(action.key, base);\n const payload = toTypeScript(action.payloadSchema, \" \");\n const result = toTypeScript(action.responseSchema, \" \");\n const arg = action.payloadSchema ? `payload: ${payload}` : \"payload?: unknown\";\n\n methods.push(\n ` /**\\n * ${action.label}\\n *\\n * \\`${action.method} ${action.path}\\` — ${action.key}\\n */\\n ${name}(${arg}): Promise<${result}>;`,\n );\n actionMap.push(` ${quoteKey(name)}: ${JSON.stringify(action.key)},`);\n }\n\n const typeName = `${appName[0].toUpperCase()}${appName.slice(1)}Connection`;\n typeBlocks.push(\n `/** ${connection.targetApp.name} — ${granted.length} acao(oes) liberada(s) nesta conexao. */\\nexport interface ${typeName} {\\n${methods.join(\"\\n\\n\") || \" // nenhuma acao liberada\"}\\n}`,\n );\n interfaceEntries.push(` ${quoteKey(appName)}: ${typeName};`);\n registryEntries.push(\n ` ${quoteKey(appName)}: {\\n appId: ${JSON.stringify(connection.targetAppId)},\\n actions: {\\n${actionMap.join(\"\\n\")}\\n },\\n },`,\n );\n\n console.log(`✓ ${connection.targetApp.name} → ${appName} (${granted.length} acoes)`);\n }\n\n const file = `// Gerado por \\`npx geekapps-connections\\`. Nao edite a mao.\n// Rode de novo quando uma conexao for aprovada ou as acoes da app alvo mudarem.\n// Gerado em ${new Date().toISOString()}\n\nimport { registerConnections } from \"@geekapps/auth-nextjs/connections\";\n\n${typeBlocks.join(\"\\n\\n\")}\n\ndeclare module \"@geekapps/auth-nextjs/connections\" {\n interface GeekappsConnections {\n${interfaceEntries.join(\"\\n\")}\n }\n}\n\nregisterConnections({\n${registryEntries.join(\"\\n\")}\n});\n`;\n\n writeFileSync(outPath, file, \"utf-8\");\n console.log(`\\n→ ${outPath}\\n`);\n console.log(\"Importe o arquivo uma vez no boot da app (ex: instrumentation.ts ou o layout raiz):\");\n console.log(` import \"./${basename(outPath)}\";\\n`);\n}\n\nmain().catch((error) => fail((error as Error).message));\n"],"mappings":"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","names":[]}