appwrite-utils-cli 1.7.7 → 1.7.9
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/SELECTION_DIALOGS.md +146 -0
- package/dist/cli/commands/databaseCommands.js +89 -23
- package/dist/config/services/ConfigLoaderService.d.ts +7 -0
- package/dist/config/services/ConfigLoaderService.js +47 -1
- package/dist/functions/deployments.js +5 -23
- package/dist/functions/methods.js +4 -2
- package/dist/functions/pathResolution.d.ts +37 -0
- package/dist/functions/pathResolution.js +185 -0
- package/dist/functions/templates/count-docs-in-collection/README.md +54 -0
- package/dist/functions/templates/count-docs-in-collection/package.json +25 -0
- package/dist/functions/templates/count-docs-in-collection/src/main.ts +159 -0
- package/dist/functions/templates/count-docs-in-collection/src/request.ts +9 -0
- package/dist/functions/templates/count-docs-in-collection/tsconfig.json +28 -0
- package/dist/functions/templates/hono-typescript/README.md +286 -0
- package/dist/functions/templates/hono-typescript/package.json +26 -0
- package/dist/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
- package/dist/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
- package/dist/functions/templates/hono-typescript/src/app.ts +180 -0
- package/dist/functions/templates/hono-typescript/src/context.ts +103 -0
- package/dist/functions/templates/hono-typescript/src/index.ts +54 -0
- package/dist/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
- package/dist/functions/templates/hono-typescript/tsconfig.json +20 -0
- package/dist/functions/templates/typescript-node/README.md +32 -0
- package/dist/functions/templates/typescript-node/package.json +25 -0
- package/dist/functions/templates/typescript-node/src/context.ts +103 -0
- package/dist/functions/templates/typescript-node/src/index.ts +29 -0
- package/dist/functions/templates/typescript-node/tsconfig.json +28 -0
- package/dist/functions/templates/uv/README.md +31 -0
- package/dist/functions/templates/uv/pyproject.toml +30 -0
- package/dist/functions/templates/uv/src/__init__.py +0 -0
- package/dist/functions/templates/uv/src/context.py +125 -0
- package/dist/functions/templates/uv/src/index.py +46 -0
- package/dist/main.js +175 -4
- package/dist/migrations/appwriteToX.d.ts +27 -2
- package/dist/migrations/appwriteToX.js +293 -69
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +1 -1
- package/dist/migrations/yaml/generateImportSchemas.js +23 -8
- package/dist/shared/schemaGenerator.js +25 -12
- package/dist/shared/selectionDialogs.d.ts +214 -0
- package/dist/shared/selectionDialogs.js +540 -0
- package/dist/utils/configDiscovery.d.ts +4 -4
- package/dist/utils/configDiscovery.js +66 -30
- package/dist/utils/yamlConverter.d.ts +1 -0
- package/dist/utils/yamlConverter.js +26 -3
- package/dist/utilsController.d.ts +7 -1
- package/dist/utilsController.js +198 -17
- package/package.json +4 -2
- package/scripts/copy-templates.ts +23 -0
- package/src/cli/commands/databaseCommands.ts +133 -34
- package/src/config/services/ConfigLoaderService.ts +62 -1
- package/src/functions/deployments.ts +10 -35
- package/src/functions/methods.ts +4 -2
- package/src/functions/pathResolution.ts +227 -0
- package/src/main.ts +276 -34
- package/src/migrations/appwriteToX.ts +385 -90
- package/src/migrations/yaml/generateImportSchemas.ts +26 -8
- package/src/shared/schemaGenerator.ts +29 -12
- package/src/shared/selectionDialogs.ts +745 -0
- package/src/utils/configDiscovery.ts +83 -39
- package/src/utils/yamlConverter.ts +29 -3
- package/src/utilsController.ts +250 -22
- package/dist/utils/schemaStrings.d.ts +0 -14
- package/dist/utils/schemaStrings.js +0 -428
- package/dist/utils/sessionPreservationExample.d.ts +0 -1666
- package/dist/utils/sessionPreservationExample.js +0 -101
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Appwrite Request Headers Schema
|
|
5
|
+
*/
|
|
6
|
+
export const AppwriteHeadersSchema = z.object({
|
|
7
|
+
"x-appwrite-trigger": z.enum(["http", "schedule", "event"]).optional(),
|
|
8
|
+
"x-appwrite-event": z.string().optional(),
|
|
9
|
+
"x-appwrite-key": z.string().optional(),
|
|
10
|
+
"x-appwrite-user-id": z.string().optional(),
|
|
11
|
+
"x-appwrite-user-jwt": z.string().optional(),
|
|
12
|
+
"x-appwrite-country-code": z.string().optional(),
|
|
13
|
+
"x-appwrite-continent-code": z.string().optional(),
|
|
14
|
+
"x-appwrite-continent-eu": z.string().optional(),
|
|
15
|
+
}).catchall(z.string()); // Allow additional headers
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Appwrite Environment Variables Schema
|
|
19
|
+
*/
|
|
20
|
+
export const AppwriteEnvSchema = z.object({
|
|
21
|
+
APPWRITE_FUNCTION_API_ENDPOINT: z.string(),
|
|
22
|
+
APPWRITE_VERSION: z.string(),
|
|
23
|
+
APPWRITE_REGION: z.string(),
|
|
24
|
+
APPWRITE_FUNCTION_API_KEY: z.string().optional(),
|
|
25
|
+
APPWRITE_FUNCTION_ID: z.string(),
|
|
26
|
+
APPWRITE_FUNCTION_NAME: z.string(),
|
|
27
|
+
APPWRITE_FUNCTION_DEPLOYMENT: z.string(),
|
|
28
|
+
APPWRITE_FUNCTION_PROJECT_ID: z.string(),
|
|
29
|
+
APPWRITE_FUNCTION_RUNTIME_NAME: z.string(),
|
|
30
|
+
APPWRITE_FUNCTION_RUNTIME_VERSION: z.string(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Appwrite Request Schema (full version from docs)
|
|
35
|
+
*/
|
|
36
|
+
export const AppwriteRequestSchema = z.object({
|
|
37
|
+
bodyText: z.string().optional(),
|
|
38
|
+
bodyJson: z.union([z.any(), z.string()]).transform((t) => {
|
|
39
|
+
if (typeof t === "string") {
|
|
40
|
+
try {
|
|
41
|
+
return JSON.parse(t);
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return t;
|
|
47
|
+
}).optional(),
|
|
48
|
+
body: z.any().optional(),
|
|
49
|
+
headers: AppwriteHeadersSchema,
|
|
50
|
+
scheme: z.enum(["http", "https"]).optional(),
|
|
51
|
+
method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"]),
|
|
52
|
+
url: z.string().optional(),
|
|
53
|
+
host: z.string().optional(),
|
|
54
|
+
port: z.number().or(z.string()).optional(),
|
|
55
|
+
path: z.string().optional(),
|
|
56
|
+
queryString: z.string().optional(),
|
|
57
|
+
query: z.record(z.string(), z.any()).optional(),
|
|
58
|
+
variables: z.record(z.string(), z.any()).optional(),
|
|
59
|
+
text: z.any().optional(),
|
|
60
|
+
payload: z.string().optional(),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Appwrite Response Schema
|
|
65
|
+
*/
|
|
66
|
+
export const AppwriteResponseSchema = z.object({
|
|
67
|
+
json: z.any(),
|
|
68
|
+
text: z.any(),
|
|
69
|
+
empty: z.any().optional(),
|
|
70
|
+
binary: z.any().optional(),
|
|
71
|
+
redirect: z.any().optional(),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Log Function Schema - Simple function type
|
|
76
|
+
*/
|
|
77
|
+
export const AppwriteLogSchema = z.any();
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Error Function Schema - Simple function type
|
|
81
|
+
*/
|
|
82
|
+
export const AppwriteErrorSchema = z.any();
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Complete Appwrite Context Schema
|
|
86
|
+
*/
|
|
87
|
+
export const AppwriteContextSchema = z.object({
|
|
88
|
+
req: AppwriteRequestSchema,
|
|
89
|
+
res: AppwriteResponseSchema,
|
|
90
|
+
log: AppwriteLogSchema,
|
|
91
|
+
error: AppwriteErrorSchema,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Type inference helpers
|
|
96
|
+
*/
|
|
97
|
+
export type AppwriteHeaders = z.infer<typeof AppwriteHeadersSchema>;
|
|
98
|
+
export type AppwriteEnv = z.infer<typeof AppwriteEnvSchema>;
|
|
99
|
+
export type AppwriteRequest = z.infer<typeof AppwriteRequestSchema>;
|
|
100
|
+
export type AppwriteResponse = z.infer<typeof AppwriteResponseSchema>;
|
|
101
|
+
export type AppwriteLog = z.infer<typeof AppwriteLogSchema>;
|
|
102
|
+
export type AppwriteError = z.infer<typeof AppwriteErrorSchema>;
|
|
103
|
+
export type AppwriteContext = z.infer<typeof AppwriteContextSchema>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { app } from "./app.js";
|
|
2
|
+
import { AppwriteContext, AppwriteContextSchema } from "./context.js";
|
|
3
|
+
import { convertAppwriteToWebRequest } from "./adapters/request.js";
|
|
4
|
+
import { convertWebResponseToAppwrite } from "./adapters/response.js";
|
|
5
|
+
import { appwriteMiddleware } from "./middleware/appwrite.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Main Appwrite function entry point
|
|
9
|
+
* This function receives the Appwrite context and routes it through Hono
|
|
10
|
+
*/
|
|
11
|
+
export default async function (context: AppwriteContext) {
|
|
12
|
+
const { req, res, log, error } = context;
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// Optional: Validate the context using Zod schema
|
|
16
|
+
AppwriteContextSchema.parse(context);
|
|
17
|
+
log("Context validation successful");
|
|
18
|
+
|
|
19
|
+
// Add Appwrite context middleware to the Hono app
|
|
20
|
+
app.use("*", appwriteMiddleware(context));
|
|
21
|
+
|
|
22
|
+
// Convert Appwrite request to Web API Request for Hono
|
|
23
|
+
const webRequest = convertAppwriteToWebRequest(req);
|
|
24
|
+
|
|
25
|
+
log(`Processing ${req.method} request to ${req.path || "/"}`);
|
|
26
|
+
|
|
27
|
+
// Create execution environment for Hono
|
|
28
|
+
const env = {
|
|
29
|
+
// Add any environment variables or context needed by Hono
|
|
30
|
+
APPWRITE_FUNCTION_ENDPOINT: process.env["APPWRITE_FUNCTION_ENDPOINT"],
|
|
31
|
+
APPWRITE_FUNCTION_PROJECT_ID: process.env["APPWRITE_FUNCTION_PROJECT_ID"],
|
|
32
|
+
APPWRITE_FUNCTION_API_KEY: process.env["APPWRITE_FUNCTION_API_KEY"],
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Process request through Hono app
|
|
36
|
+
const honoResponse = await app.fetch(webRequest, env);
|
|
37
|
+
|
|
38
|
+
// Convert Hono response back to Appwrite response format
|
|
39
|
+
await convertWebResponseToAppwrite(honoResponse, res);
|
|
40
|
+
|
|
41
|
+
log(`Request completed with status ${honoResponse.status}`);
|
|
42
|
+
|
|
43
|
+
} catch (validationError) {
|
|
44
|
+
error(`Function execution failed: ${validationError}`);
|
|
45
|
+
|
|
46
|
+
// Return error response
|
|
47
|
+
return res.json({
|
|
48
|
+
error: "Function execution failed",
|
|
49
|
+
message: validationError instanceof Error ? validationError.message : String(validationError),
|
|
50
|
+
functionName: "{{functionName}}",
|
|
51
|
+
timestamp: new Date().toISOString(),
|
|
52
|
+
}, 500);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from "hono";
|
|
2
|
+
import type { AppwriteContext } from "../context.js";
|
|
3
|
+
|
|
4
|
+
// Extend Hono's context to include Appwrite context
|
|
5
|
+
declare module "hono" {
|
|
6
|
+
interface ContextVariableMap {
|
|
7
|
+
appwriteContext: AppwriteContext;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Middleware to inject Appwrite context into Hono
|
|
13
|
+
*/
|
|
14
|
+
export const appwriteMiddleware = (appwriteContext: AppwriteContext): MiddlewareHandler => {
|
|
15
|
+
return async (c, next) => {
|
|
16
|
+
// Inject Appwrite context into Hono context
|
|
17
|
+
c.set("appwriteContext", appwriteContext);
|
|
18
|
+
|
|
19
|
+
// Add logging helper methods to Hono context
|
|
20
|
+
c.log = (message: string) => {
|
|
21
|
+
appwriteContext.log(`[${c.req.method} ${c.req.path}] ${message}`);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
c.error = (message: string) => {
|
|
25
|
+
appwriteContext.error(`[${c.req.method} ${c.req.path}] ${message}`);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
await next();
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Middleware for request logging
|
|
34
|
+
*/
|
|
35
|
+
export const requestLogger = (): MiddlewareHandler => {
|
|
36
|
+
return async (c, next) => {
|
|
37
|
+
const start = Date.now();
|
|
38
|
+
const appwriteContext = c.get("appwriteContext");
|
|
39
|
+
|
|
40
|
+
appwriteContext?.log(`→ ${c.req.method} ${c.req.path}`);
|
|
41
|
+
|
|
42
|
+
await next();
|
|
43
|
+
|
|
44
|
+
const duration = Date.now() - start;
|
|
45
|
+
appwriteContext?.log(`← ${c.req.method} ${c.req.path} ${c.res.status} (${duration}ms)`);
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Middleware for error handling
|
|
51
|
+
*/
|
|
52
|
+
export const errorHandler = (): MiddlewareHandler => {
|
|
53
|
+
return async (c, next) => {
|
|
54
|
+
try {
|
|
55
|
+
await next();
|
|
56
|
+
} catch (err) {
|
|
57
|
+
const appwriteContext = c.get("appwriteContext");
|
|
58
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
59
|
+
|
|
60
|
+
appwriteContext?.error(`Error in ${c.req.method} ${c.req.path}: ${error.message}`);
|
|
61
|
+
|
|
62
|
+
return c.json(
|
|
63
|
+
{
|
|
64
|
+
error: "Internal Server Error",
|
|
65
|
+
message: error.message,
|
|
66
|
+
path: c.req.path,
|
|
67
|
+
method: c.req.method,
|
|
68
|
+
},
|
|
69
|
+
500
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Middleware to extract and validate Appwrite headers
|
|
77
|
+
*/
|
|
78
|
+
export const appwriteHeaders = (): MiddlewareHandler => {
|
|
79
|
+
return async (c, next) => {
|
|
80
|
+
const appwriteContext = c.get("appwriteContext");
|
|
81
|
+
const headers = appwriteContext?.req.headers;
|
|
82
|
+
|
|
83
|
+
// Add helpful getters for common Appwrite headers
|
|
84
|
+
c.appwrite = {
|
|
85
|
+
trigger: headers?.["x-appwrite-trigger"] as "http" | "schedule" | "event" | undefined,
|
|
86
|
+
event: headers?.["x-appwrite-event"],
|
|
87
|
+
key: headers?.["x-appwrite-key"],
|
|
88
|
+
userId: headers?.["x-appwrite-user-id"],
|
|
89
|
+
userJwt: headers?.["x-appwrite-user-jwt"],
|
|
90
|
+
countryCode: headers?.["x-appwrite-country-code"],
|
|
91
|
+
continentCode: headers?.["x-appwrite-continent-code"],
|
|
92
|
+
continentEu: headers?.["x-appwrite-continent-eu"],
|
|
93
|
+
isUserAuthenticated: () => !!headers?.["x-appwrite-user-id"],
|
|
94
|
+
isApiKeyRequest: () => !!headers?.["x-appwrite-key"],
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
await next();
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Extend Hono context to include Appwrite helpers
|
|
102
|
+
declare module "hono" {
|
|
103
|
+
interface Context {
|
|
104
|
+
log: (message: string) => void;
|
|
105
|
+
error: (message: string) => void;
|
|
106
|
+
appwrite: {
|
|
107
|
+
trigger?: "http" | "schedule" | "event";
|
|
108
|
+
event?: string;
|
|
109
|
+
key?: string;
|
|
110
|
+
userId?: string;
|
|
111
|
+
userJwt?: string;
|
|
112
|
+
countryCode?: string;
|
|
113
|
+
continentCode?: string;
|
|
114
|
+
continentEu?: string;
|
|
115
|
+
isUserAuthenticated: () => boolean;
|
|
116
|
+
isApiKeyRequest: () => boolean;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"allowSyntheticDefaultImports": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"outDir": "./dist",
|
|
14
|
+
"rootDir": "./src",
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"types": ["node"]
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# TypeScript Node.js Function Template
|
|
2
|
+
|
|
3
|
+
This is a TypeScript template for Appwrite Functions using Node.js runtime.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
- `src/index.ts`: Main function entry point
|
|
7
|
+
- `src/appwriteRequest.ts`: Type definitions for Appwrite request object
|
|
8
|
+
- `src/appwriteResponse.ts`: Type definitions for Appwrite response object
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
Your function will receive:
|
|
12
|
+
- `req`: AppwriteRequest object containing request data, headers, and environment variables
|
|
13
|
+
- `res`: AppwriteResponse object for sending responses
|
|
14
|
+
- `log`: Function for logging (shows in your function logs)
|
|
15
|
+
- `error`: Function for error logging
|
|
16
|
+
|
|
17
|
+
## Example Request
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"databaseId": "your-database-id",
|
|
21
|
+
"collectionId": "your-collection-id"
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Development
|
|
26
|
+
1. Install dependencies: `npm|yarn|bun install`
|
|
27
|
+
2. Build: `npm|yarn|bun run build`
|
|
28
|
+
3. Deploy: Function will be built automatically during deployment
|
|
29
|
+
|
|
30
|
+
## Deployment
|
|
31
|
+
Make sure it's inside `appwriteConfig.ts` functions array, and if you want to build it FIRST, before Appwrite (using your system), you can
|
|
32
|
+
add the `predeployCommands` to the function in `appwriteConfig.ts` -- for an example, see `count-docs-in-collection` function.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{functionName}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Appwrite TypeScript Node.js function",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node dist/index.js",
|
|
10
|
+
"dev": "tsx src/index.ts"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"node-appwrite": "^13.0.0",
|
|
14
|
+
"appwrite-utils": "latest",
|
|
15
|
+
"zod": "^3.22.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^20.0.0",
|
|
19
|
+
"typescript": "^5.0.0",
|
|
20
|
+
"tsx": "^4.0.0"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Appwrite Request Headers Schema
|
|
5
|
+
*/
|
|
6
|
+
export const AppwriteHeadersSchema = z.object({
|
|
7
|
+
"x-appwrite-trigger": z.enum(["http", "schedule", "event"]).optional(),
|
|
8
|
+
"x-appwrite-event": z.string().optional(),
|
|
9
|
+
"x-appwrite-key": z.string().optional(),
|
|
10
|
+
"x-appwrite-user-id": z.string().optional(),
|
|
11
|
+
"x-appwrite-user-jwt": z.string().optional(),
|
|
12
|
+
"x-appwrite-country-code": z.string().optional(),
|
|
13
|
+
"x-appwrite-continent-code": z.string().optional(),
|
|
14
|
+
"x-appwrite-continent-eu": z.string().optional(),
|
|
15
|
+
}).catchall(z.string()); // Allow additional headers
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Appwrite Environment Variables Schema
|
|
19
|
+
*/
|
|
20
|
+
export const AppwriteEnvSchema = z.object({
|
|
21
|
+
APPWRITE_FUNCTION_API_ENDPOINT: z.string(),
|
|
22
|
+
APPWRITE_VERSION: z.string(),
|
|
23
|
+
APPWRITE_REGION: z.string(),
|
|
24
|
+
APPWRITE_FUNCTION_API_KEY: z.string().optional(),
|
|
25
|
+
APPWRITE_FUNCTION_ID: z.string(),
|
|
26
|
+
APPWRITE_FUNCTION_NAME: z.string(),
|
|
27
|
+
APPWRITE_FUNCTION_DEPLOYMENT: z.string(),
|
|
28
|
+
APPWRITE_FUNCTION_PROJECT_ID: z.string(),
|
|
29
|
+
APPWRITE_FUNCTION_RUNTIME_NAME: z.string(),
|
|
30
|
+
APPWRITE_FUNCTION_RUNTIME_VERSION: z.string(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Appwrite Request Schema (full version from docs)
|
|
35
|
+
*/
|
|
36
|
+
export const AppwriteRequestSchema = z.object({
|
|
37
|
+
bodyText: z.string().optional(),
|
|
38
|
+
bodyJson: z.union([z.any(), z.string()]).transform((t) => {
|
|
39
|
+
if (typeof t === "string") {
|
|
40
|
+
try {
|
|
41
|
+
return JSON.parse(t);
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return t;
|
|
47
|
+
}).optional(),
|
|
48
|
+
body: z.any().optional(),
|
|
49
|
+
headers: AppwriteHeadersSchema,
|
|
50
|
+
scheme: z.enum(["http", "https"]).optional(),
|
|
51
|
+
method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"]),
|
|
52
|
+
url: z.string().optional(),
|
|
53
|
+
host: z.string().optional(),
|
|
54
|
+
port: z.number().or(z.string()).optional(),
|
|
55
|
+
path: z.string().optional(),
|
|
56
|
+
queryString: z.string().optional(),
|
|
57
|
+
query: z.record(z.string(), z.any()).optional(),
|
|
58
|
+
variables: z.record(z.string(), z.any()).optional(),
|
|
59
|
+
text: z.any().optional(),
|
|
60
|
+
payload: z.string().optional(),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Appwrite Response Schema
|
|
65
|
+
*/
|
|
66
|
+
export const AppwriteResponseSchema = z.object({
|
|
67
|
+
json: z.any(),
|
|
68
|
+
text: z.any(),
|
|
69
|
+
empty: z.any().optional(),
|
|
70
|
+
binary: z.any().optional(),
|
|
71
|
+
redirect: z.any().optional(),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Log Function Schema - Simple function type
|
|
76
|
+
*/
|
|
77
|
+
export const AppwriteLogSchema = z.any();
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Error Function Schema - Simple function type
|
|
81
|
+
*/
|
|
82
|
+
export const AppwriteErrorSchema = z.any();
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Complete Appwrite Context Schema
|
|
86
|
+
*/
|
|
87
|
+
export const AppwriteContextSchema = z.object({
|
|
88
|
+
req: AppwriteRequestSchema,
|
|
89
|
+
res: AppwriteResponseSchema,
|
|
90
|
+
log: AppwriteLogSchema,
|
|
91
|
+
error: AppwriteErrorSchema,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Type inference helpers
|
|
96
|
+
*/
|
|
97
|
+
export type AppwriteHeaders = z.infer<typeof AppwriteHeadersSchema>;
|
|
98
|
+
export type AppwriteEnv = z.infer<typeof AppwriteEnvSchema>;
|
|
99
|
+
export type AppwriteRequest = z.infer<typeof AppwriteRequestSchema>;
|
|
100
|
+
export type AppwriteResponse = z.infer<typeof AppwriteResponseSchema>;
|
|
101
|
+
export type AppwriteLog = z.infer<typeof AppwriteLogSchema>;
|
|
102
|
+
export type AppwriteError = z.infer<typeof AppwriteErrorSchema>;
|
|
103
|
+
export type AppwriteContext = z.infer<typeof AppwriteContextSchema>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Client } from "node-appwrite";
|
|
2
|
+
import { AppwriteContext, AppwriteContextSchema } from "./context.js";
|
|
3
|
+
|
|
4
|
+
export default async function (context: AppwriteContext) {
|
|
5
|
+
const { req, res, log, error } = context;
|
|
6
|
+
|
|
7
|
+
// Optional: Validate the context using Zod schema
|
|
8
|
+
try {
|
|
9
|
+
AppwriteContextSchema.parse(context);
|
|
10
|
+
log("Context validation successful");
|
|
11
|
+
} catch (validationError) {
|
|
12
|
+
error(`Context validation failed: ${validationError}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const client = new Client()
|
|
16
|
+
.setEndpoint(process.env["APPWRITE_FUNCTION_ENDPOINT"]!)
|
|
17
|
+
.setProject(process.env["APPWRITE_FUNCTION_PROJECT_ID"]!)
|
|
18
|
+
.setKey(req.headers["x-appwrite-key"] || "");
|
|
19
|
+
|
|
20
|
+
log(`Processing ${req.method} request to ${req.path}`);
|
|
21
|
+
|
|
22
|
+
return res.json({
|
|
23
|
+
message: "Hello from TypeScript function!",
|
|
24
|
+
functionName: "{{functionName}}",
|
|
25
|
+
method: req.method,
|
|
26
|
+
path: req.path,
|
|
27
|
+
headers: req.headers,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"allowSyntheticDefaultImports": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"checkJs": false,
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"rootDir": "./src",
|
|
12
|
+
"strict": true,
|
|
13
|
+
"noImplicitAny": true,
|
|
14
|
+
"strictNullChecks": true,
|
|
15
|
+
"strictFunctionTypes": true,
|
|
16
|
+
"noImplicitThis": true,
|
|
17
|
+
"noImplicitReturns": true,
|
|
18
|
+
"noFallthroughCasesInSwitch": true,
|
|
19
|
+
"moduleDetection": "force",
|
|
20
|
+
"resolveJsonModule": true,
|
|
21
|
+
"isolatedModules": true,
|
|
22
|
+
"verbatimModuleSyntax": false,
|
|
23
|
+
"skipLibCheck": true,
|
|
24
|
+
"forceConsistentCasingInFileNames": true
|
|
25
|
+
},
|
|
26
|
+
"include": ["src/**/*"],
|
|
27
|
+
"exclude": ["node_modules", "dist"]
|
|
28
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Python UV Function Template
|
|
2
|
+
|
|
3
|
+
This is a Python template for Appwrite Functions using UV for fast dependency management.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
- `src/index.py`: Main function entry point
|
|
7
|
+
- `pyproject.toml`: UV/PyPI project configuration and dependencies
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
Your function will receive a context object with:
|
|
11
|
+
- `req`: Request object containing request data, headers, and environment variables
|
|
12
|
+
- `res`: Response object for sending responses
|
|
13
|
+
- `log`: Function for logging (shows in your function logs)
|
|
14
|
+
- `error`: Function for error logging
|
|
15
|
+
|
|
16
|
+
## Example Request
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"key": "value"
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Development
|
|
24
|
+
1. Install UV: `curl -LsSf https://astral.sh/uv/install.sh | sh`
|
|
25
|
+
2. Install dependencies: `uv sync`
|
|
26
|
+
3. Run locally: `uv run python src/index.py`
|
|
27
|
+
4. Deploy: Dependencies will be installed during deployment
|
|
28
|
+
|
|
29
|
+
## Deployment
|
|
30
|
+
Make sure it's inside `appwriteConfig.yaml` functions array, and if you want to install dependencies FIRST, before Appwrite (using your system), you can
|
|
31
|
+
add the `predeployCommands` to the function in `appwriteConfig.yaml`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "{{functionName}}"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Appwrite Python function using UV"
|
|
5
|
+
authors = [{name = "Your Name", email = "you@example.com"}]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.9"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"appwrite>=7.0.1",
|
|
10
|
+
"pydantic>=2.0.0",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
[build-system]
|
|
14
|
+
requires = ["hatchling"]
|
|
15
|
+
build-backend = "hatchling.build"
|
|
16
|
+
|
|
17
|
+
[tool.uv]
|
|
18
|
+
dev-dependencies = [
|
|
19
|
+
"pytest>=7.0.0",
|
|
20
|
+
"black>=23.0.0",
|
|
21
|
+
"ruff>=0.1.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[tool.ruff]
|
|
25
|
+
line-length = 88
|
|
26
|
+
target-version = "py39"
|
|
27
|
+
|
|
28
|
+
[tool.ruff.lint]
|
|
29
|
+
select = ["E", "F", "W", "I"]
|
|
30
|
+
ignore = ["E501"]
|
|
File without changes
|