@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/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
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "sqlite",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "6",
8
+ "when": 1733941526291,
9
+ "tag": "0000_flowery_meggan",
10
+ "breakpoints": true
11
+ }
12
+ ]
13
+ }
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,3 @@
1
+ export * from './db/schema';
2
+ export * from './middleware';
3
+ export * from './types';
@@ -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
+ });
package/wrangler.toml ADDED
@@ -0,0 +1,8 @@
1
+ # wrangler.toml in shared folder
2
+ name = "shared-migrations"
3
+ compatibility_date = "2024-12-10"
4
+
5
+ [[ d1_databases ]]
6
+ binding = "DB"
7
+ database_name = "zodic-db"
8
+ database_id = "b4b0a981-f921-4258-ad7a-b2d7b50eb381"