@zodic/shared 0.0.1
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/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/d379cf52b047a184ecf29a10a32b971cde5e2c256717041a7cd396844038970d.sqlite +0 -0
- package/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/d379cf52b047a184ecf29a10a32b971cde5e2c256717041a7cd396844038970d.sqlite-shm +0 -0
- package/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/d379cf52b047a184ecf29a10a32b971cde5e2c256717041a7cd396844038970d.sqlite-wal +0 -0
- package/README.md +15 -0
- package/bun.lockb +0 -0
- package/db/migrations/0000_flowery_meggan.sql +20 -0
- package/db/migrations/meta/0000_snapshot.json +140 -0
- package/db/migrations/meta/_journal.json +13 -0
- package/db/schema.ts +102 -0
- package/drizzle.config.ts +8 -0
- package/index.ts +3 -0
- package/middleware/index.ts +32 -0
- package/package.json +26 -0
- package/tsconfig.json +22 -0
- package/types/db.ts +19 -0
- package/types/index.ts +197 -0
- package/utils/index.ts +48 -0
- package/wrangler.toml +8 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @zodic/shared
|
|
2
|
+
|
|
3
|
+
To install dependencies:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
bun install
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
To run:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun run index.ts
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This project was created using `bun init` in bun v1.0.4. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
package/bun.lockb
ADDED
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
CREATE TABLE `tokens` (
|
|
2
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
3
|
+
`user_id` text NOT NULL,
|
|
4
|
+
`refresh_token` text NOT NULL,
|
|
5
|
+
`created_at` text DEFAULT 'CURRENT_TIMESTAMP'
|
|
6
|
+
);
|
|
7
|
+
--> statement-breakpoint
|
|
8
|
+
CREATE TABLE `users_table` (
|
|
9
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
10
|
+
`name` text NOT NULL,
|
|
11
|
+
`age` integer NOT NULL,
|
|
12
|
+
`email` text NOT NULL,
|
|
13
|
+
`birthday` text,
|
|
14
|
+
`birth_time` text,
|
|
15
|
+
`crown` text,
|
|
16
|
+
`createdAt` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
17
|
+
`updatedAt` text DEFAULT CURRENT_TIMESTAMP
|
|
18
|
+
);
|
|
19
|
+
--> statement-breakpoint
|
|
20
|
+
CREATE UNIQUE INDEX `users_table_email_unique` ON `users_table` (`email`);
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "6",
|
|
3
|
+
"dialect": "sqlite",
|
|
4
|
+
"id": "ebd56564-96c0-4785-a419-40258282dbc0",
|
|
5
|
+
"prevId": "00000000-0000-0000-0000-000000000000",
|
|
6
|
+
"tables": {
|
|
7
|
+
"tokens": {
|
|
8
|
+
"name": "tokens",
|
|
9
|
+
"columns": {
|
|
10
|
+
"id": {
|
|
11
|
+
"name": "id",
|
|
12
|
+
"type": "text",
|
|
13
|
+
"primaryKey": true,
|
|
14
|
+
"notNull": true,
|
|
15
|
+
"autoincrement": false
|
|
16
|
+
},
|
|
17
|
+
"user_id": {
|
|
18
|
+
"name": "user_id",
|
|
19
|
+
"type": "text",
|
|
20
|
+
"primaryKey": false,
|
|
21
|
+
"notNull": true,
|
|
22
|
+
"autoincrement": false
|
|
23
|
+
},
|
|
24
|
+
"refresh_token": {
|
|
25
|
+
"name": "refresh_token",
|
|
26
|
+
"type": "text",
|
|
27
|
+
"primaryKey": false,
|
|
28
|
+
"notNull": true,
|
|
29
|
+
"autoincrement": false
|
|
30
|
+
},
|
|
31
|
+
"created_at": {
|
|
32
|
+
"name": "created_at",
|
|
33
|
+
"type": "text",
|
|
34
|
+
"primaryKey": false,
|
|
35
|
+
"notNull": false,
|
|
36
|
+
"autoincrement": false,
|
|
37
|
+
"default": "'CURRENT_TIMESTAMP'"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"indexes": {},
|
|
41
|
+
"foreignKeys": {},
|
|
42
|
+
"compositePrimaryKeys": {},
|
|
43
|
+
"uniqueConstraints": {},
|
|
44
|
+
"checkConstraints": {}
|
|
45
|
+
},
|
|
46
|
+
"users_table": {
|
|
47
|
+
"name": "users_table",
|
|
48
|
+
"columns": {
|
|
49
|
+
"id": {
|
|
50
|
+
"name": "id",
|
|
51
|
+
"type": "text",
|
|
52
|
+
"primaryKey": true,
|
|
53
|
+
"notNull": true,
|
|
54
|
+
"autoincrement": false
|
|
55
|
+
},
|
|
56
|
+
"name": {
|
|
57
|
+
"name": "name",
|
|
58
|
+
"type": "text",
|
|
59
|
+
"primaryKey": false,
|
|
60
|
+
"notNull": true,
|
|
61
|
+
"autoincrement": false
|
|
62
|
+
},
|
|
63
|
+
"age": {
|
|
64
|
+
"name": "age",
|
|
65
|
+
"type": "integer",
|
|
66
|
+
"primaryKey": false,
|
|
67
|
+
"notNull": true,
|
|
68
|
+
"autoincrement": false
|
|
69
|
+
},
|
|
70
|
+
"email": {
|
|
71
|
+
"name": "email",
|
|
72
|
+
"type": "text",
|
|
73
|
+
"primaryKey": false,
|
|
74
|
+
"notNull": true,
|
|
75
|
+
"autoincrement": false
|
|
76
|
+
},
|
|
77
|
+
"birthday": {
|
|
78
|
+
"name": "birthday",
|
|
79
|
+
"type": "text",
|
|
80
|
+
"primaryKey": false,
|
|
81
|
+
"notNull": false,
|
|
82
|
+
"autoincrement": false
|
|
83
|
+
},
|
|
84
|
+
"birth_time": {
|
|
85
|
+
"name": "birth_time",
|
|
86
|
+
"type": "text",
|
|
87
|
+
"primaryKey": false,
|
|
88
|
+
"notNull": false,
|
|
89
|
+
"autoincrement": false
|
|
90
|
+
},
|
|
91
|
+
"crown": {
|
|
92
|
+
"name": "crown",
|
|
93
|
+
"type": "text",
|
|
94
|
+
"primaryKey": false,
|
|
95
|
+
"notNull": false,
|
|
96
|
+
"autoincrement": false
|
|
97
|
+
},
|
|
98
|
+
"createdAt": {
|
|
99
|
+
"name": "createdAt",
|
|
100
|
+
"type": "text",
|
|
101
|
+
"primaryKey": false,
|
|
102
|
+
"notNull": true,
|
|
103
|
+
"autoincrement": false,
|
|
104
|
+
"default": "CURRENT_TIMESTAMP"
|
|
105
|
+
},
|
|
106
|
+
"updatedAt": {
|
|
107
|
+
"name": "updatedAt",
|
|
108
|
+
"type": "text",
|
|
109
|
+
"primaryKey": false,
|
|
110
|
+
"notNull": false,
|
|
111
|
+
"autoincrement": false,
|
|
112
|
+
"default": "CURRENT_TIMESTAMP"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"indexes": {
|
|
116
|
+
"users_table_email_unique": {
|
|
117
|
+
"name": "users_table_email_unique",
|
|
118
|
+
"columns": [
|
|
119
|
+
"email"
|
|
120
|
+
],
|
|
121
|
+
"isUnique": true
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"foreignKeys": {},
|
|
125
|
+
"compositePrimaryKeys": {},
|
|
126
|
+
"uniqueConstraints": {},
|
|
127
|
+
"checkConstraints": {}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"views": {},
|
|
131
|
+
"enums": {},
|
|
132
|
+
"_meta": {
|
|
133
|
+
"schemas": {},
|
|
134
|
+
"tables": {},
|
|
135
|
+
"columns": {}
|
|
136
|
+
},
|
|
137
|
+
"internal": {
|
|
138
|
+
"indexes": {}
|
|
139
|
+
}
|
|
140
|
+
}
|
package/db/schema.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
import {
|
|
3
|
+
index,
|
|
4
|
+
integer,
|
|
5
|
+
real,
|
|
6
|
+
sqliteTable,
|
|
7
|
+
text,
|
|
8
|
+
} from 'drizzle-orm/sqlite-core';
|
|
9
|
+
|
|
10
|
+
export const users = sqliteTable(
|
|
11
|
+
'users',
|
|
12
|
+
{
|
|
13
|
+
id: text('id').primaryKey(),
|
|
14
|
+
email: text('email').notNull().unique(),
|
|
15
|
+
name: text('name').notNull(),
|
|
16
|
+
profileImage: text('profile_image'),
|
|
17
|
+
userPhotoId: text('user_photo_id'),
|
|
18
|
+
userPhotoUrl: text('user_photo_url'),
|
|
19
|
+
gender: text('gender'),
|
|
20
|
+
birthDateTime: text('birth_date_time').notNull(),
|
|
21
|
+
latitude: real('latitude').notNull(),
|
|
22
|
+
longitude: real('longitude').notNull(),
|
|
23
|
+
createdAt: text('created_at')
|
|
24
|
+
.default(sql`CURRENT_TIMESTAMP`)
|
|
25
|
+
.notNull(),
|
|
26
|
+
},
|
|
27
|
+
(t) => [index('users_email_idx').on(t.email)]
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export const astrologicalData = sqliteTable(
|
|
31
|
+
'astrological_data',
|
|
32
|
+
{
|
|
33
|
+
id: text('id').primaryKey(),
|
|
34
|
+
userId: text('user_id')
|
|
35
|
+
.notNull()
|
|
36
|
+
.references(() => users.id, { onDelete: 'cascade' }),
|
|
37
|
+
planet: text('planet').notNull(), // Planet name (e.g., "Sun", "Moon")
|
|
38
|
+
sign: text('sign').notNull(), // Zodiac sign (e.g., "Sagittarius")
|
|
39
|
+
house: integer('house').notNull(), // House number (1-12)
|
|
40
|
+
fullDegree: real('full_degree').notNull(), // Full degree in 360° system
|
|
41
|
+
normDegree: real('norm_degree').notNull(), // Degree within the sign (0-29°)
|
|
42
|
+
speed: real('speed').notNull(), // Speed of the planet
|
|
43
|
+
isRetro: integer('is_retro').notNull(), // 0 (false) or 1 (true) for retrograde
|
|
44
|
+
},
|
|
45
|
+
(t) => [index('astrological_data_user_id_idx').on(t.userId)]
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
export const products = sqliteTable(
|
|
49
|
+
'products',
|
|
50
|
+
{
|
|
51
|
+
id: text('id').primaryKey(),
|
|
52
|
+
name: text('name').unique().notNull(),
|
|
53
|
+
description: text('description'),
|
|
54
|
+
createdAt: text('created_at')
|
|
55
|
+
.default(sql`CURRENT_TIMESTAMP`)
|
|
56
|
+
.notNull(),
|
|
57
|
+
},
|
|
58
|
+
(t) => [index('products_name_idx').on(t.name)]
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export const generations = sqliteTable(
|
|
62
|
+
'generations',
|
|
63
|
+
{
|
|
64
|
+
id: text('id').primaryKey(),
|
|
65
|
+
userId: text('user_id')
|
|
66
|
+
.notNull()
|
|
67
|
+
.references(() => users.id, { onDelete: 'cascade' }),
|
|
68
|
+
productId: text('product_id')
|
|
69
|
+
.notNull()
|
|
70
|
+
.references(() => products.id, { onDelete: 'set null' }),
|
|
71
|
+
type: text('type').notNull(), // Generation type (e.g., "luminous_self", "archetype")
|
|
72
|
+
imageId: text('image_id'),
|
|
73
|
+
imageUrl: text('image_url'),
|
|
74
|
+
reportContent: text('report_content'),
|
|
75
|
+
externalSourceUrl: text('external_source_url'),
|
|
76
|
+
createdAt: text('created_at').default('CURRENT_TIMESTAMP'),
|
|
77
|
+
metadata: text('metadata'),
|
|
78
|
+
},
|
|
79
|
+
(t) => [
|
|
80
|
+
index('generations_user_id_idx').on(t.userId),
|
|
81
|
+
index('generations_product_id_idx').on(t.productId),
|
|
82
|
+
index('generations_user_id_product_id_idx').on(t.userId, t.productId),
|
|
83
|
+
]
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
export const tokens = sqliteTable(
|
|
87
|
+
'tokens',
|
|
88
|
+
{
|
|
89
|
+
id: text('id').primaryKey(),
|
|
90
|
+
userId: text('user_id')
|
|
91
|
+
.notNull()
|
|
92
|
+
.references(() => users.id, { onDelete: 'cascade' }),
|
|
93
|
+
refreshToken: text('refresh_token').unique().notNull(),
|
|
94
|
+
expiresAt: text('expires_at').notNull(), // Expiration timestamp for the token
|
|
95
|
+
createdAt: text('created_at')
|
|
96
|
+
.default(sql`CURRENT_TIMESTAMP`)
|
|
97
|
+
.notNull(),
|
|
98
|
+
},
|
|
99
|
+
(t) => [
|
|
100
|
+
index('tokens_user_id_idx').on(t.userId), // Index on user_id
|
|
101
|
+
]
|
|
102
|
+
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { defineConfig } from 'drizzle-kit';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
schema: './db/schema.ts', // Path to your Drizzle-ORM schema
|
|
5
|
+
out: './db/migrations', // Path to store generated migrations
|
|
6
|
+
dialect: 'sqlite',
|
|
7
|
+
driver: 'd1-http', // Use "sqlite" for D1 Database
|
|
8
|
+
});
|
package/index.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getCookie } from "hono/cookie";
|
|
2
|
+
import { Ctx } from "../types";
|
|
3
|
+
import { verifyToken } from "../utils";
|
|
4
|
+
|
|
5
|
+
export const jwtMiddleware = async (c: Ctx, next: () => Promise<void>) => {
|
|
6
|
+
let token: string | undefined = undefined;
|
|
7
|
+
|
|
8
|
+
// Check for the Authorization header
|
|
9
|
+
const authHeader = c.req.header('Authorization');
|
|
10
|
+
if (authHeader && authHeader.startsWith('Bearer ')) {
|
|
11
|
+
token = authHeader.substring(7); // Remove 'Bearer ' prefix
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!token) {
|
|
15
|
+
token = getCookie(c, 'accessToken');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!token) {
|
|
19
|
+
return c.json({ error: 'Unauthorized: No token provided' }, 401);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const payload = await verifyToken(c, token);
|
|
24
|
+
|
|
25
|
+
c.set('jwtPayload', payload);
|
|
26
|
+
|
|
27
|
+
await next(); // Proceed to the next middleware or route handler
|
|
28
|
+
} catch (err: any) {
|
|
29
|
+
console.error(err.message);
|
|
30
|
+
return c.json({ error: 'Unauthorized: Invalid or expired token' }, 401);
|
|
31
|
+
}
|
|
32
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zodic/shared",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"module": "index.ts",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"migrate-latest-test": "wrangler d1 execute DB --file=$(ls -t ./db/migrations/*.sql | head -n 1)",
|
|
11
|
+
"migrate-latest": "wrangler d1 execute DB --file=$(ls -t ./db/migrations/*.sql | head -n 1) --remote"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@cloudflare/workers-types": "^4.20241205.0",
|
|
15
|
+
"bun-types": "latest"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"typescript": "^5.0.0"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"drizzle-kit": "^0.30.0",
|
|
22
|
+
"drizzle-orm": "^0.38.0",
|
|
23
|
+
"hono": "^4.6.13",
|
|
24
|
+
"jose": "^5.9.6"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["ESNext"],
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"target": "esnext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"allowImportingTsExtensions": true,
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"composite": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"downlevelIteration": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"allowSyntheticDefaultImports": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
"allowJs": true,
|
|
18
|
+
"types": [
|
|
19
|
+
"bun-types" // add Bun global
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|
package/types/db.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { InferInsertModel, InferSelectModel, Table } from 'drizzle-orm';
|
|
2
|
+
import { users, astrologicalData, generations, products, tokens } from '../db/schema';
|
|
3
|
+
|
|
4
|
+
type NullableSelect<T extends Table> = InferSelectModel<T> | undefined | null;
|
|
5
|
+
|
|
6
|
+
export type SelectUser = NullableSelect<typeof users>;
|
|
7
|
+
export type InsertUser = InferInsertModel<typeof users>;
|
|
8
|
+
|
|
9
|
+
export type SelectAstrologicalData = InferSelectModel<typeof astrologicalData>;
|
|
10
|
+
export type InsertAstrologicalData = InferInsertModel<typeof astrologicalData>;
|
|
11
|
+
|
|
12
|
+
export type SelectGeneration = NullableSelect<typeof generations>;
|
|
13
|
+
export type InsertGeneration = InferInsertModel<typeof generations>;
|
|
14
|
+
|
|
15
|
+
export type SelectProduct = NullableSelect<typeof products>;
|
|
16
|
+
export type InsertProduct = InferInsertModel<typeof products>;
|
|
17
|
+
|
|
18
|
+
export type SelectToken = NullableSelect<typeof tokens>;
|
|
19
|
+
export type InsertToken = InferInsertModel<typeof tokens>;
|
package/types/index.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Ai,
|
|
3
|
+
D1Database,
|
|
4
|
+
KVNamespace,
|
|
5
|
+
R2Bucket,
|
|
6
|
+
} from '@cloudflare/workers-types';
|
|
7
|
+
import { Context, Env } from 'hono';
|
|
8
|
+
export * from './db';
|
|
9
|
+
|
|
10
|
+
export type CentralBindings = {
|
|
11
|
+
TEST_IMAGES_BUCKET: R2Bucket;
|
|
12
|
+
PHOTOS_BUCKET: R2Bucket;
|
|
13
|
+
OPENAI_API_KEY: string;
|
|
14
|
+
LEONARDO_API_KEY: string;
|
|
15
|
+
DESCRIBER_API_KEY: string;
|
|
16
|
+
DESCRIBER_APP_ID: string;
|
|
17
|
+
AKOOL_API_KEY: string;
|
|
18
|
+
KV_GENERATION_MANAGEMENT: KVNamespace;
|
|
19
|
+
KV_USER_GENERATIONS: KVNamespace;
|
|
20
|
+
KV_ARCHETYPES: KVNamespace;
|
|
21
|
+
KV_LEONARDO_PROMPTS: KVNamespace;
|
|
22
|
+
KV_TEST: KVNamespace;
|
|
23
|
+
PROMPT_IMAGE_DESCRIBER: string;
|
|
24
|
+
PROMPT_GENERATE_ARCHETYPE: string;
|
|
25
|
+
PROMPT_GENERATE_LEONARDO: string;
|
|
26
|
+
NEGATIVE_PROMPT_LEONARDO: string;
|
|
27
|
+
PROMPT_GENERATE_USER_LUMINOUS_SELF: string;
|
|
28
|
+
AI: Ai;
|
|
29
|
+
DB: D1Database;
|
|
30
|
+
JWT_SECRET: string;
|
|
31
|
+
CLOUDFLARE_DATABASE_ID: string;
|
|
32
|
+
CLOUDFLARE_D1_TOKEN: string;
|
|
33
|
+
CLOUDFLARE_ACCOUNT_ID: string;
|
|
34
|
+
ISSUER: string;
|
|
35
|
+
GOOGLE_API_KEY: string;
|
|
36
|
+
GOOGLE_SERVER_URL: string;
|
|
37
|
+
GOOGLE_CLIENT_ID: string;
|
|
38
|
+
GOOGLE_CLIENT_SECRET: string;
|
|
39
|
+
FACEBOOK_SERVER_URL: string;
|
|
40
|
+
FACEBOOK_CLIENT_ID: string;
|
|
41
|
+
FACEBOOK_CLIENT_SECRET: string;
|
|
42
|
+
OAUTH_REDIRECT_URI: string;
|
|
43
|
+
ASTROLOGY_API_USER: string;
|
|
44
|
+
ASTROLOGY_API_KEY: string;
|
|
45
|
+
|
|
46
|
+
API_BASE_URL: string;
|
|
47
|
+
PUBLIC_GOOGLE_CLIENT_ID: string;
|
|
48
|
+
PUBLIC_FACEBOOK_CLIENT_ID: string;
|
|
49
|
+
PUBLIC_APP_NAME: string;
|
|
50
|
+
PUBLIC_APP_VERSION: string;
|
|
51
|
+
PUBLIC_ANALYTICS_ID?: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type Variables = {
|
|
55
|
+
jwtPayload: {
|
|
56
|
+
userId: string;
|
|
57
|
+
email?: string;
|
|
58
|
+
roles?: string[];
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type BackendBindings = Env &
|
|
63
|
+
Pick<
|
|
64
|
+
CentralBindings,
|
|
65
|
+
| 'TEST_IMAGES_BUCKET'
|
|
66
|
+
| 'PHOTOS_BUCKET'
|
|
67
|
+
| 'OPENAI_API_KEY'
|
|
68
|
+
| 'LEONARDO_API_KEY'
|
|
69
|
+
| 'DESCRIBER_API_KEY'
|
|
70
|
+
| 'DESCRIBER_APP_ID'
|
|
71
|
+
| 'AKOOL_API_KEY'
|
|
72
|
+
| 'KV_GENERATION_MANAGEMENT'
|
|
73
|
+
| 'KV_USER_GENERATIONS'
|
|
74
|
+
| 'KV_ARCHETYPES'
|
|
75
|
+
| 'KV_LEONARDO_PROMPTS'
|
|
76
|
+
| 'PROMPT_IMAGE_DESCRIBER'
|
|
77
|
+
| 'PROMPT_GENERATE_ARCHETYPE'
|
|
78
|
+
| 'PROMPT_GENERATE_LEONARDO'
|
|
79
|
+
| 'NEGATIVE_PROMPT_LEONARDO'
|
|
80
|
+
| 'PROMPT_GENERATE_USER_LUMINOUS_SELF'
|
|
81
|
+
| 'DB'
|
|
82
|
+
| 'JWT_SECRET'
|
|
83
|
+
| 'GOOGLE_API_KEY'
|
|
84
|
+
| 'GOOGLE_SERVER_URL'
|
|
85
|
+
| 'GOOGLE_CLIENT_ID'
|
|
86
|
+
| 'GOOGLE_CLIENT_SECRET'
|
|
87
|
+
| 'FACEBOOK_SERVER_URL'
|
|
88
|
+
| 'FACEBOOK_CLIENT_ID'
|
|
89
|
+
| 'FACEBOOK_CLIENT_SECRET'
|
|
90
|
+
| 'OAUTH_REDIRECT_URI'
|
|
91
|
+
| 'ASTROLOGY_API_USER'
|
|
92
|
+
| 'ASTROLOGY_API_KEY'
|
|
93
|
+
| 'AI'
|
|
94
|
+
>;
|
|
95
|
+
|
|
96
|
+
export type BackendCtx = Context<
|
|
97
|
+
{
|
|
98
|
+
Bindings: BackendBindings;
|
|
99
|
+
Variables: Variables;
|
|
100
|
+
},
|
|
101
|
+
any,
|
|
102
|
+
{}
|
|
103
|
+
>;
|
|
104
|
+
|
|
105
|
+
export type FrontendBindings = Pick<
|
|
106
|
+
CentralBindings,
|
|
107
|
+
| 'API_BASE_URL'
|
|
108
|
+
| 'PUBLIC_GOOGLE_CLIENT_ID'
|
|
109
|
+
| 'PUBLIC_FACEBOOK_CLIENT_ID'
|
|
110
|
+
| 'PUBLIC_APP_NAME'
|
|
111
|
+
| 'PUBLIC_APP_VERSION'
|
|
112
|
+
| 'PUBLIC_ANALYTICS_ID'
|
|
113
|
+
>;
|
|
114
|
+
|
|
115
|
+
export type FrontCtx = {
|
|
116
|
+
bindings: FrontendBindings;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export type AuthBindings = Env &
|
|
120
|
+
Pick<
|
|
121
|
+
CentralBindings,
|
|
122
|
+
| 'JWT_SECRET'
|
|
123
|
+
| 'GOOGLE_CLIENT_ID'
|
|
124
|
+
| 'GOOGLE_CLIENT_SECRET'
|
|
125
|
+
| 'GOOGLE_SERVER_URL'
|
|
126
|
+
| 'FACEBOOK_CLIENT_ID'
|
|
127
|
+
| 'FACEBOOK_CLIENT_SECRET'
|
|
128
|
+
| 'FACEBOOK_SERVER_URL'
|
|
129
|
+
| 'OAUTH_REDIRECT_URI'
|
|
130
|
+
| 'ISSUER'
|
|
131
|
+
>;
|
|
132
|
+
|
|
133
|
+
export type AuthCtx = {
|
|
134
|
+
bindings: AuthBindings;
|
|
135
|
+
variables: Variables;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export type Bindings = Env & {
|
|
139
|
+
TEST_IMAGES_BUCKET: R2Bucket;
|
|
140
|
+
PHOTOS_BUCKET: R2Bucket;
|
|
141
|
+
OPENAI_API_KEY: string;
|
|
142
|
+
LEONARDO_API_KEY: string;
|
|
143
|
+
DESCRIBER_API_KEY: string;
|
|
144
|
+
DESCRIBER_APP_ID: string;
|
|
145
|
+
AKOOL_API_KEY: string;
|
|
146
|
+
KV_GENERATION_MANAGEMENT: KVNamespace;
|
|
147
|
+
KV_USER_GENERATIONS: KVNamespace;
|
|
148
|
+
KV_ARCHETYPES: KVNamespace;
|
|
149
|
+
KV_LEONARDO_PROMPTS: KVNamespace;
|
|
150
|
+
KV_TEST: KVNamespace;
|
|
151
|
+
PROMPT_IMAGE_DESCRIBER: string;
|
|
152
|
+
PROMPT_GENERATE_ARCHETYPE: string;
|
|
153
|
+
PROMPT_GENERATE_LEONARDO: string;
|
|
154
|
+
NEGATIVE_PROMPT_LEONARDO: string;
|
|
155
|
+
PROMPT_GENERATE_USER_LUMINOUS_SELF: string;
|
|
156
|
+
AI: Ai;
|
|
157
|
+
DB: D1Database;
|
|
158
|
+
JWT_SECRET: string;
|
|
159
|
+
CLOUDFLARE_DATABASE_ID: string;
|
|
160
|
+
CLOUDFLARE_D1_TOKEN: string;
|
|
161
|
+
CLOUDFLARE_ACCOUNT_ID: string;
|
|
162
|
+
ISSUER: string;
|
|
163
|
+
GOOGLE_API_KEY: string;
|
|
164
|
+
GOOGLE_SERVER_URL: string;
|
|
165
|
+
GOOGLE_CLIENT_ID: string;
|
|
166
|
+
GOOGLE_CLIENT_SECRET: string;
|
|
167
|
+
FACEBOOK_SERVER_URL: string;
|
|
168
|
+
FACEBOOK_CLIENT_ID: string;
|
|
169
|
+
FACEBOOK_CLIENT_SECRET: string;
|
|
170
|
+
OAUTH_REDIRECT_URI: string;
|
|
171
|
+
ASTROLOGY_API_USER: string;
|
|
172
|
+
ASTROLOGY_API_KEY: string;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export type Ctx = Context<
|
|
176
|
+
{
|
|
177
|
+
Bindings: Bindings;
|
|
178
|
+
Variables: Variables;
|
|
179
|
+
},
|
|
180
|
+
any,
|
|
181
|
+
{}
|
|
182
|
+
>;
|
|
183
|
+
|
|
184
|
+
export type Provider = 'google' | 'facebook';
|
|
185
|
+
|
|
186
|
+
export type ProviderInfo = {
|
|
187
|
+
serverUrl: string;
|
|
188
|
+
clientId: string;
|
|
189
|
+
clientSecret: string;
|
|
190
|
+
resourceUrl: string;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export const VALID_GENDERS_ARRAY = ['male', 'female', 'non-binary'] as const;
|
|
194
|
+
|
|
195
|
+
export type Gender = (typeof VALID_GENDERS_ARRAY)[number];
|
|
196
|
+
|
|
197
|
+
export const VALID_GENDERS = new Set<Gender>(VALID_GENDERS_ARRAY);
|
package/utils/index.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jwtVerify } from 'jose';
|
|
2
|
+
import { Ctx, Provider, ProviderInfo } from '../types';
|
|
3
|
+
|
|
4
|
+
export const verifyToken = async (
|
|
5
|
+
c: Ctx,
|
|
6
|
+
token: string
|
|
7
|
+
): Promise<{ userId: string; email?: string; roles?: string[] }> => {
|
|
8
|
+
const jwtSecret = c.env.JWT_SECRET;
|
|
9
|
+
const audience = c.env.CLOUDFLARE_ACCOUNT_ID;
|
|
10
|
+
const issuer = c.env.ISSUER;
|
|
11
|
+
|
|
12
|
+
if (!jwtSecret)
|
|
13
|
+
throw new Error('Jwt Secret is not defined in the environment');
|
|
14
|
+
if (!audience) throw new Error('Audience is not defined in the environment');
|
|
15
|
+
if (!issuer) throw new Error('Issuer is not defined in the environment');
|
|
16
|
+
|
|
17
|
+
const secret = new TextEncoder().encode(jwtSecret);
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const { payload } = await jwtVerify(token, secret, {
|
|
21
|
+
audience,
|
|
22
|
+
issuer,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (payload.exp && payload.exp * 1000 < Date.now()) {
|
|
26
|
+
throw new Error('Token has expired');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return payload as { userId: string; email?: string; roles?: string[] };
|
|
30
|
+
} catch (err) {
|
|
31
|
+
throw new Error('Invalid or expired token');
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const providers: (c: Ctx) => Record<Provider, ProviderInfo> = (c) => ({
|
|
36
|
+
google: {
|
|
37
|
+
serverUrl: c.env.GOOGLE_SERVER_URL,
|
|
38
|
+
clientId: c.env.GOOGLE_CLIENT_ID,
|
|
39
|
+
clientSecret: c.env.GOOGLE_CLIENT_SECRET,
|
|
40
|
+
resourceUrl: '',
|
|
41
|
+
},
|
|
42
|
+
facebook: {
|
|
43
|
+
serverUrl: c.env.FACEBOOK_SERVER_URL,
|
|
44
|
+
clientId: c.env.FACEBOOK_CLIENT_ID,
|
|
45
|
+
clientSecret: c.env.FACEBOOK_CLIENT_SECRET,
|
|
46
|
+
resourceUrl: '',
|
|
47
|
+
},
|
|
48
|
+
});
|