@geekmidas/cli 0.13.0 → 0.14.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/{bundler-B1qy9b-j.cjs → bundler-BjholBlA.cjs} +26 -7
- package/dist/bundler-BjholBlA.cjs.map +1 -0
- package/dist/{bundler-DskIqW2t.mjs → bundler-DWctKN1z.mjs} +27 -8
- package/dist/bundler-DWctKN1z.mjs.map +1 -0
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/dokploy-api-B7KxOQr3.cjs +3 -0
- package/dist/dokploy-api-C7F9VykY.cjs +317 -0
- package/dist/dokploy-api-C7F9VykY.cjs.map +1 -0
- package/dist/dokploy-api-CaETb2L6.mjs +305 -0
- package/dist/dokploy-api-CaETb2L6.mjs.map +1 -0
- package/dist/dokploy-api-DHvfmWbi.mjs +3 -0
- package/dist/{encryption-Dyf_r1h-.cjs → encryption-D7Efcdi9.cjs} +1 -1
- package/dist/{encryption-Dyf_r1h-.cjs.map → encryption-D7Efcdi9.cjs.map} +1 -1
- package/dist/{encryption-C8H-38Yy.mjs → encryption-h4Nb6W-M.mjs} +1 -1
- package/dist/{encryption-C8H-38Yy.mjs.map → encryption-h4Nb6W-M.mjs.map} +1 -1
- package/dist/index.cjs +1513 -1136
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1513 -1136
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-Bt_1FDpT.cjs → openapi-C89hhkZC.cjs} +3 -3
- package/dist/{openapi-Bt_1FDpT.cjs.map → openapi-C89hhkZC.cjs.map} +1 -1
- package/dist/{openapi-BfFlOBCG.mjs → openapi-CZVcfxk-.mjs} +3 -3
- package/dist/{openapi-BfFlOBCG.mjs.map → openapi-CZVcfxk-.mjs.map} +1 -1
- package/dist/{openapi-react-query-B6XTeGqS.mjs → openapi-react-query-CM2_qlW9.mjs} +1 -1
- package/dist/{openapi-react-query-B6XTeGqS.mjs.map → openapi-react-query-CM2_qlW9.mjs.map} +1 -1
- package/dist/{openapi-react-query-B-sNWHFU.cjs → openapi-react-query-iKjfLzff.cjs} +1 -1
- package/dist/{openapi-react-query-B-sNWHFU.cjs.map → openapi-react-query-iKjfLzff.cjs.map} +1 -1
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -1
- package/dist/{storage-kSxTjkNb.mjs → storage-BaOP55oq.mjs} +16 -2
- package/dist/storage-BaOP55oq.mjs.map +1 -0
- package/dist/{storage-Bj1E26lU.cjs → storage-Bn3K9Ccu.cjs} +21 -1
- package/dist/storage-Bn3K9Ccu.cjs.map +1 -0
- package/dist/storage-UfyTn7Zm.cjs +7 -0
- package/dist/storage-nkGIjeXt.mjs +3 -0
- package/dist/{types-BhkZc-vm.d.cts → types-BgaMXsUa.d.cts} +3 -1
- package/dist/{types-BR0M2v_c.d.mts.map → types-BgaMXsUa.d.cts.map} +1 -1
- package/dist/{types-BR0M2v_c.d.mts → types-iFk5ms7y.d.mts} +3 -1
- package/dist/{types-BhkZc-vm.d.cts.map → types-iFk5ms7y.d.mts.map} +1 -1
- package/package.json +3 -3
- package/src/auth/__tests__/credentials.spec.ts +127 -0
- package/src/auth/__tests__/index.spec.ts +69 -0
- package/src/auth/credentials.ts +33 -0
- package/src/auth/index.ts +57 -50
- package/src/build/__tests__/bundler.spec.ts +1 -1
- package/src/build/__tests__/endpoint-analyzer.spec.ts +623 -0
- package/src/build/__tests__/handler-templates.spec.ts +272 -0
- package/src/build/bundler.ts +53 -4
- package/src/build/index.ts +21 -0
- package/src/build/types.ts +6 -0
- package/src/deploy/__tests__/dokploy-api.spec.ts +698 -0
- package/src/deploy/__tests__/dokploy.spec.ts +196 -6
- package/src/deploy/__tests__/index.spec.ts +339 -0
- package/src/deploy/__tests__/init.spec.ts +147 -16
- package/src/deploy/docker.ts +32 -3
- package/src/deploy/dokploy-api.ts +581 -0
- package/src/deploy/dokploy.ts +66 -93
- package/src/deploy/index.ts +587 -32
- package/src/deploy/init.ts +192 -249
- package/src/deploy/types.ts +19 -1
- package/src/dev/__tests__/index.spec.ts +95 -0
- package/src/docker/__tests__/templates.spec.ts +144 -0
- package/src/docker/index.ts +96 -6
- package/src/docker/templates.ts +114 -27
- package/src/generators/EndpointGenerator.ts +2 -2
- package/src/index.ts +34 -13
- package/src/secrets/storage.ts +15 -0
- package/src/types.ts +2 -0
- package/dist/bundler-B1qy9b-j.cjs.map +0 -1
- package/dist/bundler-DskIqW2t.mjs.map +0 -1
- package/dist/storage-BOOpAF8N.cjs +0 -5
- package/dist/storage-Bj1E26lU.cjs.map +0 -1
- package/dist/storage-kSxTjkNb.mjs.map +0 -1
- package/dist/storage-tgZSUnKl.mjs +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi-react-query-B6XTeGqS.mjs","names":["options: ReactQueryOptions","spec: OpenAPISpec","operations: OperationInfo[]","operation: any","schema: any","_spec: OpenAPISpec","apiName: string","op: OperationInfo","paramParts: string[]","str: string"],"sources":["../src/openapi-react-query.ts"],"sourcesContent":["#!/usr/bin/env -S npx tsx\n\nimport { exec } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\ninterface ReactQueryOptions {\n\tinput?: string;\n\toutput?: string;\n\tname?: string;\n}\n\ninterface OpenAPISpec {\n\topenapi: string;\n\tinfo?: {\n\t\ttitle?: string;\n\t\tversion?: string;\n\t};\n\tpaths: Record<string, Record<string, any>>;\n}\n\nexport async function generateReactQueryCommand(\n\toptions: ReactQueryOptions = {},\n): Promise<void> {\n\tconst logger = console;\n\n\ttry {\n\t\t// Read OpenAPI spec\n\t\tconst inputPath = options.input || join(process.cwd(), 'openapi.json');\n\n\t\tif (!existsSync(inputPath)) {\n\t\t\tthrow new Error(\n\t\t\t\t`OpenAPI spec not found at ${inputPath}. Run 'npx @geekmidas/cli openapi' first.`,\n\t\t\t);\n\t\t}\n\n\t\tconst specContent = await readFile(inputPath, 'utf-8');\n\t\tconst spec: OpenAPISpec = JSON.parse(specContent);\n\n\t\t// Generate TypeScript types from OpenAPI spec\n\t\tconst outputDir = dirname(\n\t\t\toptions.output || join(process.cwd(), 'src', 'api', 'hooks.ts'),\n\t\t);\n\t\tconst typesPath = join(outputDir, 'openapi-types.d.ts');\n\n\t\tlogger.log('Generating TypeScript types from OpenAPI spec...');\n\n\t\ttry {\n\t\t\t// Use npx to run openapi-typescript\n\t\t\tawait execAsync(\n\t\t\t\t`npx openapi-typescript \"${inputPath}\" -o \"${typesPath}\"`,\n\t\t\t\t{ cwd: process.cwd() },\n\t\t\t);\n\t\t\tlogger.log(`TypeScript types generated: ${typesPath}`);\n\t\t} catch (_error) {\n\t\t\tlogger.warn(\n\t\t\t\t'Could not generate types with openapi-typescript. Install it for better type inference.',\n\t\t\t);\n\t\t\tlogger.warn('Run: npm install -D openapi-typescript');\n\n\t\t\t// Generate basic types file\n\t\t\tawait mkdir(dirname(typesPath), { recursive: true });\n\t\t\tawait writeFile(\n\t\t\t\ttypesPath,\n\t\t\t\t`// Auto-generated placeholder types\nexport interface paths {\n [path: string]: {\n [method: string]: {\n operationId?: string;\n parameters?: any;\n requestBody?: any;\n responses?: any;\n };\n };\n}\n`,\n\t\t\t);\n\t\t}\n\n\t\t// Extract operation info\n\t\tconst operations = extractOperations(spec);\n\n\t\t// Generate TypeScript code\n\t\tconst code = generateReactQueryCode(\n\t\t\tspec,\n\t\t\toperations,\n\t\t\toptions.name || 'API',\n\t\t);\n\n\t\t// Write output\n\t\tconst outputPath =\n\t\t\toptions.output || join(process.cwd(), 'src', 'api', 'hooks.ts');\n\t\tawait mkdir(dirname(outputPath), { recursive: true });\n\t\tawait writeFile(outputPath, code);\n\n\t\tlogger.log(`React Query hooks generated: ${outputPath}`);\n\t\tlogger.log(`Generated ${operations.length} hooks`);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`React Query generation failed: ${(error as Error).message}`,\n\t\t);\n\t}\n}\n\ninterface OperationInfo {\n\toperationId: string;\n\tpath: string;\n\tmethod: string;\n\tendpoint: string; // Full endpoint like 'GET /users/{id}'\n\tparameters?: Array<{ name: string; in: string; required?: boolean }>;\n\trequestBody?: boolean;\n\tresponseType?: string;\n}\n\nfunction extractOperations(spec: OpenAPISpec): OperationInfo[] {\n\tconst operations: OperationInfo[] = [];\n\n\tObject.entries(spec.paths).forEach(([path, methods]) => {\n\t\tObject.entries(methods).forEach(([method, operation]) => {\n\t\t\tif (operation.operationId) {\n\t\t\t\toperations.push({\n\t\t\t\t\toperationId: operation.operationId,\n\t\t\t\t\tpath,\n\t\t\t\t\tmethod: method.toUpperCase(),\n\t\t\t\t\tendpoint: `${method.toUpperCase()} ${path}`,\n\t\t\t\t\tparameters: operation.parameters,\n\t\t\t\t\trequestBody: !!operation.requestBody,\n\t\t\t\t\tresponseType: extractResponseType(operation),\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t});\n\n\treturn operations;\n}\n\nfunction extractResponseType(operation: any): string {\n\tconst responses = operation.responses;\n\tif (!responses) return 'unknown';\n\n\tconst successResponse = responses['200'] || responses['201'];\n\tif (!successResponse?.content?.['application/json']?.schema) {\n\t\treturn 'unknown';\n\t}\n\n\t// Basic type inference from schema\n\tconst schema = successResponse.content['application/json'].schema;\n\treturn schemaToTypeString(schema);\n}\n\nfunction schemaToTypeString(schema: any): string {\n\tif (!schema) return 'unknown';\n\n\tswitch (schema.type) {\n\t\tcase 'string':\n\t\t\treturn 'string';\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number';\n\t\tcase 'boolean':\n\t\t\treturn 'boolean';\n\t\tcase 'array':\n\t\t\treturn `Array<${schemaToTypeString(schema.items)}>`;\n\t\tcase 'object':\n\t\t\tif (schema.properties) {\n\t\t\t\tconst props = Object.entries(schema.properties)\n\t\t\t\t\t.map(\n\t\t\t\t\t\t([key, value]: [string, any]) =>\n\t\t\t\t\t\t\t`${key}: ${schemaToTypeString(value)}`,\n\t\t\t\t\t)\n\t\t\t\t\t.join('; ');\n\t\t\t\treturn `{ ${props} }`;\n\t\t\t}\n\t\t\treturn 'Record<string, unknown>';\n\t\tdefault:\n\t\t\treturn 'unknown';\n\t}\n}\n\nfunction generateReactQueryCode(\n\t_spec: OpenAPISpec,\n\toperations: OperationInfo[],\n\tapiName: string,\n): string {\n\tconst imports = `import { createTypedQueryClient } from '@geekmidas/client';\nimport type { paths } from './openapi-types';\n\n// Create typed query client\nexport const ${apiName.toLowerCase()} = createTypedQueryClient<paths>({\n baseURL: process.env.NEXT_PUBLIC_API_URL || '/api',\n});\n\n// Export individual hooks for better DX\n`;\n\n\tconst queryHooks = operations\n\t\t.filter((op) => op.method === 'GET')\n\t\t.map((op) => generateQueryHook(op, apiName))\n\t\t.join('\\n\\n');\n\n\tconst mutationHooks = operations\n\t\t.filter((op) => op.method !== 'GET')\n\t\t.map((op) => generateMutationHook(op, apiName))\n\t\t.join('\\n\\n');\n\n\tconst typeExports = generateTypeExports(operations);\n\n\treturn `${imports}\n// Query Hooks\n${queryHooks}\n\n// Mutation Hooks\n${mutationHooks}\n\n// Type exports for convenience\n${typeExports}\n\n// Re-export the api for advanced usage\nexport { ${apiName.toLowerCase()} };\n`;\n}\n\nfunction generateQueryHook(op: OperationInfo, apiName: string): string {\n\tconst hookName = `use${capitalize(op.operationId)}`;\n\tconst endpoint = op.endpoint;\n\tconst hasParams = op.parameters?.some((p) => p.in === 'path');\n\tconst hasQuery = op.parameters?.some((p) => p.in === 'query');\n\n\t// Generate properly typed hook\n\tlet params = '';\n\tlet args = '';\n\n\tif (hasParams || hasQuery) {\n\t\tconst paramParts: string[] = [];\n\t\tif (hasParams) {\n\t\t\tconst pathParams =\n\t\t\t\top.parameters?.filter((p) => p.in === 'path').map((p) => p.name) || [];\n\t\t\tparamParts.push(\n\t\t\t\t`params: { ${pathParams.map((p) => `${p}: string`).join('; ')} }`,\n\t\t\t);\n\t\t}\n\t\tif (hasQuery) {\n\t\t\tparamParts.push(`query?: Record<string, any>`);\n\t\t}\n\t\tparams = `config: { ${paramParts.join('; ')} }, `;\n\t\targs = ', config';\n\t}\n\n\treturn `export const ${hookName} = (\n ${params}options?: Parameters<typeof ${apiName.toLowerCase()}.useQuery>[2]\n) => {\n return ${apiName.toLowerCase()}.useQuery('${endpoint}' as any${args}, options);\n};`;\n}\n\nfunction generateMutationHook(op: OperationInfo, apiName: string): string {\n\tconst hookName = `use${capitalize(op.operationId)}`;\n\tconst endpoint = op.endpoint;\n\n\treturn `export const ${hookName} = (\n options?: Parameters<typeof ${apiName.toLowerCase()}.useMutation>[1]\n) => {\n return ${apiName.toLowerCase()}.useMutation('${endpoint}' as any, options);\n};`;\n}\n\nfunction generateTypeExports(operations: OperationInfo[]): string {\n\tconst exports = operations.map((op) => {\n\t\tconst typeName = capitalize(op.operationId);\n\t\tconst isQuery = op.method === 'GET';\n\n\t\tif (isQuery) {\n\t\t\treturn `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['data']>>;`;\n\t\t} else {\n\t\t\treturn `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['mutateAsync']>>;`;\n\t\t}\n\t});\n\n\treturn exports.join('\\n');\n}\n\nfunction capitalize(str: string): string {\n\treturn str.charAt(0).toUpperCase() + str.slice(1);\n}\n"],"mappings":";;;;;;;AAQA,MAAM,YAAY,UAAU,KAAK;AAiBjC,eAAsB,0BACrBA,UAA6B,CAAE,GACf;CAChB,MAAM,SAAS;AAEf,KAAI;EAEH,MAAM,YAAY,QAAQ,SAAS,KAAK,QAAQ,KAAK,EAAE,eAAe;AAEtE,OAAK,WAAW,UAAU,CACzB,OAAM,IAAI,OACR,4BAA4B,UAAU;EAIzC,MAAM,cAAc,MAAM,SAAS,WAAW,QAAQ;EACtD,MAAMC,OAAoB,KAAK,MAAM,YAAY;EAGjD,MAAM,YAAY,QACjB,QAAQ,UAAU,KAAK,QAAQ,KAAK,EAAE,OAAO,OAAO,WAAW,CAC/D;EACD,MAAM,YAAY,KAAK,WAAW,qBAAqB;AAEvD,SAAO,IAAI,mDAAmD;AAE9D,MAAI;AAEH,SAAM,WACJ,0BAA0B,UAAU,QAAQ,UAAU,IACvD,EAAE,KAAK,QAAQ,KAAK,CAAE,EACtB;AACD,UAAO,KAAK,8BAA8B,UAAU,EAAE;EACtD,SAAQ,QAAQ;AAChB,UAAO,KACN,0FACA;AACD,UAAO,KAAK,yCAAyC;AAGrD,SAAM,MAAM,QAAQ,UAAU,EAAE,EAAE,WAAW,KAAM,EAAC;AACpD,SAAM,UACL,YACC;;;;;;;;;;;EAYD;EACD;EAGD,MAAM,aAAa,kBAAkB,KAAK;EAG1C,MAAM,OAAO,uBACZ,MACA,YACA,QAAQ,QAAQ,MAChB;EAGD,MAAM,aACL,QAAQ,UAAU,KAAK,QAAQ,KAAK,EAAE,OAAO,OAAO,WAAW;AAChE,QAAM,MAAM,QAAQ,WAAW,EAAE,EAAE,WAAW,KAAM,EAAC;AACrD,QAAM,UAAU,YAAY,KAAK;AAEjC,SAAO,KAAK,+BAA+B,WAAW,EAAE;AACxD,SAAO,KAAK,YAAY,WAAW,OAAO,QAAQ;CAClD,SAAQ,OAAO;AACf,QAAM,IAAI,OACR,iCAAkC,MAAgB,QAAQ;CAE5D;AACD;AAYD,SAAS,kBAAkBA,MAAoC;CAC9D,MAAMC,aAA8B,CAAE;AAEtC,QAAO,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,QAAQ,KAAK;AACvD,SAAO,QAAQ,QAAQ,CAAC,QAAQ,CAAC,CAAC,QAAQ,UAAU,KAAK;AACxD,OAAI,UAAU,YACb,YAAW,KAAK;IACf,aAAa,UAAU;IACvB;IACA,QAAQ,OAAO,aAAa;IAC5B,WAAW,EAAE,OAAO,aAAa,CAAC,GAAG,KAAK;IAC1C,YAAY,UAAU;IACtB,eAAe,UAAU;IACzB,cAAc,oBAAoB,UAAU;GAC5C,EAAC;EAEH,EAAC;CACF,EAAC;AAEF,QAAO;AACP;AAED,SAAS,oBAAoBC,WAAwB;CACpD,MAAM,YAAY,UAAU;AAC5B,MAAK,UAAW,QAAO;CAEvB,MAAM,kBAAkB,UAAU,UAAU,UAAU;AACtD,MAAK,iBAAiB,UAAU,qBAAqB,OACpD,QAAO;CAIR,MAAM,SAAS,gBAAgB,QAAQ,oBAAoB;AAC3D,QAAO,mBAAmB,OAAO;AACjC;AAED,SAAS,mBAAmBC,QAAqB;AAChD,MAAK,OAAQ,QAAO;AAEpB,SAAQ,OAAO,MAAf;EACC,KAAK,SACJ,QAAO;EACR,KAAK;EACL,KAAK,UACJ,QAAO;EACR,KAAK,UACJ,QAAO;EACR,KAAK,QACJ,SAAQ,QAAQ,mBAAmB,OAAO,MAAM,CAAC;EAClD,KAAK;AACJ,OAAI,OAAO,YAAY;IACtB,MAAM,QAAQ,OAAO,QAAQ,OAAO,WAAW,CAC7C,IACA,CAAC,CAAC,KAAK,MAAqB,MAC1B,EAAE,IAAI,IAAI,mBAAmB,MAAM,CAAC,EACtC,CACA,KAAK,KAAK;AACZ,YAAQ,IAAI,MAAM;GAClB;AACD,UAAO;EACR,QACC,QAAO;CACR;AACD;AAED,SAAS,uBACRC,OACAH,YACAI,SACS;CACT,MAAM,WAAW;;;;eAIH,QAAQ,aAAa,CAAC;;;;;;CAOpC,MAAM,aAAa,WACjB,OAAO,CAAC,OAAO,GAAG,WAAW,MAAM,CACnC,IAAI,CAAC,OAAO,kBAAkB,IAAI,QAAQ,CAAC,CAC3C,KAAK,OAAO;CAEd,MAAM,gBAAgB,WACpB,OAAO,CAAC,OAAO,GAAG,WAAW,MAAM,CACnC,IAAI,CAAC,OAAO,qBAAqB,IAAI,QAAQ,CAAC,CAC9C,KAAK,OAAO;CAEd,MAAM,cAAc,oBAAoB,WAAW;AAEnD,SAAQ,EAAE,QAAQ;;EAEjB,WAAW;;;EAGX,cAAc;;;EAGd,YAAY;;;WAGH,QAAQ,aAAa,CAAC;;AAEhC;AAED,SAAS,kBAAkBC,IAAmBD,SAAyB;CACtE,MAAM,YAAY,KAAK,WAAW,GAAG,YAAY,CAAC;CAClD,MAAM,WAAW,GAAG;CACpB,MAAM,YAAY,GAAG,YAAY,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO;CAC7D,MAAM,WAAW,GAAG,YAAY,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;CAG7D,IAAI,SAAS;CACb,IAAI,OAAO;AAEX,KAAI,aAAa,UAAU;EAC1B,MAAME,aAAuB,CAAE;AAC/B,MAAI,WAAW;GACd,MAAM,aACL,GAAG,YAAY,OAAO,CAAC,MAAM,EAAE,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAE;AACvE,cAAW,MACT,YAAY,WAAW,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,KAAK,KAAK,CAAC,IAC9D;EACD;AACD,MAAI,SACH,YAAW,MAAM,6BAA6B;AAE/C,YAAU,YAAY,WAAW,KAAK,KAAK,CAAC;AAC5C,SAAO;CACP;AAED,SAAQ,eAAe,SAAS;IAC7B,OAAO,8BAA8B,QAAQ,aAAa,CAAC;;WAEpD,QAAQ,aAAa,CAAC,aAAa,SAAS,UAAU,KAAK;;AAErE;AAED,SAAS,qBAAqBD,IAAmBD,SAAyB;CACzE,MAAM,YAAY,KAAK,WAAW,GAAG,YAAY,CAAC;CAClD,MAAM,WAAW,GAAG;AAEpB,SAAQ,eAAe,SAAS;gCACD,QAAQ,aAAa,CAAC;;WAE3C,QAAQ,aAAa,CAAC,gBAAgB,SAAS;;AAEzD;AAED,SAAS,oBAAoBJ,YAAqC;CACjE,MAAM,UAAU,WAAW,IAAI,CAAC,OAAO;EACtC,MAAM,WAAW,WAAW,GAAG,YAAY;EAC3C,MAAM,UAAU,GAAG,WAAW;AAE9B,MAAI,QACH,SAAQ,cAAc,SAAS,qDAAqD,SAAS;MAE7F,SAAQ,cAAc,SAAS,qDAAqD,SAAS;CAE9F,EAAC;AAEF,QAAO,QAAQ,KAAK,KAAK;AACzB;AAED,SAAS,WAAWO,KAAqB;AACxC,QAAO,IAAI,OAAO,EAAE,CAAC,aAAa,GAAG,IAAI,MAAM,EAAE;AACjD"}
|
|
1
|
+
{"version":3,"file":"openapi-react-query-CM2_qlW9.mjs","names":["options: ReactQueryOptions","spec: OpenAPISpec","operations: OperationInfo[]","operation: any","schema: any","_spec: OpenAPISpec","apiName: string","op: OperationInfo","paramParts: string[]","str: string"],"sources":["../src/openapi-react-query.ts"],"sourcesContent":["#!/usr/bin/env -S npx tsx\n\nimport { exec } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\ninterface ReactQueryOptions {\n\tinput?: string;\n\toutput?: string;\n\tname?: string;\n}\n\ninterface OpenAPISpec {\n\topenapi: string;\n\tinfo?: {\n\t\ttitle?: string;\n\t\tversion?: string;\n\t};\n\tpaths: Record<string, Record<string, any>>;\n}\n\nexport async function generateReactQueryCommand(\n\toptions: ReactQueryOptions = {},\n): Promise<void> {\n\tconst logger = console;\n\n\ttry {\n\t\t// Read OpenAPI spec\n\t\tconst inputPath = options.input || join(process.cwd(), 'openapi.json');\n\n\t\tif (!existsSync(inputPath)) {\n\t\t\tthrow new Error(\n\t\t\t\t`OpenAPI spec not found at ${inputPath}. Run 'npx @geekmidas/cli openapi' first.`,\n\t\t\t);\n\t\t}\n\n\t\tconst specContent = await readFile(inputPath, 'utf-8');\n\t\tconst spec: OpenAPISpec = JSON.parse(specContent);\n\n\t\t// Generate TypeScript types from OpenAPI spec\n\t\tconst outputDir = dirname(\n\t\t\toptions.output || join(process.cwd(), 'src', 'api', 'hooks.ts'),\n\t\t);\n\t\tconst typesPath = join(outputDir, 'openapi-types.d.ts');\n\n\t\tlogger.log('Generating TypeScript types from OpenAPI spec...');\n\n\t\ttry {\n\t\t\t// Use npx to run openapi-typescript\n\t\t\tawait execAsync(\n\t\t\t\t`npx openapi-typescript \"${inputPath}\" -o \"${typesPath}\"`,\n\t\t\t\t{ cwd: process.cwd() },\n\t\t\t);\n\t\t\tlogger.log(`TypeScript types generated: ${typesPath}`);\n\t\t} catch (_error) {\n\t\t\tlogger.warn(\n\t\t\t\t'Could not generate types with openapi-typescript. Install it for better type inference.',\n\t\t\t);\n\t\t\tlogger.warn('Run: npm install -D openapi-typescript');\n\n\t\t\t// Generate basic types file\n\t\t\tawait mkdir(dirname(typesPath), { recursive: true });\n\t\t\tawait writeFile(\n\t\t\t\ttypesPath,\n\t\t\t\t`// Auto-generated placeholder types\nexport interface paths {\n [path: string]: {\n [method: string]: {\n operationId?: string;\n parameters?: any;\n requestBody?: any;\n responses?: any;\n };\n };\n}\n`,\n\t\t\t);\n\t\t}\n\n\t\t// Extract operation info\n\t\tconst operations = extractOperations(spec);\n\n\t\t// Generate TypeScript code\n\t\tconst code = generateReactQueryCode(\n\t\t\tspec,\n\t\t\toperations,\n\t\t\toptions.name || 'API',\n\t\t);\n\n\t\t// Write output\n\t\tconst outputPath =\n\t\t\toptions.output || join(process.cwd(), 'src', 'api', 'hooks.ts');\n\t\tawait mkdir(dirname(outputPath), { recursive: true });\n\t\tawait writeFile(outputPath, code);\n\n\t\tlogger.log(`React Query hooks generated: ${outputPath}`);\n\t\tlogger.log(`Generated ${operations.length} hooks`);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`React Query generation failed: ${(error as Error).message}`,\n\t\t);\n\t}\n}\n\ninterface OperationInfo {\n\toperationId: string;\n\tpath: string;\n\tmethod: string;\n\tendpoint: string; // Full endpoint like 'GET /users/{id}'\n\tparameters?: Array<{ name: string; in: string; required?: boolean }>;\n\trequestBody?: boolean;\n\tresponseType?: string;\n}\n\nfunction extractOperations(spec: OpenAPISpec): OperationInfo[] {\n\tconst operations: OperationInfo[] = [];\n\n\tObject.entries(spec.paths).forEach(([path, methods]) => {\n\t\tObject.entries(methods).forEach(([method, operation]) => {\n\t\t\tif (operation.operationId) {\n\t\t\t\toperations.push({\n\t\t\t\t\toperationId: operation.operationId,\n\t\t\t\t\tpath,\n\t\t\t\t\tmethod: method.toUpperCase(),\n\t\t\t\t\tendpoint: `${method.toUpperCase()} ${path}`,\n\t\t\t\t\tparameters: operation.parameters,\n\t\t\t\t\trequestBody: !!operation.requestBody,\n\t\t\t\t\tresponseType: extractResponseType(operation),\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t});\n\n\treturn operations;\n}\n\nfunction extractResponseType(operation: any): string {\n\tconst responses = operation.responses;\n\tif (!responses) return 'unknown';\n\n\tconst successResponse = responses['200'] || responses['201'];\n\tif (!successResponse?.content?.['application/json']?.schema) {\n\t\treturn 'unknown';\n\t}\n\n\t// Basic type inference from schema\n\tconst schema = successResponse.content['application/json'].schema;\n\treturn schemaToTypeString(schema);\n}\n\nfunction schemaToTypeString(schema: any): string {\n\tif (!schema) return 'unknown';\n\n\tswitch (schema.type) {\n\t\tcase 'string':\n\t\t\treturn 'string';\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number';\n\t\tcase 'boolean':\n\t\t\treturn 'boolean';\n\t\tcase 'array':\n\t\t\treturn `Array<${schemaToTypeString(schema.items)}>`;\n\t\tcase 'object':\n\t\t\tif (schema.properties) {\n\t\t\t\tconst props = Object.entries(schema.properties)\n\t\t\t\t\t.map(\n\t\t\t\t\t\t([key, value]: [string, any]) =>\n\t\t\t\t\t\t\t`${key}: ${schemaToTypeString(value)}`,\n\t\t\t\t\t)\n\t\t\t\t\t.join('; ');\n\t\t\t\treturn `{ ${props} }`;\n\t\t\t}\n\t\t\treturn 'Record<string, unknown>';\n\t\tdefault:\n\t\t\treturn 'unknown';\n\t}\n}\n\nfunction generateReactQueryCode(\n\t_spec: OpenAPISpec,\n\toperations: OperationInfo[],\n\tapiName: string,\n): string {\n\tconst imports = `import { createTypedQueryClient } from '@geekmidas/client';\nimport type { paths } from './openapi-types';\n\n// Create typed query client\nexport const ${apiName.toLowerCase()} = createTypedQueryClient<paths>({\n baseURL: process.env.NEXT_PUBLIC_API_URL || '/api',\n});\n\n// Export individual hooks for better DX\n`;\n\n\tconst queryHooks = operations\n\t\t.filter((op) => op.method === 'GET')\n\t\t.map((op) => generateQueryHook(op, apiName))\n\t\t.join('\\n\\n');\n\n\tconst mutationHooks = operations\n\t\t.filter((op) => op.method !== 'GET')\n\t\t.map((op) => generateMutationHook(op, apiName))\n\t\t.join('\\n\\n');\n\n\tconst typeExports = generateTypeExports(operations);\n\n\treturn `${imports}\n// Query Hooks\n${queryHooks}\n\n// Mutation Hooks\n${mutationHooks}\n\n// Type exports for convenience\n${typeExports}\n\n// Re-export the api for advanced usage\nexport { ${apiName.toLowerCase()} };\n`;\n}\n\nfunction generateQueryHook(op: OperationInfo, apiName: string): string {\n\tconst hookName = `use${capitalize(op.operationId)}`;\n\tconst endpoint = op.endpoint;\n\tconst hasParams = op.parameters?.some((p) => p.in === 'path');\n\tconst hasQuery = op.parameters?.some((p) => p.in === 'query');\n\n\t// Generate properly typed hook\n\tlet params = '';\n\tlet args = '';\n\n\tif (hasParams || hasQuery) {\n\t\tconst paramParts: string[] = [];\n\t\tif (hasParams) {\n\t\t\tconst pathParams =\n\t\t\t\top.parameters?.filter((p) => p.in === 'path').map((p) => p.name) || [];\n\t\t\tparamParts.push(\n\t\t\t\t`params: { ${pathParams.map((p) => `${p}: string`).join('; ')} }`,\n\t\t\t);\n\t\t}\n\t\tif (hasQuery) {\n\t\t\tparamParts.push(`query?: Record<string, any>`);\n\t\t}\n\t\tparams = `config: { ${paramParts.join('; ')} }, `;\n\t\targs = ', config';\n\t}\n\n\treturn `export const ${hookName} = (\n ${params}options?: Parameters<typeof ${apiName.toLowerCase()}.useQuery>[2]\n) => {\n return ${apiName.toLowerCase()}.useQuery('${endpoint}' as any${args}, options);\n};`;\n}\n\nfunction generateMutationHook(op: OperationInfo, apiName: string): string {\n\tconst hookName = `use${capitalize(op.operationId)}`;\n\tconst endpoint = op.endpoint;\n\n\treturn `export const ${hookName} = (\n options?: Parameters<typeof ${apiName.toLowerCase()}.useMutation>[1]\n) => {\n return ${apiName.toLowerCase()}.useMutation('${endpoint}' as any, options);\n};`;\n}\n\nfunction generateTypeExports(operations: OperationInfo[]): string {\n\tconst exports = operations.map((op) => {\n\t\tconst typeName = capitalize(op.operationId);\n\t\tconst isQuery = op.method === 'GET';\n\n\t\tif (isQuery) {\n\t\t\treturn `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['data']>>;`;\n\t\t} else {\n\t\t\treturn `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['mutateAsync']>>;`;\n\t\t}\n\t});\n\n\treturn exports.join('\\n');\n}\n\nfunction capitalize(str: string): string {\n\treturn str.charAt(0).toUpperCase() + str.slice(1);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi-react-query-B-sNWHFU.cjs","names":["exec","options: ReactQueryOptions","spec: OpenAPISpec","operations: OperationInfo[]","operation: any","schema: any","_spec: OpenAPISpec","apiName: string","op: OperationInfo","paramParts: string[]","exports","str: string"],"sources":["../src/openapi-react-query.ts"],"sourcesContent":["#!/usr/bin/env -S npx tsx\n\nimport { exec } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\ninterface ReactQueryOptions {\n\tinput?: string;\n\toutput?: string;\n\tname?: string;\n}\n\ninterface OpenAPISpec {\n\topenapi: string;\n\tinfo?: {\n\t\ttitle?: string;\n\t\tversion?: string;\n\t};\n\tpaths: Record<string, Record<string, any>>;\n}\n\nexport async function generateReactQueryCommand(\n\toptions: ReactQueryOptions = {},\n): Promise<void> {\n\tconst logger = console;\n\n\ttry {\n\t\t// Read OpenAPI spec\n\t\tconst inputPath = options.input || join(process.cwd(), 'openapi.json');\n\n\t\tif (!existsSync(inputPath)) {\n\t\t\tthrow new Error(\n\t\t\t\t`OpenAPI spec not found at ${inputPath}. Run 'npx @geekmidas/cli openapi' first.`,\n\t\t\t);\n\t\t}\n\n\t\tconst specContent = await readFile(inputPath, 'utf-8');\n\t\tconst spec: OpenAPISpec = JSON.parse(specContent);\n\n\t\t// Generate TypeScript types from OpenAPI spec\n\t\tconst outputDir = dirname(\n\t\t\toptions.output || join(process.cwd(), 'src', 'api', 'hooks.ts'),\n\t\t);\n\t\tconst typesPath = join(outputDir, 'openapi-types.d.ts');\n\n\t\tlogger.log('Generating TypeScript types from OpenAPI spec...');\n\n\t\ttry {\n\t\t\t// Use npx to run openapi-typescript\n\t\t\tawait execAsync(\n\t\t\t\t`npx openapi-typescript \"${inputPath}\" -o \"${typesPath}\"`,\n\t\t\t\t{ cwd: process.cwd() },\n\t\t\t);\n\t\t\tlogger.log(`TypeScript types generated: ${typesPath}`);\n\t\t} catch (_error) {\n\t\t\tlogger.warn(\n\t\t\t\t'Could not generate types with openapi-typescript. Install it for better type inference.',\n\t\t\t);\n\t\t\tlogger.warn('Run: npm install -D openapi-typescript');\n\n\t\t\t// Generate basic types file\n\t\t\tawait mkdir(dirname(typesPath), { recursive: true });\n\t\t\tawait writeFile(\n\t\t\t\ttypesPath,\n\t\t\t\t`// Auto-generated placeholder types\nexport interface paths {\n [path: string]: {\n [method: string]: {\n operationId?: string;\n parameters?: any;\n requestBody?: any;\n responses?: any;\n };\n };\n}\n`,\n\t\t\t);\n\t\t}\n\n\t\t// Extract operation info\n\t\tconst operations = extractOperations(spec);\n\n\t\t// Generate TypeScript code\n\t\tconst code = generateReactQueryCode(\n\t\t\tspec,\n\t\t\toperations,\n\t\t\toptions.name || 'API',\n\t\t);\n\n\t\t// Write output\n\t\tconst outputPath =\n\t\t\toptions.output || join(process.cwd(), 'src', 'api', 'hooks.ts');\n\t\tawait mkdir(dirname(outputPath), { recursive: true });\n\t\tawait writeFile(outputPath, code);\n\n\t\tlogger.log(`React Query hooks generated: ${outputPath}`);\n\t\tlogger.log(`Generated ${operations.length} hooks`);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`React Query generation failed: ${(error as Error).message}`,\n\t\t);\n\t}\n}\n\ninterface OperationInfo {\n\toperationId: string;\n\tpath: string;\n\tmethod: string;\n\tendpoint: string; // Full endpoint like 'GET /users/{id}'\n\tparameters?: Array<{ name: string; in: string; required?: boolean }>;\n\trequestBody?: boolean;\n\tresponseType?: string;\n}\n\nfunction extractOperations(spec: OpenAPISpec): OperationInfo[] {\n\tconst operations: OperationInfo[] = [];\n\n\tObject.entries(spec.paths).forEach(([path, methods]) => {\n\t\tObject.entries(methods).forEach(([method, operation]) => {\n\t\t\tif (operation.operationId) {\n\t\t\t\toperations.push({\n\t\t\t\t\toperationId: operation.operationId,\n\t\t\t\t\tpath,\n\t\t\t\t\tmethod: method.toUpperCase(),\n\t\t\t\t\tendpoint: `${method.toUpperCase()} ${path}`,\n\t\t\t\t\tparameters: operation.parameters,\n\t\t\t\t\trequestBody: !!operation.requestBody,\n\t\t\t\t\tresponseType: extractResponseType(operation),\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t});\n\n\treturn operations;\n}\n\nfunction extractResponseType(operation: any): string {\n\tconst responses = operation.responses;\n\tif (!responses) return 'unknown';\n\n\tconst successResponse = responses['200'] || responses['201'];\n\tif (!successResponse?.content?.['application/json']?.schema) {\n\t\treturn 'unknown';\n\t}\n\n\t// Basic type inference from schema\n\tconst schema = successResponse.content['application/json'].schema;\n\treturn schemaToTypeString(schema);\n}\n\nfunction schemaToTypeString(schema: any): string {\n\tif (!schema) return 'unknown';\n\n\tswitch (schema.type) {\n\t\tcase 'string':\n\t\t\treturn 'string';\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number';\n\t\tcase 'boolean':\n\t\t\treturn 'boolean';\n\t\tcase 'array':\n\t\t\treturn `Array<${schemaToTypeString(schema.items)}>`;\n\t\tcase 'object':\n\t\t\tif (schema.properties) {\n\t\t\t\tconst props = Object.entries(schema.properties)\n\t\t\t\t\t.map(\n\t\t\t\t\t\t([key, value]: [string, any]) =>\n\t\t\t\t\t\t\t`${key}: ${schemaToTypeString(value)}`,\n\t\t\t\t\t)\n\t\t\t\t\t.join('; ');\n\t\t\t\treturn `{ ${props} }`;\n\t\t\t}\n\t\t\treturn 'Record<string, unknown>';\n\t\tdefault:\n\t\t\treturn 'unknown';\n\t}\n}\n\nfunction generateReactQueryCode(\n\t_spec: OpenAPISpec,\n\toperations: OperationInfo[],\n\tapiName: string,\n): string {\n\tconst imports = `import { createTypedQueryClient } from '@geekmidas/client';\nimport type { paths } from './openapi-types';\n\n// Create typed query client\nexport const ${apiName.toLowerCase()} = createTypedQueryClient<paths>({\n baseURL: process.env.NEXT_PUBLIC_API_URL || '/api',\n});\n\n// Export individual hooks for better DX\n`;\n\n\tconst queryHooks = operations\n\t\t.filter((op) => op.method === 'GET')\n\t\t.map((op) => generateQueryHook(op, apiName))\n\t\t.join('\\n\\n');\n\n\tconst mutationHooks = operations\n\t\t.filter((op) => op.method !== 'GET')\n\t\t.map((op) => generateMutationHook(op, apiName))\n\t\t.join('\\n\\n');\n\n\tconst typeExports = generateTypeExports(operations);\n\n\treturn `${imports}\n// Query Hooks\n${queryHooks}\n\n// Mutation Hooks\n${mutationHooks}\n\n// Type exports for convenience\n${typeExports}\n\n// Re-export the api for advanced usage\nexport { ${apiName.toLowerCase()} };\n`;\n}\n\nfunction generateQueryHook(op: OperationInfo, apiName: string): string {\n\tconst hookName = `use${capitalize(op.operationId)}`;\n\tconst endpoint = op.endpoint;\n\tconst hasParams = op.parameters?.some((p) => p.in === 'path');\n\tconst hasQuery = op.parameters?.some((p) => p.in === 'query');\n\n\t// Generate properly typed hook\n\tlet params = '';\n\tlet args = '';\n\n\tif (hasParams || hasQuery) {\n\t\tconst paramParts: string[] = [];\n\t\tif (hasParams) {\n\t\t\tconst pathParams =\n\t\t\t\top.parameters?.filter((p) => p.in === 'path').map((p) => p.name) || [];\n\t\t\tparamParts.push(\n\t\t\t\t`params: { ${pathParams.map((p) => `${p}: string`).join('; ')} }`,\n\t\t\t);\n\t\t}\n\t\tif (hasQuery) {\n\t\t\tparamParts.push(`query?: Record<string, any>`);\n\t\t}\n\t\tparams = `config: { ${paramParts.join('; ')} }, `;\n\t\targs = ', config';\n\t}\n\n\treturn `export const ${hookName} = (\n ${params}options?: Parameters<typeof ${apiName.toLowerCase()}.useQuery>[2]\n) => {\n return ${apiName.toLowerCase()}.useQuery('${endpoint}' as any${args}, options);\n};`;\n}\n\nfunction generateMutationHook(op: OperationInfo, apiName: string): string {\n\tconst hookName = `use${capitalize(op.operationId)}`;\n\tconst endpoint = op.endpoint;\n\n\treturn `export const ${hookName} = (\n options?: Parameters<typeof ${apiName.toLowerCase()}.useMutation>[1]\n) => {\n return ${apiName.toLowerCase()}.useMutation('${endpoint}' as any, options);\n};`;\n}\n\nfunction generateTypeExports(operations: OperationInfo[]): string {\n\tconst exports = operations.map((op) => {\n\t\tconst typeName = capitalize(op.operationId);\n\t\tconst isQuery = op.method === 'GET';\n\n\t\tif (isQuery) {\n\t\t\treturn `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['data']>>;`;\n\t\t} else {\n\t\t\treturn `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['mutateAsync']>>;`;\n\t\t}\n\t});\n\n\treturn exports.join('\\n');\n}\n\nfunction capitalize(str: string): string {\n\treturn str.charAt(0).toUpperCase() + str.slice(1);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"openapi-react-query-iKjfLzff.cjs","names":["exec","options: ReactQueryOptions","spec: OpenAPISpec","operations: OperationInfo[]","operation: any","schema: any","_spec: OpenAPISpec","apiName: string","op: OperationInfo","paramParts: string[]","exports","str: string"],"sources":["../src/openapi-react-query.ts"],"sourcesContent":["#!/usr/bin/env -S npx tsx\n\nimport { exec } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\ninterface ReactQueryOptions {\n\tinput?: string;\n\toutput?: string;\n\tname?: string;\n}\n\ninterface OpenAPISpec {\n\topenapi: string;\n\tinfo?: {\n\t\ttitle?: string;\n\t\tversion?: string;\n\t};\n\tpaths: Record<string, Record<string, any>>;\n}\n\nexport async function generateReactQueryCommand(\n\toptions: ReactQueryOptions = {},\n): Promise<void> {\n\tconst logger = console;\n\n\ttry {\n\t\t// Read OpenAPI spec\n\t\tconst inputPath = options.input || join(process.cwd(), 'openapi.json');\n\n\t\tif (!existsSync(inputPath)) {\n\t\t\tthrow new Error(\n\t\t\t\t`OpenAPI spec not found at ${inputPath}. Run 'npx @geekmidas/cli openapi' first.`,\n\t\t\t);\n\t\t}\n\n\t\tconst specContent = await readFile(inputPath, 'utf-8');\n\t\tconst spec: OpenAPISpec = JSON.parse(specContent);\n\n\t\t// Generate TypeScript types from OpenAPI spec\n\t\tconst outputDir = dirname(\n\t\t\toptions.output || join(process.cwd(), 'src', 'api', 'hooks.ts'),\n\t\t);\n\t\tconst typesPath = join(outputDir, 'openapi-types.d.ts');\n\n\t\tlogger.log('Generating TypeScript types from OpenAPI spec...');\n\n\t\ttry {\n\t\t\t// Use npx to run openapi-typescript\n\t\t\tawait execAsync(\n\t\t\t\t`npx openapi-typescript \"${inputPath}\" -o \"${typesPath}\"`,\n\t\t\t\t{ cwd: process.cwd() },\n\t\t\t);\n\t\t\tlogger.log(`TypeScript types generated: ${typesPath}`);\n\t\t} catch (_error) {\n\t\t\tlogger.warn(\n\t\t\t\t'Could not generate types with openapi-typescript. Install it for better type inference.',\n\t\t\t);\n\t\t\tlogger.warn('Run: npm install -D openapi-typescript');\n\n\t\t\t// Generate basic types file\n\t\t\tawait mkdir(dirname(typesPath), { recursive: true });\n\t\t\tawait writeFile(\n\t\t\t\ttypesPath,\n\t\t\t\t`// Auto-generated placeholder types\nexport interface paths {\n [path: string]: {\n [method: string]: {\n operationId?: string;\n parameters?: any;\n requestBody?: any;\n responses?: any;\n };\n };\n}\n`,\n\t\t\t);\n\t\t}\n\n\t\t// Extract operation info\n\t\tconst operations = extractOperations(spec);\n\n\t\t// Generate TypeScript code\n\t\tconst code = generateReactQueryCode(\n\t\t\tspec,\n\t\t\toperations,\n\t\t\toptions.name || 'API',\n\t\t);\n\n\t\t// Write output\n\t\tconst outputPath =\n\t\t\toptions.output || join(process.cwd(), 'src', 'api', 'hooks.ts');\n\t\tawait mkdir(dirname(outputPath), { recursive: true });\n\t\tawait writeFile(outputPath, code);\n\n\t\tlogger.log(`React Query hooks generated: ${outputPath}`);\n\t\tlogger.log(`Generated ${operations.length} hooks`);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`React Query generation failed: ${(error as Error).message}`,\n\t\t);\n\t}\n}\n\ninterface OperationInfo {\n\toperationId: string;\n\tpath: string;\n\tmethod: string;\n\tendpoint: string; // Full endpoint like 'GET /users/{id}'\n\tparameters?: Array<{ name: string; in: string; required?: boolean }>;\n\trequestBody?: boolean;\n\tresponseType?: string;\n}\n\nfunction extractOperations(spec: OpenAPISpec): OperationInfo[] {\n\tconst operations: OperationInfo[] = [];\n\n\tObject.entries(spec.paths).forEach(([path, methods]) => {\n\t\tObject.entries(methods).forEach(([method, operation]) => {\n\t\t\tif (operation.operationId) {\n\t\t\t\toperations.push({\n\t\t\t\t\toperationId: operation.operationId,\n\t\t\t\t\tpath,\n\t\t\t\t\tmethod: method.toUpperCase(),\n\t\t\t\t\tendpoint: `${method.toUpperCase()} ${path}`,\n\t\t\t\t\tparameters: operation.parameters,\n\t\t\t\t\trequestBody: !!operation.requestBody,\n\t\t\t\t\tresponseType: extractResponseType(operation),\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t});\n\n\treturn operations;\n}\n\nfunction extractResponseType(operation: any): string {\n\tconst responses = operation.responses;\n\tif (!responses) return 'unknown';\n\n\tconst successResponse = responses['200'] || responses['201'];\n\tif (!successResponse?.content?.['application/json']?.schema) {\n\t\treturn 'unknown';\n\t}\n\n\t// Basic type inference from schema\n\tconst schema = successResponse.content['application/json'].schema;\n\treturn schemaToTypeString(schema);\n}\n\nfunction schemaToTypeString(schema: any): string {\n\tif (!schema) return 'unknown';\n\n\tswitch (schema.type) {\n\t\tcase 'string':\n\t\t\treturn 'string';\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number';\n\t\tcase 'boolean':\n\t\t\treturn 'boolean';\n\t\tcase 'array':\n\t\t\treturn `Array<${schemaToTypeString(schema.items)}>`;\n\t\tcase 'object':\n\t\t\tif (schema.properties) {\n\t\t\t\tconst props = Object.entries(schema.properties)\n\t\t\t\t\t.map(\n\t\t\t\t\t\t([key, value]: [string, any]) =>\n\t\t\t\t\t\t\t`${key}: ${schemaToTypeString(value)}`,\n\t\t\t\t\t)\n\t\t\t\t\t.join('; ');\n\t\t\t\treturn `{ ${props} }`;\n\t\t\t}\n\t\t\treturn 'Record<string, unknown>';\n\t\tdefault:\n\t\t\treturn 'unknown';\n\t}\n}\n\nfunction generateReactQueryCode(\n\t_spec: OpenAPISpec,\n\toperations: OperationInfo[],\n\tapiName: string,\n): string {\n\tconst imports = `import { createTypedQueryClient } from '@geekmidas/client';\nimport type { paths } from './openapi-types';\n\n// Create typed query client\nexport const ${apiName.toLowerCase()} = createTypedQueryClient<paths>({\n baseURL: process.env.NEXT_PUBLIC_API_URL || '/api',\n});\n\n// Export individual hooks for better DX\n`;\n\n\tconst queryHooks = operations\n\t\t.filter((op) => op.method === 'GET')\n\t\t.map((op) => generateQueryHook(op, apiName))\n\t\t.join('\\n\\n');\n\n\tconst mutationHooks = operations\n\t\t.filter((op) => op.method !== 'GET')\n\t\t.map((op) => generateMutationHook(op, apiName))\n\t\t.join('\\n\\n');\n\n\tconst typeExports = generateTypeExports(operations);\n\n\treturn `${imports}\n// Query Hooks\n${queryHooks}\n\n// Mutation Hooks\n${mutationHooks}\n\n// Type exports for convenience\n${typeExports}\n\n// Re-export the api for advanced usage\nexport { ${apiName.toLowerCase()} };\n`;\n}\n\nfunction generateQueryHook(op: OperationInfo, apiName: string): string {\n\tconst hookName = `use${capitalize(op.operationId)}`;\n\tconst endpoint = op.endpoint;\n\tconst hasParams = op.parameters?.some((p) => p.in === 'path');\n\tconst hasQuery = op.parameters?.some((p) => p.in === 'query');\n\n\t// Generate properly typed hook\n\tlet params = '';\n\tlet args = '';\n\n\tif (hasParams || hasQuery) {\n\t\tconst paramParts: string[] = [];\n\t\tif (hasParams) {\n\t\t\tconst pathParams =\n\t\t\t\top.parameters?.filter((p) => p.in === 'path').map((p) => p.name) || [];\n\t\t\tparamParts.push(\n\t\t\t\t`params: { ${pathParams.map((p) => `${p}: string`).join('; ')} }`,\n\t\t\t);\n\t\t}\n\t\tif (hasQuery) {\n\t\t\tparamParts.push(`query?: Record<string, any>`);\n\t\t}\n\t\tparams = `config: { ${paramParts.join('; ')} }, `;\n\t\targs = ', config';\n\t}\n\n\treturn `export const ${hookName} = (\n ${params}options?: Parameters<typeof ${apiName.toLowerCase()}.useQuery>[2]\n) => {\n return ${apiName.toLowerCase()}.useQuery('${endpoint}' as any${args}, options);\n};`;\n}\n\nfunction generateMutationHook(op: OperationInfo, apiName: string): string {\n\tconst hookName = `use${capitalize(op.operationId)}`;\n\tconst endpoint = op.endpoint;\n\n\treturn `export const ${hookName} = (\n options?: Parameters<typeof ${apiName.toLowerCase()}.useMutation>[1]\n) => {\n return ${apiName.toLowerCase()}.useMutation('${endpoint}' as any, options);\n};`;\n}\n\nfunction generateTypeExports(operations: OperationInfo[]): string {\n\tconst exports = operations.map((op) => {\n\t\tconst typeName = capitalize(op.operationId);\n\t\tconst isQuery = op.method === 'GET';\n\n\t\tif (isQuery) {\n\t\t\treturn `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['data']>>;`;\n\t\t} else {\n\t\t\treturn `export type ${typeName}Response = Awaited<ReturnType<ReturnType<typeof use${typeName}>['mutateAsync']>>;`;\n\t\t}\n\t});\n\n\treturn exports.join('\\n');\n}\n\nfunction capitalize(str: string): string {\n\treturn str.charAt(0).toUpperCase() + str.slice(1);\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
|
-
const require_openapi_react_query = require('./openapi-react-query-
|
|
2
|
+
const require_openapi_react_query = require('./openapi-react-query-iKjfLzff.cjs');
|
|
3
3
|
|
|
4
4
|
exports.generateReactQueryCommand = require_openapi_react_query.generateReactQueryCommand;
|
package/dist/openapi.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
2
|
require('./config-AmInkU7k.cjs');
|
|
3
|
-
const require_openapi = require('./openapi-
|
|
3
|
+
const require_openapi = require('./openapi-C89hhkZC.cjs');
|
|
4
4
|
|
|
5
5
|
exports.OPENAPI_OUTPUT_PATH = require_openapi.OPENAPI_OUTPUT_PATH;
|
|
6
6
|
exports.generateOpenApi = require_openapi.generateOpenApi;
|
package/dist/openapi.d.cts
CHANGED
package/dist/openapi.d.mts
CHANGED
package/dist/openapi.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
2
|
import "./config-DYULeEv8.mjs";
|
|
3
|
-
import { OPENAPI_OUTPUT_PATH, generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi-
|
|
3
|
+
import { OPENAPI_OUTPUT_PATH, generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi-CZVcfxk-.mjs";
|
|
4
4
|
|
|
5
5
|
export { OPENAPI_OUTPUT_PATH, generateOpenApi, openapiCommand, resolveOpenApiConfig };
|
|
@@ -24,6 +24,20 @@ function secretsExist(stage, cwd = process.cwd()) {
|
|
|
24
24
|
return existsSync(getSecretsPath(stage, cwd));
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
+
* Initialize an empty StageSecrets object for a stage.
|
|
28
|
+
*/
|
|
29
|
+
function initStageSecrets(stage) {
|
|
30
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
31
|
+
return {
|
|
32
|
+
stage,
|
|
33
|
+
createdAt: now,
|
|
34
|
+
updatedAt: now,
|
|
35
|
+
services: {},
|
|
36
|
+
urls: {},
|
|
37
|
+
custom: {}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
27
41
|
* Read secrets for a stage.
|
|
28
42
|
* @returns StageSecrets or null if not found
|
|
29
43
|
*/
|
|
@@ -129,5 +143,5 @@ function validateEnvironmentVariables(requiredVars, secrets) {
|
|
|
129
143
|
}
|
|
130
144
|
|
|
131
145
|
//#endregion
|
|
132
|
-
export { getSecretsDir, getSecretsPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, validateEnvironmentVariables, writeStageSecrets };
|
|
133
|
-
//# sourceMappingURL=storage-
|
|
146
|
+
export { getSecretsDir, getSecretsPath, initStageSecrets, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, validateEnvironmentVariables, writeStageSecrets };
|
|
147
|
+
//# sourceMappingURL=storage-BaOP55oq.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-BaOP55oq.mjs","names":["stage: string","secrets: StageSecrets","key: string","value: string","updated: StageSecrets","password: string","requiredVars: string[]","missing: string[]","provided: string[]"],"sources":["../src/secrets/storage.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { EmbeddableSecrets, StageSecrets } from './types';\n\n/** Default secrets directory relative to project root */\nconst SECRETS_DIR = '.gkm/secrets';\n\n/**\n * Get the secrets directory path.\n */\nexport function getSecretsDir(cwd = process.cwd()): string {\n\treturn join(cwd, SECRETS_DIR);\n}\n\n/**\n * Get the secrets file path for a stage.\n */\nexport function getSecretsPath(stage: string, cwd = process.cwd()): string {\n\treturn join(getSecretsDir(cwd), `${stage}.json`);\n}\n\n/**\n * Check if secrets exist for a stage.\n */\nexport function secretsExist(stage: string, cwd = process.cwd()): boolean {\n\treturn existsSync(getSecretsPath(stage, cwd));\n}\n\n/**\n * Initialize an empty StageSecrets object for a stage.\n */\nexport function initStageSecrets(stage: string): StageSecrets {\n\tconst now = new Date().toISOString();\n\treturn {\n\t\tstage,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t\tservices: {},\n\t\turls: {},\n\t\tcustom: {},\n\t};\n}\n\n/**\n * Read secrets for a stage.\n * @returns StageSecrets or null if not found\n */\nexport async function readStageSecrets(\n\tstage: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets | null> {\n\tconst path = getSecretsPath(stage, cwd);\n\n\tif (!existsSync(path)) {\n\t\treturn null;\n\t}\n\n\tconst content = await readFile(path, 'utf-8');\n\treturn JSON.parse(content) as StageSecrets;\n}\n\n/**\n * Write secrets for a stage.\n */\nexport async function writeStageSecrets(\n\tsecrets: StageSecrets,\n\tcwd = process.cwd(),\n): Promise<void> {\n\tconst dir = getSecretsDir(cwd);\n\tconst path = getSecretsPath(secrets.stage, cwd);\n\n\t// Ensure directory exists\n\tawait mkdir(dir, { recursive: true });\n\n\t// Write with pretty formatting\n\tawait writeFile(path, JSON.stringify(secrets, null, 2), 'utf-8');\n}\n\n/**\n * Convert StageSecrets to embeddable format (flat key-value pairs).\n * This is what gets encrypted and embedded in the bundle.\n */\nexport function toEmbeddableSecrets(secrets: StageSecrets): EmbeddableSecrets {\n\treturn {\n\t\t...secrets.urls,\n\t\t...secrets.custom,\n\t\t// Also include individual service credentials if needed\n\t\t...(secrets.services.postgres && {\n\t\t\tPOSTGRES_USER: secrets.services.postgres.username,\n\t\t\tPOSTGRES_PASSWORD: secrets.services.postgres.password,\n\t\t\tPOSTGRES_DB: secrets.services.postgres.database ?? 'app',\n\t\t\tPOSTGRES_HOST: secrets.services.postgres.host,\n\t\t\tPOSTGRES_PORT: String(secrets.services.postgres.port),\n\t\t}),\n\t\t...(secrets.services.redis && {\n\t\t\tREDIS_PASSWORD: secrets.services.redis.password,\n\t\t\tREDIS_HOST: secrets.services.redis.host,\n\t\t\tREDIS_PORT: String(secrets.services.redis.port),\n\t\t}),\n\t\t...(secrets.services.rabbitmq && {\n\t\t\tRABBITMQ_USER: secrets.services.rabbitmq.username,\n\t\t\tRABBITMQ_PASSWORD: secrets.services.rabbitmq.password,\n\t\t\tRABBITMQ_HOST: secrets.services.rabbitmq.host,\n\t\t\tRABBITMQ_PORT: String(secrets.services.rabbitmq.port),\n\t\t\tRABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? '/',\n\t\t}),\n\t};\n}\n\n/**\n * Update a custom secret in the secrets file.\n */\nexport async function setCustomSecret(\n\tstage: string,\n\tkey: string,\n\tvalue: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets> {\n\tconst secrets = await readStageSecrets(stage, cwd);\n\n\tif (!secrets) {\n\t\tthrow new Error(\n\t\t\t`Secrets not found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t}\n\n\tconst updated: StageSecrets = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: {\n\t\t\t...secrets.custom,\n\t\t\t[key]: value,\n\t\t},\n\t};\n\n\tawait writeStageSecrets(updated, cwd);\n\treturn updated;\n}\n\n/**\n * Mask a password for display (show first 4 and last 2 chars).\n */\nexport function maskPassword(password: string): string {\n\tif (password.length <= 8) {\n\t\treturn '********';\n\t}\n\treturn `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;\n}\n\n/**\n * Result of environment variable validation.\n */\nexport interface EnvValidationResult {\n\t/** Whether all required environment variables are present */\n\tvalid: boolean;\n\t/** List of missing environment variable names */\n\tmissing: string[];\n\t/** List of environment variables that are provided */\n\tprovided: string[];\n\t/** List of environment variables that were required */\n\trequired: string[];\n}\n\n/**\n * Validate that all required environment variables are present in secrets.\n *\n * @param requiredVars - Array of environment variable names required by the application\n * @param secrets - Stage secrets to validate against\n * @returns Validation result with missing and provided variables\n *\n * @example\n * ```typescript\n * const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];\n * const secrets = await readStageSecrets('production');\n * const result = validateEnvironmentVariables(required, secrets);\n *\n * if (!result.valid) {\n * console.error(`Missing environment variables: ${result.missing.join(', ')}`);\n * }\n * ```\n */\nexport function validateEnvironmentVariables(\n\trequiredVars: string[],\n\tsecrets: StageSecrets,\n): EnvValidationResult {\n\tconst embeddable = toEmbeddableSecrets(secrets);\n\tconst availableVars = new Set(Object.keys(embeddable));\n\n\tconst missing: string[] = [];\n\tconst provided: string[] = [];\n\n\tfor (const varName of requiredVars) {\n\t\tif (availableVars.has(varName)) {\n\t\t\tprovided.push(varName);\n\t\t} else {\n\t\t\tmissing.push(varName);\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: missing.length === 0,\n\t\tmissing: missing.sort(),\n\t\tprovided: provided.sort(),\n\t\trequired: [...requiredVars].sort(),\n\t};\n}\n"],"mappings":";;;;;;AAMA,MAAM,cAAc;;;;AAKpB,SAAgB,cAAc,MAAM,QAAQ,KAAK,EAAU;AAC1D,QAAO,KAAK,KAAK,YAAY;AAC7B;;;;AAKD,SAAgB,eAAeA,OAAe,MAAM,QAAQ,KAAK,EAAU;AAC1E,QAAO,KAAK,cAAc,IAAI,GAAG,EAAE,MAAM,OAAO;AAChD;;;;AAKD,SAAgB,aAAaA,OAAe,MAAM,QAAQ,KAAK,EAAW;AACzE,QAAO,WAAW,eAAe,OAAO,IAAI,CAAC;AAC7C;;;;AAKD,SAAgB,iBAAiBA,OAA6B;CAC7D,MAAM,MAAM,qBAAI,QAAO,aAAa;AACpC,QAAO;EACN;EACA,WAAW;EACX,WAAW;EACX,UAAU,CAAE;EACZ,MAAM,CAAE;EACR,QAAQ,CAAE;CACV;AACD;;;;;AAMD,eAAsB,iBACrBA,OACA,MAAM,QAAQ,KAAK,EACY;CAC/B,MAAM,OAAO,eAAe,OAAO,IAAI;AAEvC,MAAK,WAAW,KAAK,CACpB,QAAO;CAGR,MAAM,UAAU,MAAM,SAAS,MAAM,QAAQ;AAC7C,QAAO,KAAK,MAAM,QAAQ;AAC1B;;;;AAKD,eAAsB,kBACrBC,SACA,MAAM,QAAQ,KAAK,EACH;CAChB,MAAM,MAAM,cAAc,IAAI;CAC9B,MAAM,OAAO,eAAe,QAAQ,OAAO,IAAI;AAG/C,OAAM,MAAM,KAAK,EAAE,WAAW,KAAM,EAAC;AAGrC,OAAM,UAAU,MAAM,KAAK,UAAU,SAAS,MAAM,EAAE,EAAE,QAAQ;AAChE;;;;;AAMD,SAAgB,oBAAoBA,SAA0C;AAC7E,QAAO;EACN,GAAG,QAAQ;EACX,GAAG,QAAQ;EAEX,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,aAAa,QAAQ,SAAS,SAAS,YAAY;GACnD,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;EACrD;EACD,GAAI,QAAQ,SAAS,SAAS;GAC7B,gBAAgB,QAAQ,SAAS,MAAM;GACvC,YAAY,QAAQ,SAAS,MAAM;GACnC,YAAY,OAAO,QAAQ,SAAS,MAAM,KAAK;EAC/C;EACD,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;GACrD,gBAAgB,QAAQ,SAAS,SAAS,SAAS;EACnD;CACD;AACD;;;;AAKD,eAAsB,gBACrBD,OACAE,KACAC,OACA,MAAM,QAAQ,KAAK,EACK;CACxB,MAAM,UAAU,MAAM,iBAAiB,OAAO,IAAI;AAElD,MAAK,QACJ,OAAM,IAAI,OACR,+BAA+B,MAAM,mCAAmC,MAAM;CAIjF,MAAMC,UAAwB;EAC7B,GAAG;EACH,WAAW,qBAAI,QAAO,aAAa;EACnC,QAAQ;GACP,GAAG,QAAQ;IACV,MAAM;EACP;CACD;AAED,OAAM,kBAAkB,SAAS,IAAI;AACrC,QAAO;AACP;;;;AAKD,SAAgB,aAAaC,UAA0B;AACtD,KAAI,SAAS,UAAU,EACtB,QAAO;AAER,SAAQ,EAAE,SAAS,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,OAAO,SAAS,SAAS,EAAE,CAAC,EAAE,SAAS,MAAM,GAAG,CAAC;AACtF;;;;;;;;;;;;;;;;;;;AAkCD,SAAgB,6BACfC,cACAL,SACsB;CACtB,MAAM,aAAa,oBAAoB,QAAQ;CAC/C,MAAM,gBAAgB,IAAI,IAAI,OAAO,KAAK,WAAW;CAErD,MAAMM,UAAoB,CAAE;CAC5B,MAAMC,WAAqB,CAAE;AAE7B,MAAK,MAAM,WAAW,aACrB,KAAI,cAAc,IAAI,QAAQ,CAC7B,UAAS,KAAK,QAAQ;KAEtB,SAAQ,KAAK,QAAQ;AAIvB,QAAO;EACN,OAAO,QAAQ,WAAW;EAC1B,SAAS,QAAQ,MAAM;EACvB,UAAU,SAAS,MAAM;EACzB,UAAU,CAAC,GAAG,YAAa,EAAC,MAAM;CAClC;AACD"}
|
|
@@ -25,6 +25,20 @@ function secretsExist(stage, cwd = process.cwd()) {
|
|
|
25
25
|
return (0, node_fs.existsSync)(getSecretsPath(stage, cwd));
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
+
* Initialize an empty StageSecrets object for a stage.
|
|
29
|
+
*/
|
|
30
|
+
function initStageSecrets(stage) {
|
|
31
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
32
|
+
return {
|
|
33
|
+
stage,
|
|
34
|
+
createdAt: now,
|
|
35
|
+
updatedAt: now,
|
|
36
|
+
services: {},
|
|
37
|
+
urls: {},
|
|
38
|
+
custom: {}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
28
42
|
* Read secrets for a stage.
|
|
29
43
|
* @returns StageSecrets or null if not found
|
|
30
44
|
*/
|
|
@@ -142,6 +156,12 @@ Object.defineProperty(exports, 'getSecretsPath', {
|
|
|
142
156
|
return getSecretsPath;
|
|
143
157
|
}
|
|
144
158
|
});
|
|
159
|
+
Object.defineProperty(exports, 'initStageSecrets', {
|
|
160
|
+
enumerable: true,
|
|
161
|
+
get: function () {
|
|
162
|
+
return initStageSecrets;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
145
165
|
Object.defineProperty(exports, 'maskPassword', {
|
|
146
166
|
enumerable: true,
|
|
147
167
|
get: function () {
|
|
@@ -184,4 +204,4 @@ Object.defineProperty(exports, 'writeStageSecrets', {
|
|
|
184
204
|
return writeStageSecrets;
|
|
185
205
|
}
|
|
186
206
|
});
|
|
187
|
-
//# sourceMappingURL=storage-
|
|
207
|
+
//# sourceMappingURL=storage-Bn3K9Ccu.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-Bn3K9Ccu.cjs","names":["stage: string","secrets: StageSecrets","key: string","value: string","updated: StageSecrets","password: string","requiredVars: string[]","missing: string[]","provided: string[]"],"sources":["../src/secrets/storage.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { EmbeddableSecrets, StageSecrets } from './types';\n\n/** Default secrets directory relative to project root */\nconst SECRETS_DIR = '.gkm/secrets';\n\n/**\n * Get the secrets directory path.\n */\nexport function getSecretsDir(cwd = process.cwd()): string {\n\treturn join(cwd, SECRETS_DIR);\n}\n\n/**\n * Get the secrets file path for a stage.\n */\nexport function getSecretsPath(stage: string, cwd = process.cwd()): string {\n\treturn join(getSecretsDir(cwd), `${stage}.json`);\n}\n\n/**\n * Check if secrets exist for a stage.\n */\nexport function secretsExist(stage: string, cwd = process.cwd()): boolean {\n\treturn existsSync(getSecretsPath(stage, cwd));\n}\n\n/**\n * Initialize an empty StageSecrets object for a stage.\n */\nexport function initStageSecrets(stage: string): StageSecrets {\n\tconst now = new Date().toISOString();\n\treturn {\n\t\tstage,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t\tservices: {},\n\t\turls: {},\n\t\tcustom: {},\n\t};\n}\n\n/**\n * Read secrets for a stage.\n * @returns StageSecrets or null if not found\n */\nexport async function readStageSecrets(\n\tstage: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets | null> {\n\tconst path = getSecretsPath(stage, cwd);\n\n\tif (!existsSync(path)) {\n\t\treturn null;\n\t}\n\n\tconst content = await readFile(path, 'utf-8');\n\treturn JSON.parse(content) as StageSecrets;\n}\n\n/**\n * Write secrets for a stage.\n */\nexport async function writeStageSecrets(\n\tsecrets: StageSecrets,\n\tcwd = process.cwd(),\n): Promise<void> {\n\tconst dir = getSecretsDir(cwd);\n\tconst path = getSecretsPath(secrets.stage, cwd);\n\n\t// Ensure directory exists\n\tawait mkdir(dir, { recursive: true });\n\n\t// Write with pretty formatting\n\tawait writeFile(path, JSON.stringify(secrets, null, 2), 'utf-8');\n}\n\n/**\n * Convert StageSecrets to embeddable format (flat key-value pairs).\n * This is what gets encrypted and embedded in the bundle.\n */\nexport function toEmbeddableSecrets(secrets: StageSecrets): EmbeddableSecrets {\n\treturn {\n\t\t...secrets.urls,\n\t\t...secrets.custom,\n\t\t// Also include individual service credentials if needed\n\t\t...(secrets.services.postgres && {\n\t\t\tPOSTGRES_USER: secrets.services.postgres.username,\n\t\t\tPOSTGRES_PASSWORD: secrets.services.postgres.password,\n\t\t\tPOSTGRES_DB: secrets.services.postgres.database ?? 'app',\n\t\t\tPOSTGRES_HOST: secrets.services.postgres.host,\n\t\t\tPOSTGRES_PORT: String(secrets.services.postgres.port),\n\t\t}),\n\t\t...(secrets.services.redis && {\n\t\t\tREDIS_PASSWORD: secrets.services.redis.password,\n\t\t\tREDIS_HOST: secrets.services.redis.host,\n\t\t\tREDIS_PORT: String(secrets.services.redis.port),\n\t\t}),\n\t\t...(secrets.services.rabbitmq && {\n\t\t\tRABBITMQ_USER: secrets.services.rabbitmq.username,\n\t\t\tRABBITMQ_PASSWORD: secrets.services.rabbitmq.password,\n\t\t\tRABBITMQ_HOST: secrets.services.rabbitmq.host,\n\t\t\tRABBITMQ_PORT: String(secrets.services.rabbitmq.port),\n\t\t\tRABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? '/',\n\t\t}),\n\t};\n}\n\n/**\n * Update a custom secret in the secrets file.\n */\nexport async function setCustomSecret(\n\tstage: string,\n\tkey: string,\n\tvalue: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets> {\n\tconst secrets = await readStageSecrets(stage, cwd);\n\n\tif (!secrets) {\n\t\tthrow new Error(\n\t\t\t`Secrets not found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t}\n\n\tconst updated: StageSecrets = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: {\n\t\t\t...secrets.custom,\n\t\t\t[key]: value,\n\t\t},\n\t};\n\n\tawait writeStageSecrets(updated, cwd);\n\treturn updated;\n}\n\n/**\n * Mask a password for display (show first 4 and last 2 chars).\n */\nexport function maskPassword(password: string): string {\n\tif (password.length <= 8) {\n\t\treturn '********';\n\t}\n\treturn `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;\n}\n\n/**\n * Result of environment variable validation.\n */\nexport interface EnvValidationResult {\n\t/** Whether all required environment variables are present */\n\tvalid: boolean;\n\t/** List of missing environment variable names */\n\tmissing: string[];\n\t/** List of environment variables that are provided */\n\tprovided: string[];\n\t/** List of environment variables that were required */\n\trequired: string[];\n}\n\n/**\n * Validate that all required environment variables are present in secrets.\n *\n * @param requiredVars - Array of environment variable names required by the application\n * @param secrets - Stage secrets to validate against\n * @returns Validation result with missing and provided variables\n *\n * @example\n * ```typescript\n * const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];\n * const secrets = await readStageSecrets('production');\n * const result = validateEnvironmentVariables(required, secrets);\n *\n * if (!result.valid) {\n * console.error(`Missing environment variables: ${result.missing.join(', ')}`);\n * }\n * ```\n */\nexport function validateEnvironmentVariables(\n\trequiredVars: string[],\n\tsecrets: StageSecrets,\n): EnvValidationResult {\n\tconst embeddable = toEmbeddableSecrets(secrets);\n\tconst availableVars = new Set(Object.keys(embeddable));\n\n\tconst missing: string[] = [];\n\tconst provided: string[] = [];\n\n\tfor (const varName of requiredVars) {\n\t\tif (availableVars.has(varName)) {\n\t\t\tprovided.push(varName);\n\t\t} else {\n\t\t\tmissing.push(varName);\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: missing.length === 0,\n\t\tmissing: missing.sort(),\n\t\tprovided: provided.sort(),\n\t\trequired: [...requiredVars].sort(),\n\t};\n}\n"],"mappings":";;;;;;;AAMA,MAAM,cAAc;;;;AAKpB,SAAgB,cAAc,MAAM,QAAQ,KAAK,EAAU;AAC1D,QAAO,oBAAK,KAAK,YAAY;AAC7B;;;;AAKD,SAAgB,eAAeA,OAAe,MAAM,QAAQ,KAAK,EAAU;AAC1E,QAAO,oBAAK,cAAc,IAAI,GAAG,EAAE,MAAM,OAAO;AAChD;;;;AAKD,SAAgB,aAAaA,OAAe,MAAM,QAAQ,KAAK,EAAW;AACzE,QAAO,wBAAW,eAAe,OAAO,IAAI,CAAC;AAC7C;;;;AAKD,SAAgB,iBAAiBA,OAA6B;CAC7D,MAAM,MAAM,qBAAI,QAAO,aAAa;AACpC,QAAO;EACN;EACA,WAAW;EACX,WAAW;EACX,UAAU,CAAE;EACZ,MAAM,CAAE;EACR,QAAQ,CAAE;CACV;AACD;;;;;AAMD,eAAsB,iBACrBA,OACA,MAAM,QAAQ,KAAK,EACY;CAC/B,MAAM,OAAO,eAAe,OAAO,IAAI;AAEvC,MAAK,wBAAW,KAAK,CACpB,QAAO;CAGR,MAAM,UAAU,MAAM,+BAAS,MAAM,QAAQ;AAC7C,QAAO,KAAK,MAAM,QAAQ;AAC1B;;;;AAKD,eAAsB,kBACrBC,SACA,MAAM,QAAQ,KAAK,EACH;CAChB,MAAM,MAAM,cAAc,IAAI;CAC9B,MAAM,OAAO,eAAe,QAAQ,OAAO,IAAI;AAG/C,OAAM,4BAAM,KAAK,EAAE,WAAW,KAAM,EAAC;AAGrC,OAAM,gCAAU,MAAM,KAAK,UAAU,SAAS,MAAM,EAAE,EAAE,QAAQ;AAChE;;;;;AAMD,SAAgB,oBAAoBA,SAA0C;AAC7E,QAAO;EACN,GAAG,QAAQ;EACX,GAAG,QAAQ;EAEX,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,aAAa,QAAQ,SAAS,SAAS,YAAY;GACnD,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;EACrD;EACD,GAAI,QAAQ,SAAS,SAAS;GAC7B,gBAAgB,QAAQ,SAAS,MAAM;GACvC,YAAY,QAAQ,SAAS,MAAM;GACnC,YAAY,OAAO,QAAQ,SAAS,MAAM,KAAK;EAC/C;EACD,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;GACrD,gBAAgB,QAAQ,SAAS,SAAS,SAAS;EACnD;CACD;AACD;;;;AAKD,eAAsB,gBACrBD,OACAE,KACAC,OACA,MAAM,QAAQ,KAAK,EACK;CACxB,MAAM,UAAU,MAAM,iBAAiB,OAAO,IAAI;AAElD,MAAK,QACJ,OAAM,IAAI,OACR,+BAA+B,MAAM,mCAAmC,MAAM;CAIjF,MAAMC,UAAwB;EAC7B,GAAG;EACH,WAAW,qBAAI,QAAO,aAAa;EACnC,QAAQ;GACP,GAAG,QAAQ;IACV,MAAM;EACP;CACD;AAED,OAAM,kBAAkB,SAAS,IAAI;AACrC,QAAO;AACP;;;;AAKD,SAAgB,aAAaC,UAA0B;AACtD,KAAI,SAAS,UAAU,EACtB,QAAO;AAER,SAAQ,EAAE,SAAS,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,OAAO,SAAS,SAAS,EAAE,CAAC,EAAE,SAAS,MAAM,GAAG,CAAC;AACtF;;;;;;;;;;;;;;;;;;;AAkCD,SAAgB,6BACfC,cACAL,SACsB;CACtB,MAAM,aAAa,oBAAoB,QAAQ;CAC/C,MAAM,gBAAgB,IAAI,IAAI,OAAO,KAAK,WAAW;CAErD,MAAMM,UAAoB,CAAE;CAC5B,MAAMC,WAAqB,CAAE;AAE7B,MAAK,MAAM,WAAW,aACrB,KAAI,cAAc,IAAI,QAAQ,CAC7B,UAAS,KAAK,QAAQ;KAEtB,SAAQ,KAAK,QAAQ;AAIvB,QAAO;EACN,OAAO,QAAQ,WAAW;EAC1B,SAAS,QAAQ,MAAM;EACvB,UAAU,SAAS,MAAM;EACzB,UAAU,CAAC,GAAG,YAAa,EAAC,MAAM;CAClC;AACD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const require_storage = require('./storage-Bn3K9Ccu.cjs');
|
|
2
|
+
|
|
3
|
+
exports.initStageSecrets = require_storage.initStageSecrets;
|
|
4
|
+
exports.readStageSecrets = require_storage.readStageSecrets;
|
|
5
|
+
exports.toEmbeddableSecrets = require_storage.toEmbeddableSecrets;
|
|
6
|
+
exports.validateEnvironmentVariables = require_storage.validateEnvironmentVariables;
|
|
7
|
+
exports.writeStageSecrets = require_storage.writeStageSecrets;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { getSecretsDir, getSecretsPath, initStageSecrets, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, validateEnvironmentVariables, writeStageSecrets } from "./storage-BaOP55oq.mjs";
|
|
2
|
+
|
|
3
|
+
export { initStageSecrets, readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, writeStageSecrets };
|
|
@@ -155,6 +155,8 @@ interface DokployProviderConfig {
|
|
|
155
155
|
applicationId: string;
|
|
156
156
|
/** Container registry (overrides docker.registry if set) */
|
|
157
157
|
registry?: string;
|
|
158
|
+
/** Registry ID in Dokploy (recommended for private registries) */
|
|
159
|
+
registryId?: string;
|
|
158
160
|
}
|
|
159
161
|
interface ProvidersConfig {
|
|
160
162
|
aws?: {
|
|
@@ -259,4 +261,4 @@ interface GkmConfig {
|
|
|
259
261
|
}
|
|
260
262
|
//#endregion
|
|
261
263
|
export { GkmConfig, OpenApiConfig };
|
|
262
|
-
//# sourceMappingURL=types-
|
|
264
|
+
//# sourceMappingURL=types-BgaMXsUa.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-
|
|
1
|
+
{"version":3,"file":"types-BgaMXsUa.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;AASiB,KAFL,MAAA,GAEmB,MAAA,GAAA,MAAA,EAAA;AAKd,UALA,cAAA,CAKoB;EAIpB,OAAA,CAAA,EAAA,OAAA;EAIA,SAAA,CAAA,EAAA,MAAA;AA4BjB;AAcY,UAlDK,mBAAA,SAA4B,cAkDf,CAAA,CAG9B;AAAiC,UAjDhB,eAAA,SAAwB,cAiDR,CAAA;AACM,UA9CtB,gBAAA,CA8CsB;EAAa;EAGnC,OAAA,CAAA,EAAA,OAAY;EAAA;EAAA,MAwBhB,CAAA,EAAA,OAAA;EAAqB;EAAqB,MAAA,CAAA,EAAA,OAAA;EAItC;EAAa,WAAA,CAAA,EAAA,MAAA;EAAA;EAIA,gBAJQ,CAAA,EAAA,OAAA;EAAc;EAOxC,QAAA,CAAA,EAAO,MAAA,EAAA;EAEF;EAiBA,WAAA,CAAA,EAAA,SAAY,GAAA,SAAA;EASZ;EAWA,OAAA,CAAA,EAAA,OAAW;EA6BX;AAajB;;;;;;EAQoC,iBAGhB,CAAA,EAAA,OAAA;;AAEsB;AAGzB,UAzJA,aAAA,CAyJS;EAAA;;;;EAGX,KACA,CAAA,EAAA,MAAA;EAAM;;;;EA+BoB,OAmBpB,CAAA,EAAA,MAAA;;;AA8BC,KA/NV,kBAAA,GA+NU,UAAA,GAAA,OAAA,GAAA,UAAA;;KA5NV,qBAAA,WACL,gCAAgC;UAGtB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;eAwBJ,wBAAwB;;;UAIpB,YAAA,SAAqB;;;;eAIxB;;KAGF,OAAA;UAEK,eAAA;;;;;;;;;;;;;;;;UAiBA,YAAA;;;;;;;;UASA,aAAA;;;;;;;;;;UAWA,WAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6BA,qBAAA;;;;;;;;;;;;UAaA,eAAA;;;qBAGC;qBACA;;;4BAGO;wBACJ;;;qBAGD;;sBAEC;;UAGJ,SAAA;UACR;cACI;UACJ;gBACM;;;cAGF;;;;;;;;;;UAUJ;;;;;;;;iCAQuB;;;;;;;;;;8BAUH;;;;;;;;;;;;;;;;;;;sBAmBR;;YAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA4BD"}
|
|
@@ -155,6 +155,8 @@ interface DokployProviderConfig {
|
|
|
155
155
|
applicationId: string;
|
|
156
156
|
/** Container registry (overrides docker.registry if set) */
|
|
157
157
|
registry?: string;
|
|
158
|
+
/** Registry ID in Dokploy (recommended for private registries) */
|
|
159
|
+
registryId?: string;
|
|
158
160
|
}
|
|
159
161
|
interface ProvidersConfig {
|
|
160
162
|
aws?: {
|
|
@@ -259,4 +261,4 @@ interface GkmConfig {
|
|
|
259
261
|
}
|
|
260
262
|
//#endregion
|
|
261
263
|
export { GkmConfig, OpenApiConfig };
|
|
262
|
-
//# sourceMappingURL=types-
|
|
264
|
+
//# sourceMappingURL=types-iFk5ms7y.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-
|
|
1
|
+
{"version":3,"file":"types-iFk5ms7y.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;AASiB,KAFL,MAAA,GAEmB,MAAA,GAAA,MAAA,EAAA;AAKd,UALA,cAAA,CAKoB;EAIpB,OAAA,CAAA,EAAA,OAAA;EAIA,SAAA,CAAA,EAAA,MAAA;AA4BjB;AAcY,UAlDK,mBAAA,SAA4B,cAkDf,CAAA,CAG9B;AAAiC,UAjDhB,eAAA,SAAwB,cAiDR,CAAA;AACM,UA9CtB,gBAAA,CA8CsB;EAAa;EAGnC,OAAA,CAAA,EAAA,OAAY;EAAA;EAAA,MAwBhB,CAAA,EAAA,OAAA;EAAqB;EAAqB,MAAA,CAAA,EAAA,OAAA;EAItC;EAAa,WAAA,CAAA,EAAA,MAAA;EAAA;EAIA,gBAJQ,CAAA,EAAA,OAAA;EAAc;EAOxC,QAAA,CAAA,EAAO,MAAA,EAAA;EAEF;EAiBA,WAAA,CAAA,EAAA,SAAY,GAAA,SAAA;EASZ;EAWA,OAAA,CAAA,EAAA,OAAW;EA6BX;AAajB;;;;;;EAQoC,iBAGhB,CAAA,EAAA,OAAA;;AAEsB;AAGzB,UAzJA,aAAA,CAyJS;EAAA;;;;EAGX,KACA,CAAA,EAAA,MAAA;EAAM;;;;EA+BoB,OAmBpB,CAAA,EAAA,MAAA;;;AA8BC,KA/NV,kBAAA,GA+NU,UAAA,GAAA,OAAA,GAAA,UAAA;;KA5NV,qBAAA,WACL,gCAAgC;UAGtB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;eAwBJ,wBAAwB;;;UAIpB,YAAA,SAAqB;;;;eAIxB;;KAGF,OAAA;UAEK,eAAA;;;;;;;;;;;;;;;;UAiBA,YAAA;;;;;;;;UASA,aAAA;;;;;;;;;;UAWA,WAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6BA,qBAAA;;;;;;;;;;;;UAaA,eAAA;;;qBAGC;qBACA;;;4BAGO;wBACJ;;;qBAGD;;sBAEC;;UAGJ,SAAA;UACR;cACI;UACJ;gBACM;;;cAGF;;;;;;;;;;UAUJ;;;;;;;;iCAQuB;;;;;;;;;;8BAUH;;;;;;;;;;;;;;;;;;;sBAmBR;;YAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA4BD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekmidas/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@geekmidas/constructs": "~0.5.0",
|
|
57
57
|
"@geekmidas/envkit": "~0.3.0",
|
|
58
|
-
"@geekmidas/logger": "~0.4.0",
|
|
59
58
|
"@geekmidas/schema": "~0.1.0",
|
|
60
|
-
"@geekmidas/telescope": "~0.4.0"
|
|
59
|
+
"@geekmidas/telescope": "~0.4.0",
|
|
60
|
+
"@geekmidas/logger": "~0.4.0"
|
|
61
61
|
},
|
|
62
62
|
"peerDependenciesMeta": {
|
|
63
63
|
"@geekmidas/telescope": {
|
|
@@ -8,10 +8,12 @@ import {
|
|
|
8
8
|
getCredentialsDir,
|
|
9
9
|
getCredentialsPath,
|
|
10
10
|
getDokployCredentials,
|
|
11
|
+
getDokployRegistryId,
|
|
11
12
|
getDokployToken,
|
|
12
13
|
readCredentials,
|
|
13
14
|
removeDokployCredentials,
|
|
14
15
|
storeDokployCredentials,
|
|
16
|
+
storeDokployRegistryId,
|
|
15
17
|
writeCredentials,
|
|
16
18
|
} from '../credentials';
|
|
17
19
|
|
|
@@ -201,4 +203,129 @@ describe('credentials storage', () => {
|
|
|
201
203
|
expect(token).toBe('stored-token');
|
|
202
204
|
});
|
|
203
205
|
});
|
|
206
|
+
|
|
207
|
+
describe('storeDokployRegistryId', () => {
|
|
208
|
+
it('should throw error when no dokploy credentials exist', async () => {
|
|
209
|
+
await expect(
|
|
210
|
+
storeDokployRegistryId('reg_123', { root: tempDir }),
|
|
211
|
+
).rejects.toThrow('Dokploy credentials not found');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should store registryId with existing credentials', async () => {
|
|
215
|
+
await storeDokployCredentials('token', 'https://test.com', {
|
|
216
|
+
root: tempDir,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
await storeDokployRegistryId('reg_123', { root: tempDir });
|
|
220
|
+
|
|
221
|
+
const creds = await readCredentials({ root: tempDir });
|
|
222
|
+
expect(creds.dokploy?.registryId).toBe('reg_123');
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should overwrite existing registryId', async () => {
|
|
226
|
+
await storeDokployCredentials('token', 'https://test.com', {
|
|
227
|
+
root: tempDir,
|
|
228
|
+
});
|
|
229
|
+
await storeDokployRegistryId('old_reg', { root: tempDir });
|
|
230
|
+
await storeDokployRegistryId('new_reg', { root: tempDir });
|
|
231
|
+
|
|
232
|
+
const creds = await readCredentials({ root: tempDir });
|
|
233
|
+
expect(creds.dokploy?.registryId).toBe('new_reg');
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
describe('getDokployRegistryId', () => {
|
|
238
|
+
it('should return undefined when no credentials exist', async () => {
|
|
239
|
+
const registryId = await getDokployRegistryId({ root: tempDir });
|
|
240
|
+
expect(registryId).toBeUndefined();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('should return undefined when credentials exist but no registryId', async () => {
|
|
244
|
+
await storeDokployCredentials('token', 'https://test.com', {
|
|
245
|
+
root: tempDir,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const registryId = await getDokployRegistryId({ root: tempDir });
|
|
249
|
+
expect(registryId).toBeUndefined();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should return stored registryId', async () => {
|
|
253
|
+
await storeDokployCredentials('token', 'https://test.com', {
|
|
254
|
+
root: tempDir,
|
|
255
|
+
});
|
|
256
|
+
await storeDokployRegistryId('reg_456', { root: tempDir });
|
|
257
|
+
|
|
258
|
+
const registryId = await getDokployRegistryId({ root: tempDir });
|
|
259
|
+
expect(registryId).toBe('reg_456');
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe('getDokployCredentials with registryId', () => {
|
|
264
|
+
it('should return registryId when stored', async () => {
|
|
265
|
+
await storeDokployCredentials('token', 'https://test.com', {
|
|
266
|
+
root: tempDir,
|
|
267
|
+
});
|
|
268
|
+
await storeDokployRegistryId('reg_789', { root: tempDir });
|
|
269
|
+
|
|
270
|
+
const creds = await getDokployCredentials({ root: tempDir });
|
|
271
|
+
expect(creds).toEqual({
|
|
272
|
+
token: 'token',
|
|
273
|
+
endpoint: 'https://test.com',
|
|
274
|
+
registryId: 'reg_789',
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should return undefined registryId when not stored', async () => {
|
|
279
|
+
await storeDokployCredentials('token', 'https://test.com', {
|
|
280
|
+
root: tempDir,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const creds = await getDokployCredentials({ root: tempDir });
|
|
284
|
+
expect(creds?.registryId).toBeUndefined();
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe('getDokployEndpoint', () => {
|
|
289
|
+
it('should return null when no credentials exist', async () => {
|
|
290
|
+
const { getDokployEndpoint } = await import('../credentials');
|
|
291
|
+
const endpoint = await getDokployEndpoint({ root: tempDir });
|
|
292
|
+
expect(endpoint).toBeNull();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should return stored endpoint', async () => {
|
|
296
|
+
const { getDokployEndpoint } = await import('../credentials');
|
|
297
|
+
await storeDokployCredentials('token', 'https://my-dokploy.com', {
|
|
298
|
+
root: tempDir,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const endpoint = await getDokployEndpoint({ root: tempDir });
|
|
302
|
+
expect(endpoint).toBe('https://my-dokploy.com');
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
describe('removeAllCredentials', () => {
|
|
307
|
+
it('should remove credentials file', async () => {
|
|
308
|
+
const { removeAllCredentials } = await import('../credentials');
|
|
309
|
+
await storeDokployCredentials('token', 'https://test.com', {
|
|
310
|
+
root: tempDir,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Verify file exists
|
|
314
|
+
const pathBefore = getCredentialsPath({ root: tempDir });
|
|
315
|
+
expect(existsSync(pathBefore)).toBe(true);
|
|
316
|
+
|
|
317
|
+
await removeAllCredentials({ root: tempDir });
|
|
318
|
+
|
|
319
|
+
// Verify file is removed
|
|
320
|
+
expect(existsSync(pathBefore)).toBe(false);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('should not throw when credentials file does not exist', async () => {
|
|
324
|
+
const { removeAllCredentials } = await import('../credentials');
|
|
325
|
+
// Should not throw
|
|
326
|
+
await expect(
|
|
327
|
+
removeAllCredentials({ root: tempDir }),
|
|
328
|
+
).resolves.toBeUndefined();
|
|
329
|
+
});
|
|
330
|
+
});
|
|
204
331
|
});
|
|
@@ -166,3 +166,72 @@ describe('URL normalization', () => {
|
|
|
166
166
|
expect(() => new URL('invalid-url')).toThrow();
|
|
167
167
|
});
|
|
168
168
|
});
|
|
169
|
+
|
|
170
|
+
describe('logoutCommand', () => {
|
|
171
|
+
let tempDir: string;
|
|
172
|
+
|
|
173
|
+
beforeEach(async () => {
|
|
174
|
+
tempDir = join(tmpdir(), `gkm-logout-test-${Date.now()}`);
|
|
175
|
+
await mkdir(tempDir, { recursive: true });
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
afterEach(async () => {
|
|
179
|
+
if (existsSync(tempDir)) {
|
|
180
|
+
await rm(tempDir, { recursive: true });
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should remove dokploy credentials', async () => {
|
|
185
|
+
// First store credentials
|
|
186
|
+
await storeDokployCredentials('my-token', 'https://dokploy.example.com', {
|
|
187
|
+
root: tempDir,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Verify they exist
|
|
191
|
+
let creds = await getDokployCredentials({ root: tempDir });
|
|
192
|
+
expect(creds).not.toBeNull();
|
|
193
|
+
|
|
194
|
+
// Remove credentials
|
|
195
|
+
const removed = await removeDokployCredentials({ root: tempDir });
|
|
196
|
+
expect(removed).toBe(true);
|
|
197
|
+
|
|
198
|
+
// Verify they're gone
|
|
199
|
+
creds = await getDokployCredentials({ root: tempDir });
|
|
200
|
+
expect(creds).toBeNull();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should return false when no credentials to remove', async () => {
|
|
204
|
+
const removed = await removeDokployCredentials({ root: tempDir });
|
|
205
|
+
expect(removed).toBe(false);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe('whoamiCommand helpers', () => {
|
|
210
|
+
let tempDir: string;
|
|
211
|
+
|
|
212
|
+
beforeEach(async () => {
|
|
213
|
+
tempDir = join(tmpdir(), `gkm-whoami-test-${Date.now()}`);
|
|
214
|
+
await mkdir(tempDir, { recursive: true });
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
afterEach(async () => {
|
|
218
|
+
if (existsSync(tempDir)) {
|
|
219
|
+
await rm(tempDir, { recursive: true });
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should return null when no credentials stored', async () => {
|
|
224
|
+
const creds = await getDokployCredentials({ root: tempDir });
|
|
225
|
+
expect(creds).toBeNull();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should return credentials when stored', async () => {
|
|
229
|
+
await storeDokployCredentials('test-token', 'https://test.example.com', {
|
|
230
|
+
root: tempDir,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const creds = await getDokployCredentials({ root: tempDir });
|
|
234
|
+
expect(creds).not.toBeNull();
|
|
235
|
+
expect(creds!.endpoint).toBe('https://test.example.com');
|
|
236
|
+
});
|
|
237
|
+
});
|