hazo_auth 10.0.0 → 10.1.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.
Files changed (43) hide show
  1. package/README.md +100 -0
  2. package/SETUP_CHECKLIST.md +18 -0
  3. package/cli-src/lib/auth/nextauth_config.ts +41 -0
  4. package/cli-src/lib/auth/request_google_scopes.ts +23 -0
  5. package/cli-src/lib/schema/sqlite_schema.ts +16 -0
  6. package/cli-src/lib/services/google_token_service.ts +408 -0
  7. package/cli-src/lib/services/index.ts +1 -1
  8. package/dist/client.d.ts +1 -0
  9. package/dist/client.d.ts.map +1 -1
  10. package/dist/client.js +2 -0
  11. package/dist/components/layouts/google_token_test/index.d.ts +6 -0
  12. package/dist/components/layouts/google_token_test/index.d.ts.map +1 -0
  13. package/dist/components/layouts/google_token_test/index.js +74 -0
  14. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
  15. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
  16. package/dist/components/ui/button.d.ts +1 -1
  17. package/dist/components/ui/input-otp.d.ts +2 -2
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +2 -0
  21. package/dist/lib/auth/nextauth_config.d.ts +2 -0
  22. package/dist/lib/auth/nextauth_config.d.ts.map +1 -1
  23. package/dist/lib/auth/nextauth_config.js +39 -1
  24. package/dist/lib/auth/request_google_scopes.d.ts +10 -0
  25. package/dist/lib/auth/request_google_scopes.d.ts.map +1 -0
  26. package/dist/lib/auth/request_google_scopes.js +13 -0
  27. package/dist/lib/schema/sqlite_schema.d.ts +1 -1
  28. package/dist/lib/schema/sqlite_schema.d.ts.map +1 -1
  29. package/dist/lib/schema/sqlite_schema.js +16 -0
  30. package/dist/lib/services/google_token_service.d.ts +48 -0
  31. package/dist/lib/services/google_token_service.d.ts.map +1 -0
  32. package/dist/lib/services/google_token_service.js +319 -0
  33. package/dist/lib/services/index.d.ts +1 -0
  34. package/dist/lib/services/index.d.ts.map +1 -1
  35. package/dist/lib/services/index.js +1 -0
  36. package/dist/server/routes/google_token.d.ts +13 -0
  37. package/dist/server/routes/google_token.d.ts.map +1 -0
  38. package/dist/server/routes/google_token.js +66 -0
  39. package/dist/server/routes/index.d.ts +1 -0
  40. package/dist/server/routes/index.d.ts.map +1 -1
  41. package/dist/server/routes/index.js +2 -0
  42. package/dist/server/routes/user_management_users.d.ts +1 -1
  43. package/package.json +9 -5
@@ -0,0 +1,319 @@
1
+ // file_description: stores, retrieves, refreshes, and revokes Google OAuth tokens with encrypted persistence
2
+ // section: imports
3
+ import { createCrudService } from "hazo_connect/server";
4
+ import { get_hazo_connect_instance } from "../hazo_connect_instance.server.js";
5
+ import { create_app_logger } from "../app_logger.js";
6
+ import { optional_import } from "hazo_core";
7
+ import { randomUUID } from "crypto";
8
+ // section: errors
9
+ export class GoogleTokenStorageUnconfigured extends Error {
10
+ constructor() {
11
+ super("Google token storage is not configured. Set HAZO_AUTH_OAUTH_KEY_CURRENT and HAZO_AUTH_OAUTH_KEY_<ID> env vars.");
12
+ this.name = "GoogleTokenStorageUnconfigured";
13
+ }
14
+ }
15
+ // section: cache
16
+ const access_token_cache = new Map();
17
+ // section: helpers
18
+ function makeKeyProvider(LookupKeyProvider) {
19
+ return new LookupKeyProvider((name) => {
20
+ if (name === "current")
21
+ return process.env.HAZO_AUTH_OAUTH_KEY_CURRENT;
22
+ if (name.startsWith("key_")) {
23
+ const keyId = name.slice(4).toUpperCase();
24
+ return process.env[`HAZO_AUTH_OAUTH_KEY_${keyId}`];
25
+ }
26
+ return undefined;
27
+ });
28
+ }
29
+ async function load_crypto_module() {
30
+ const cryptoModule = await optional_import("hazo_secure/crypto");
31
+ if (!cryptoModule)
32
+ throw new GoogleTokenStorageUnconfigured();
33
+ return cryptoModule;
34
+ }
35
+ // section: store
36
+ /**
37
+ * Stores (inserts or updates) Google OAuth tokens for a user, encrypting sensitive fields.
38
+ * Throws GoogleTokenStorageUnconfigured if hazo_secure/crypto is unavailable or keys are missing.
39
+ */
40
+ export async function store_google_oauth_token(params) {
41
+ var _a, _b;
42
+ const logger = create_app_logger();
43
+ const { encryptField, decryptField: _decryptField, aadFor, LookupKeyProvider } = await load_crypto_module();
44
+ const keys = makeKeyProvider(LookupKeyProvider);
45
+ // Force-fail early if no key is configured
46
+ try {
47
+ await keys.current();
48
+ }
49
+ catch (err) {
50
+ const msg = err instanceof Error ? err.message : String(err);
51
+ logger.error("google_token_service_key_provider_failed", {
52
+ filename: "google_token_service.ts",
53
+ error: msg,
54
+ });
55
+ throw new GoogleTokenStorageUnconfigured();
56
+ }
57
+ const refresh_enc = await encryptField(params.refresh_token, {
58
+ keys,
59
+ aad: aadFor("hazo_google_oauth_tokens", params.user_id, "refresh_token"),
60
+ });
61
+ const refresh_token_enc = JSON.stringify(refresh_enc);
62
+ let access_token_enc = null;
63
+ if (params.access_token) {
64
+ const access_enc = await encryptField(params.access_token, {
65
+ keys,
66
+ aad: aadFor("hazo_google_oauth_tokens", params.user_id, "access_token"),
67
+ });
68
+ access_token_enc = JSON.stringify(access_enc);
69
+ }
70
+ const adapter = get_hazo_connect_instance();
71
+ const service = createCrudService(adapter, "hazo_google_oauth_tokens");
72
+ const existing_rows = (await service.findBy({
73
+ user_id: params.user_id,
74
+ provider: "google",
75
+ }));
76
+ const now = new Date().toISOString();
77
+ if (existing_rows.length > 0) {
78
+ const existing = existing_rows[0];
79
+ await service.updateById(existing.id, {
80
+ refresh_token_enc,
81
+ access_token_enc,
82
+ scopes: params.scopes,
83
+ expires_at: (_a = params.expires_at) !== null && _a !== void 0 ? _a : null,
84
+ changed_at: now,
85
+ });
86
+ logger.info("google_token_service_token_updated", {
87
+ filename: "google_token_service.ts",
88
+ user_id: params.user_id,
89
+ });
90
+ }
91
+ else {
92
+ await service.insert({
93
+ id: randomUUID(),
94
+ user_id: params.user_id,
95
+ provider: "google",
96
+ refresh_token_enc,
97
+ access_token_enc,
98
+ scopes: params.scopes,
99
+ expires_at: (_b = params.expires_at) !== null && _b !== void 0 ? _b : null,
100
+ created_at: now,
101
+ changed_at: now,
102
+ });
103
+ logger.info("google_token_service_token_stored", {
104
+ filename: "google_token_service.ts",
105
+ user_id: params.user_id,
106
+ });
107
+ }
108
+ }
109
+ // section: get
110
+ /**
111
+ * Returns a valid access token for the user, refreshing via Google if needed.
112
+ * Returns a typed error result instead of throwing for expected failure modes.
113
+ */
114
+ export async function getGoogleToken(userId, opts) {
115
+ var _a, _b;
116
+ const logger = create_app_logger();
117
+ // Check in-memory cache first
118
+ const cached = access_token_cache.get(userId);
119
+ if (cached) {
120
+ const still_valid = new Date(cached.expires_at).getTime() - 60000 > Date.now();
121
+ if (still_valid) {
122
+ logger.info("google_token_service_cache_hit", {
123
+ filename: "google_token_service.ts",
124
+ user_id: userId,
125
+ });
126
+ // We need scopes from DB even on cache hit when scope check is requested
127
+ if (!((_a = opts === null || opts === void 0 ? void 0 : opts.scopes) === null || _a === void 0 ? void 0 : _a.length)) {
128
+ // No scope check needed — return cached token (scopes unknown from cache alone)
129
+ // Fall through to DB to get scopes for the result shape
130
+ }
131
+ }
132
+ }
133
+ const adapter = get_hazo_connect_instance();
134
+ const service = createCrudService(adapter, "hazo_google_oauth_tokens");
135
+ const rows = (await service.findBy({ user_id: userId, provider: "google" }));
136
+ if (rows.length === 0) {
137
+ return { ok: false, error: "not_connected" };
138
+ }
139
+ const row = rows[0];
140
+ // Scope check
141
+ if ((_b = opts === null || opts === void 0 ? void 0 : opts.scopes) === null || _b === void 0 ? void 0 : _b.length) {
142
+ const stored_scopes = row.scopes.split(" ").filter(Boolean);
143
+ const missing = opts.scopes.some((s) => !stored_scopes.includes(s));
144
+ if (missing) {
145
+ return { ok: false, error: "reconsent_required" };
146
+ }
147
+ }
148
+ // Return cached token now that we have the row (scope check passed)
149
+ if (cached) {
150
+ const still_valid = new Date(cached.expires_at).getTime() - 60000 > Date.now();
151
+ if (still_valid) {
152
+ return { ok: true, access_token: cached.token, scopes: row.scopes };
153
+ }
154
+ }
155
+ // Need to refresh — load crypto
156
+ let cryptoModule;
157
+ try {
158
+ cryptoModule = await load_crypto_module();
159
+ }
160
+ catch (_c) {
161
+ return { ok: false, error: "unconfigured" };
162
+ }
163
+ const { decryptField, aadFor, LookupKeyProvider } = cryptoModule;
164
+ const keys = makeKeyProvider(LookupKeyProvider);
165
+ let decrypted_refresh;
166
+ try {
167
+ decrypted_refresh = await decryptField(JSON.parse(row.refresh_token_enc), {
168
+ keys,
169
+ aad: aadFor("hazo_google_oauth_tokens", userId, "refresh_token"),
170
+ });
171
+ }
172
+ catch (err) {
173
+ const msg = err instanceof Error ? err.message : String(err);
174
+ logger.error("google_token_service_decrypt_failed", {
175
+ filename: "google_token_service.ts",
176
+ user_id: userId,
177
+ error: msg,
178
+ });
179
+ return { ok: false, error: "refresh_failed" };
180
+ }
181
+ // Call Google token refresh endpoint
182
+ let resp;
183
+ try {
184
+ resp = await fetch("https://oauth2.googleapis.com/token", {
185
+ method: "POST",
186
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
187
+ body: new URLSearchParams({
188
+ grant_type: "refresh_token",
189
+ refresh_token: decrypted_refresh,
190
+ client_id: process.env.HAZO_AUTH_GOOGLE_CLIENT_ID,
191
+ client_secret: process.env.HAZO_AUTH_GOOGLE_CLIENT_SECRET,
192
+ }),
193
+ });
194
+ }
195
+ catch (err) {
196
+ const msg = err instanceof Error ? err.message : String(err);
197
+ logger.error("google_token_service_refresh_fetch_failed", {
198
+ filename: "google_token_service.ts",
199
+ user_id: userId,
200
+ error: msg,
201
+ });
202
+ return { ok: false, error: "refresh_failed" };
203
+ }
204
+ if (!resp.ok) {
205
+ logger.warn("google_token_service_refresh_rejected", {
206
+ filename: "google_token_service.ts",
207
+ user_id: userId,
208
+ status: resp.status,
209
+ });
210
+ return { ok: false, error: "refresh_failed" };
211
+ }
212
+ const data = await resp.json();
213
+ // Persist new access token (encrypted)
214
+ const new_expires_at = new Date(Date.now() + data.expires_in * 1000).toISOString();
215
+ try {
216
+ const { encryptField } = cryptoModule;
217
+ const access_enc = await encryptField(data.access_token, {
218
+ keys,
219
+ aad: aadFor("hazo_google_oauth_tokens", userId, "access_token"),
220
+ });
221
+ const access_token_enc = JSON.stringify(access_enc);
222
+ await service.updateById(row.id, {
223
+ access_token_enc,
224
+ expires_at: new_expires_at,
225
+ changed_at: new Date().toISOString(),
226
+ });
227
+ }
228
+ catch (err) {
229
+ const msg = err instanceof Error ? err.message : String(err);
230
+ logger.warn("google_token_service_persist_access_token_failed", {
231
+ filename: "google_token_service.ts",
232
+ user_id: userId,
233
+ error: msg,
234
+ note: "Access token refreshed successfully but could not be persisted",
235
+ });
236
+ }
237
+ // Update in-memory cache
238
+ access_token_cache.set(userId, { token: data.access_token, expires_at: new_expires_at });
239
+ logger.info("google_token_service_token_refreshed", {
240
+ filename: "google_token_service.ts",
241
+ user_id: userId,
242
+ });
243
+ return { ok: true, access_token: data.access_token, scopes: row.scopes };
244
+ }
245
+ // section: revoke
246
+ /**
247
+ * Revokes the user's Google OAuth tokens — best-effort remote revocation, then deletes DB row.
248
+ */
249
+ export async function revoke_google_oauth_token(userId) {
250
+ const logger = create_app_logger();
251
+ const adapter = get_hazo_connect_instance();
252
+ const service = createCrudService(adapter, "hazo_google_oauth_tokens");
253
+ const rows = (await service.findBy({ user_id: userId, provider: "google" }));
254
+ if (rows.length === 0) {
255
+ return { ok: false, error: "not_connected" };
256
+ }
257
+ const row = rows[0];
258
+ // Attempt remote revocation — best effort
259
+ try {
260
+ const { decryptField, aadFor, LookupKeyProvider } = await load_crypto_module();
261
+ const keys = makeKeyProvider(LookupKeyProvider);
262
+ const decrypted_refresh = await decryptField(JSON.parse(row.refresh_token_enc), {
263
+ keys,
264
+ aad: aadFor("hazo_google_oauth_tokens", userId, "refresh_token"),
265
+ });
266
+ const revoke_resp = await fetch(`https://oauth2.googleapis.com/revoke?token=${encodeURIComponent(decrypted_refresh)}`, { method: "POST" });
267
+ if (!revoke_resp.ok) {
268
+ logger.warn("google_token_service_revoke_remote_failed", {
269
+ filename: "google_token_service.ts",
270
+ user_id: userId,
271
+ status: revoke_resp.status,
272
+ note: "Google revocation returned non-OK status; proceeding to delete local record",
273
+ });
274
+ }
275
+ else {
276
+ logger.info("google_token_service_revoke_remote_ok", {
277
+ filename: "google_token_service.ts",
278
+ user_id: userId,
279
+ });
280
+ }
281
+ }
282
+ catch (err) {
283
+ const msg = err instanceof Error ? err.message : String(err);
284
+ logger.warn("google_token_service_revoke_remote_error", {
285
+ filename: "google_token_service.ts",
286
+ user_id: userId,
287
+ error: msg,
288
+ note: "Remote revocation failed; proceeding to delete local record",
289
+ });
290
+ }
291
+ // Always delete the local row
292
+ await service.deleteById(row.id);
293
+ access_token_cache.delete(userId);
294
+ logger.info("google_token_service_revoked", {
295
+ filename: "google_token_service.ts",
296
+ user_id: userId,
297
+ });
298
+ return { ok: true };
299
+ }
300
+ // section: status
301
+ /**
302
+ * Returns connection status and scope information for a user's Google OAuth connection.
303
+ * Does not decrypt or refresh tokens.
304
+ */
305
+ export async function get_google_token_status(userId) {
306
+ var _a;
307
+ const adapter = get_hazo_connect_instance();
308
+ const service = createCrudService(adapter, "hazo_google_oauth_tokens");
309
+ const rows = (await service.findBy({ user_id: userId, provider: "google" }));
310
+ if (rows.length === 0) {
311
+ return { connected: false, scopes: "", expires_at: null };
312
+ }
313
+ const row = rows[0];
314
+ return {
315
+ connected: true,
316
+ scopes: row.scopes,
317
+ expires_at: (_a = row.expires_at) !== null && _a !== void 0 ? _a : null,
318
+ };
319
+ }
@@ -18,4 +18,5 @@ export * from "./scope_service.js";
18
18
  export * from "./user_scope_service.js";
19
19
  export * from "./oauth_service.js";
20
20
  export * from "./branding_service.js";
21
+ export * from "./google_token_service.js";
21
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/services/index.ts"],"names":[],"mappings":"AAEA,cAAc,iBAAiB,CAAC;AAChC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/services/index.ts"],"names":[],"mappings":"AAEA,cAAc,iBAAiB,CAAC;AAChC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC"}
@@ -20,3 +20,4 @@ export * from "./scope_service.js";
20
20
  export * from "./user_scope_service.js";
21
21
  export * from "./oauth_service.js";
22
22
  export * from "./branding_service.js";
23
+ export * from "./google_token_service.js";
@@ -0,0 +1,13 @@
1
+ import type { NextRequest } from "next/server";
2
+ /**
3
+ * GET /api/hazo_auth/google/token
4
+ * Returns the current Google OAuth token status for the authenticated user.
5
+ */
6
+ export declare function GET(request: NextRequest): Promise<Response>;
7
+ /**
8
+ * DELETE /api/hazo_auth/google/token
9
+ * Revokes the stored Google OAuth token for the authenticated user.
10
+ * Does NOT sign the user out.
11
+ */
12
+ export declare function DELETE(request: NextRequest): Promise<Response>;
13
+ //# sourceMappingURL=google_token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google_token.d.ts","sourceRoot":"","sources":["../../../src/server/routes/google_token.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAS/C;;;GAGG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW,qBAuB7C;AAGD;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW,qBAuBhD"}
@@ -0,0 +1,66 @@
1
+ import { hazo_get_auth } from "../../lib/auth/hazo_get_auth.server.js";
2
+ import { get_google_token_status, revoke_google_oauth_token, } from "../../lib/services/google_token_service.js";
3
+ import { create_app_logger } from "../../lib/app_logger.js";
4
+ // section: get_handler
5
+ /**
6
+ * GET /api/hazo_auth/google/token
7
+ * Returns the current Google OAuth token status for the authenticated user.
8
+ */
9
+ export async function GET(request) {
10
+ var _a;
11
+ const logger = create_app_logger();
12
+ try {
13
+ const auth = await hazo_get_auth(request);
14
+ if (!((_a = auth.user) === null || _a === void 0 ? void 0 : _a.id)) {
15
+ return new Response(JSON.stringify({ ok: false, error: "unauthenticated" }), {
16
+ status: 401,
17
+ headers: { "Content-Type": "application/json" },
18
+ });
19
+ }
20
+ const status = await get_google_token_status(auth.user.id);
21
+ return new Response(JSON.stringify({ ok: true, data: status }), {
22
+ status: 200,
23
+ headers: { "Content-Type": "application/json" },
24
+ });
25
+ }
26
+ catch (error) {
27
+ const msg = error instanceof Error ? error.message : String(error);
28
+ logger.error("google_token_get_error", { error: msg });
29
+ return new Response(JSON.stringify({ ok: false, error: "internal_error" }), {
30
+ status: 500,
31
+ headers: { "Content-Type": "application/json" },
32
+ });
33
+ }
34
+ }
35
+ // section: delete_handler
36
+ /**
37
+ * DELETE /api/hazo_auth/google/token
38
+ * Revokes the stored Google OAuth token for the authenticated user.
39
+ * Does NOT sign the user out.
40
+ */
41
+ export async function DELETE(request) {
42
+ var _a;
43
+ const logger = create_app_logger();
44
+ try {
45
+ const auth = await hazo_get_auth(request);
46
+ if (!((_a = auth.user) === null || _a === void 0 ? void 0 : _a.id)) {
47
+ return new Response(JSON.stringify({ ok: false, error: "unauthenticated" }), {
48
+ status: 401,
49
+ headers: { "Content-Type": "application/json" },
50
+ });
51
+ }
52
+ const result = await revoke_google_oauth_token(auth.user.id);
53
+ return new Response(JSON.stringify(result), {
54
+ status: result.ok ? 200 : 400,
55
+ headers: { "Content-Type": "application/json" },
56
+ });
57
+ }
58
+ catch (error) {
59
+ const msg = error instanceof Error ? error.message : String(error);
60
+ logger.error("google_token_delete_error", { error: msg });
61
+ return new Response(JSON.stringify({ ok: false, error: "internal_error" }), {
62
+ status: 500,
63
+ headers: { "Content-Type": "application/json" },
64
+ });
65
+ }
66
+ }
@@ -39,4 +39,5 @@ export { legalDocsAcceptPOST } from './legal_docs_accept.js';
39
39
  export { legalDocsPublishPOST } from './legal_docs_publish.js';
40
40
  export { consentMeGET } from "./consent_me.js";
41
41
  export { stringsDefaultsGET } from "./strings_defaults.js";
42
+ export { GET as googleTokenGET, DELETE as googleTokenDELETE } from "./google_token.js";
42
43
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/routes/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/routes/index.ts"],"names":[],"mappings":"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"}
@@ -56,3 +56,5 @@ export { legalDocsPublishPOST } from './legal_docs_publish.js';
56
56
  export { consentMeGET } from "./consent_me.js";
57
57
  // Strings routes
58
58
  export { stringsDefaultsGET } from "./strings_defaults.js";
59
+ // Google OAuth token routes (status + revoke)
60
+ export { GET as googleTokenGET, DELETE as googleTokenDELETE } from "./google_token.js";
@@ -26,7 +26,7 @@ export declare function GET(request: NextRequest): Promise<NextResponse<{
26
26
  profile_source: {} | null;
27
27
  user_type: string | null;
28
28
  app_user_data: Record<string, unknown> | null;
29
- legal_acceptance_status: "none" | "current" | "outdated";
29
+ legal_acceptance_status: "current" | "none" | "outdated";
30
30
  }[];
31
31
  }>>;
32
32
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_auth",
3
- "version": "10.0.0",
3
+ "version": "10.1.0",
4
4
  "description": "Zero-config authentication UI components for Next.js with RBAC, OAuth, scope-based multi-tenancy, and invitations",
5
5
  "keywords": [
6
6
  "authentication",
@@ -254,11 +254,12 @@
254
254
  "@radix-ui/react-tooltip": "^1.2.0",
255
255
  "hazo_api": "^2.3.1",
256
256
  "hazo_config": "^2.1.10",
257
- "hazo_connect": "^3.4.1",
257
+ "hazo_connect": "^3.5.1",
258
258
  "hazo_core": "^1.1.0",
259
259
  "hazo_logs": "^2.0.3",
260
260
  "hazo_notify": "^6.1.3",
261
- "hazo_ui": "^3.2.1",
261
+ "hazo_secure": "^1.1.0",
262
+ "hazo_ui": "^3.4.1",
262
263
  "input-otp": "^1.4.0",
263
264
  "lucide-react": "^0.553.0",
264
265
  "next": "^14.0.0",
@@ -287,6 +288,9 @@
287
288
  "hazo_notify": {
288
289
  "optional": true
289
290
  },
291
+ "hazo_secure": {
292
+ "optional": true
293
+ },
290
294
  "hazo_ui": {
291
295
  "optional": true
292
296
  },
@@ -390,11 +394,11 @@
390
394
  "eslint-plugin-storybook": "^10.0.6",
391
395
  "hazo_api": "^2.3.1",
392
396
  "hazo_config": "^2.1.10",
393
- "hazo_connect": "^3.4.1",
397
+ "hazo_connect": "^3.5.1",
394
398
  "hazo_core": "^1.1.0",
395
399
  "hazo_logs": "^2.0.3",
396
400
  "hazo_notify": "^6.1.3",
397
- "hazo_ui": "^3.2.1",
401
+ "hazo_ui": "^3.4.1",
398
402
  "input-otp": "^1.4.0",
399
403
  "jest": "^30.2.0",
400
404
  "jest-environment-jsdom": "^30.0.0",