appflare 0.0.27 → 0.0.28

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.
@@ -0,0 +1,121 @@
1
+ import ts from "typescript";
2
+ import fs from "fs";
3
+
4
+ export function extractClientConfig(configPath: string): string | null {
5
+ if (!fs.existsSync(configPath)) {
6
+ return null;
7
+ }
8
+
9
+ const sourceCode = fs.readFileSync(configPath, "utf-8");
10
+ const sourceFile = ts.createSourceFile(
11
+ "appflare.config.ts",
12
+ sourceCode,
13
+ ts.ScriptTarget.Latest,
14
+ true,
15
+ );
16
+
17
+ let clientOptionsNode: ts.Expression | undefined;
18
+
19
+ // 1. Find the default export
20
+ // 2. Find the 'auth' property in the object literal
21
+ // 3. Find the 'clientOptions' property in the 'auth' object literal
22
+
23
+ function findClientOptions(node: ts.Node) {
24
+ if (ts.isExportAssignment(node)) {
25
+ const expr = node.expression;
26
+ if (ts.isObjectLiteralExpression(expr)) {
27
+ const authProp = expr.properties.find(
28
+ (p) =>
29
+ ts.isPropertyAssignment(p) &&
30
+ ts.isIdentifier(p.name) &&
31
+ p.name.text === "auth",
32
+ ) as ts.PropertyAssignment | undefined;
33
+
34
+ if (authProp && ts.isObjectLiteralExpression(authProp.initializer)) {
35
+ const clientOptionsProp = authProp.initializer.properties.find(
36
+ (p) =>
37
+ ts.isPropertyAssignment(p) &&
38
+ ts.isIdentifier(p.name) &&
39
+ p.name.text === "clientOptions",
40
+ ) as ts.PropertyAssignment | undefined;
41
+
42
+ if (clientOptionsProp) {
43
+ clientOptionsNode = clientOptionsProp.initializer;
44
+ }
45
+ }
46
+ }
47
+ }
48
+ ts.forEachChild(node, findClientOptions);
49
+ }
50
+
51
+ findClientOptions(sourceFile);
52
+
53
+ if (!clientOptionsNode) {
54
+ return null;
55
+ }
56
+
57
+ const clientOptionsText = clientOptionsNode.getText(sourceFile);
58
+
59
+ // 4. Identify identifiers used in clientOptionsText to find necessary imports
60
+ const usedIdentifiers = new Set<string>();
61
+
62
+ function findIdentifiers(node: ts.Node) {
63
+ if (ts.isIdentifier(node)) {
64
+ usedIdentifiers.add(node.text);
65
+ }
66
+ ts.forEachChild(node, findIdentifiers);
67
+ }
68
+
69
+ findIdentifiers(clientOptionsNode);
70
+
71
+ // 5. Scan top-level imports to find matching named imports
72
+ const importsToKeep: string[] = [];
73
+
74
+ for (const statement of sourceFile.statements) {
75
+ if (ts.isImportDeclaration(statement)) {
76
+ const importClause = statement.importClause;
77
+ if (!importClause) continue;
78
+
79
+ const moduleSpecifier = statement.moduleSpecifier.getText(sourceFile);
80
+
81
+ // Check for named imports
82
+ if (
83
+ importClause.namedBindings &&
84
+ ts.isNamedImports(importClause.namedBindings)
85
+ ) {
86
+ const keepElements: string[] = [];
87
+ for (const element of importClause.namedBindings.elements) {
88
+ if (usedIdentifiers.has(element.name.text)) {
89
+ keepElements.push(element.getText(sourceFile));
90
+ }
91
+ }
92
+ if (keepElements.length > 0) {
93
+ importsToKeep.push(
94
+ `import { ${keepElements.join(", ")} } from ${moduleSpecifier};`,
95
+ );
96
+ }
97
+ }
98
+
99
+ // Check for default import
100
+ if (importClause.name && usedIdentifiers.has(importClause.name.text)) {
101
+ importsToKeep.push(
102
+ `import ${importClause.name.text} from ${moduleSpecifier};`,
103
+ );
104
+ }
105
+
106
+ // Check for namespace import
107
+ if (
108
+ importClause.namedBindings &&
109
+ ts.isNamespaceImport(importClause.namedBindings)
110
+ ) {
111
+ if (usedIdentifiers.has(importClause.namedBindings.name.text)) {
112
+ importsToKeep.push(
113
+ `import * as ${importClause.namedBindings.name.text} from ${moduleSpecifier};`,
114
+ );
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ return `${importsToKeep.join("\n")}\n\nexport const clientOptions = ${clientOptionsText};`;
121
+ }
@@ -15,6 +15,7 @@ import {
15
15
  generateInternalTypeLines,
16
16
  } from "./types";
17
17
  import { renderObjectKey } from "./utils";
18
+ import { extractClientConfig } from "./extract-configuration";
18
19
 
19
20
  const HEADER_TEMPLATE = `/* eslint-disable */
20
21
  /**
@@ -833,7 +834,7 @@ export function generateApiClient(params: {
833
834
  authBasePath?: string;
834
835
  authEnabled?: boolean;
835
836
  configPathAbs?: string;
836
- }): string {
837
+ }): { apiTs: string; clientConfigTs: string | null } {
837
838
  const { importLines, importAliasBySource } = generateImports(params);
838
839
  const {
839
840
  queriesByFile,
@@ -892,15 +893,17 @@ export function generateApiClient(params: {
892
893
  buildUrl(baseUrl, authBasePath),
893
894
  });`;
894
895
 
896
+ const clientConfigTs =
897
+ params.authEnabled && params.configPathAbs
898
+ ? extractClientConfig(params.configPathAbs)
899
+ : null;
900
+
895
901
  if (params.authEnabled && params.configPathAbs) {
896
- const configImportPath = toImportPathFromGeneratedSrc(
897
- params.outDirAbs,
898
- params.configPathAbs,
899
- );
900
- configImport = `\nimport __appflareConfig from ${JSON.stringify(configImportPath)};`;
902
+ if (clientConfigTs) {
903
+ configImport = `\nimport { clientOptions } from "./client.config";`;
901
904
 
902
- // Use a factory function pattern to properly infer the client type from clientOptions
903
- authClientTypeDefinitions = `const __getAppflareAuthClientOptions = () => (__appflareConfig.auth?.clientOptions ?? {}) as const;
905
+ // Use a factory function pattern to properly infer the client type from clientOptions
906
+ authClientTypeDefinitions = `const __getAppflareAuthClientOptions = () => (clientOptions ?? {}) as const;
904
907
  type AppflareAuthClientOptions = ReturnType<typeof __getAppflareAuthClientOptions>;
905
908
  const __createTypedAuthClient = (baseURL: string) => createAuthClient({
906
909
  ...__getAppflareAuthClientOptions(),
@@ -908,37 +911,63 @@ const __createTypedAuthClient = (baseURL: string) => createAuthClient({
908
911
  });
909
912
  type AppflareAuthClient = ReturnType<typeof __createTypedAuthClient>;`;
910
913
 
911
- authClientInit = ` const auth = createAuthClient({
914
+ authClientInit = ` const auth = createAuthClient({
912
915
  ...__getAppflareAuthClientOptions(),
913
916
  ...(options.auth ?? {}),
914
917
  baseURL:
915
918
  (options.auth as any)?.baseURL ??
916
919
  buildUrl(baseUrl, authBasePath),
917
920
  });`;
921
+ } else {
922
+ const configImportPath = toImportPathFromGeneratedSrc(
923
+ params.outDirAbs,
924
+ params.configPathAbs,
925
+ );
926
+ configImport = `\nimport __appflareConfig from ${JSON.stringify(configImportPath)};`;
927
+
928
+ // Use a factory function pattern to properly infer the client type from clientOptions
929
+ authClientTypeDefinitions = `const __getAppflareAuthClientOptions = () => (__appflareConfig.auth?.clientOptions ?? {}) as const;
930
+ type AppflareAuthClientOptions = ReturnType<typeof __getAppflareAuthClientOptions>;
931
+ const __createTypedAuthClient = (baseURL: string) => createAuthClient({
932
+ ...__getAppflareAuthClientOptions(),
933
+ baseURL,
934
+ });
935
+ type AppflareAuthClient = ReturnType<typeof __createTypedAuthClient>;`;
936
+
937
+ authClientInit = ` const auth = createAuthClient({
938
+ ...__getAppflareAuthClientOptions(),
939
+ ...(options.auth ?? {}),
940
+ baseURL:
941
+ (options.auth as any)?.baseURL ??
942
+ buildUrl(baseUrl, authBasePath),
943
+ });`;
944
+ }
918
945
  }
919
946
 
920
947
  const typeBlocks = generateTypeBlocks(params.handlers, importAliasBySource);
921
948
 
922
- return (
923
- HEADER_TEMPLATE.replace("{{configImport}}", configImport) +
924
- importLines.join("\n") +
925
- TYPE_DEFINITIONS_TEMPLATE +
926
- typeBlocks.join("\n\n") +
927
- INTERNAL_TEMPLATE.replace(
928
- "{{internalQueriesTypeDef}}",
929
- internalQueriesTypeDef,
930
- )
931
- .replace("{{internalMutationsTypeDef}}", internalMutationsTypeDef)
932
- .replace("{{internalInit}}", internalInit)
933
- .replace("{{internalQueriesMeta}}", internalQueriesMeta)
934
- .replace("{{internalMutationsMeta}}", internalMutationsMeta) +
935
- CLIENT_TYPES_TEMPLATE.replace("{{queriesTypeDef}}", queriesTypeDef)
936
- .replace("{{mutationsTypeDef}}", mutationsTypeDef)
937
- .replace("{{queriesInit}}", queriesInit)
938
- .replace("{{mutationsInit}}", mutationsInit)
939
- .replace("{{authBasePath}}", authBasePathLiteral)
940
- .replace("{{authClientTypeDefinitions}}", authClientTypeDefinitions)
941
- .replace("{{authClientInit}}", authClientInit) +
942
- UTILITY_FUNCTIONS_TEMPLATE
943
- );
949
+ return {
950
+ apiTs:
951
+ HEADER_TEMPLATE.replace("{{configImport}}", configImport) +
952
+ importLines.join("\n") +
953
+ TYPE_DEFINITIONS_TEMPLATE +
954
+ typeBlocks.join("\n\n") +
955
+ INTERNAL_TEMPLATE.replace(
956
+ "{{internalQueriesTypeDef}}",
957
+ internalQueriesTypeDef,
958
+ )
959
+ .replace("{{internalMutationsTypeDef}}", internalMutationsTypeDef)
960
+ .replace("{{internalInit}}", internalInit)
961
+ .replace("{{internalQueriesMeta}}", internalQueriesMeta)
962
+ .replace("{{internalMutationsMeta}}", internalMutationsMeta) +
963
+ CLIENT_TYPES_TEMPLATE.replace("{{queriesTypeDef}}", queriesTypeDef)
964
+ .replace("{{mutationsTypeDef}}", mutationsTypeDef)
965
+ .replace("{{queriesInit}}", queriesInit)
966
+ .replace("{{mutationsInit}}", mutationsInit)
967
+ .replace("{{authBasePath}}", authBasePathLiteral)
968
+ .replace("{{authClientTypeDefinitions}}", authClientTypeDefinitions)
969
+ .replace("{{authClientInit}}", authClientInit) +
970
+ UTILITY_FUNCTIONS_TEMPLATE,
971
+ clientConfigTs,
972
+ };
944
973
  }
package/cli/index.ts CHANGED
@@ -219,7 +219,7 @@ export default schema;
219
219
  configPathAbs,
220
220
  });
221
221
 
222
- const apiTs = generateApiClient({
222
+ const { apiTs, clientConfigTs } = generateApiClient({
223
223
  handlers,
224
224
  outDirAbs,
225
225
  authBasePath:
@@ -230,6 +230,12 @@ export default schema;
230
230
  configPathAbs,
231
231
  });
232
232
  await fs.writeFile(path.join(outDirAbs, "src", "api.ts"), apiTs);
233
+ if (clientConfigTs) {
234
+ await fs.writeFile(
235
+ path.join(outDirAbs, "src", "client.config.ts"),
236
+ clientConfigTs,
237
+ );
238
+ }
233
239
 
234
240
  const serverTs = generateHonoServer({
235
241
  handlers,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appflare",
3
- "version": "0.0.27",
3
+ "version": "0.0.28",
4
4
  "bin": {
5
5
  "appflare": "./cli/index.ts"
6
6
  },