@contentgrowth/llm-service 1.4.0 → 1.4.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/dist/index.d.cts +1 -92
- package/dist/index.d.ts +1 -92
- package/dist/utils/google-auth.cjs +257 -0
- package/dist/utils/google-auth.cjs.map +1 -0
- package/dist/utils/google-auth.d.cts +151 -0
- package/dist/utils/google-auth.d.ts +151 -0
- package/dist/utils/google-auth.js +230 -0
- package/dist/utils/google-auth.js.map +1 -0
- package/dist/utils/index.cjs +259 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +230 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -2,6 +2,7 @@ import OpenAI from 'openai';
|
|
|
2
2
|
import Anthropic from '@anthropic-ai/sdk';
|
|
3
3
|
import { GoogleGenAI } from '@google/genai';
|
|
4
4
|
export { Modality } from '@google/genai';
|
|
5
|
+
import { GoogleTokenManager } from './utils/google-auth.cjs';
|
|
5
6
|
|
|
6
7
|
declare namespace FINISH_REASONS {
|
|
7
8
|
let COMPLETED: string;
|
|
@@ -807,98 +808,6 @@ declare function handleApiError(error: Error, operation?: string, context?: stri
|
|
|
807
808
|
*/
|
|
808
809
|
declare function sanitizeError(error: Error, context?: string): Error;
|
|
809
810
|
|
|
810
|
-
/**
|
|
811
|
-
* Google OAuth2 Token Manager
|
|
812
|
-
*
|
|
813
|
-
* Handles token generation, caching, and automatic refresh for
|
|
814
|
-
* Google Cloud service accounts. Tokens are cached and automatically
|
|
815
|
-
* refreshed when they expire (with a 5-minute safety buffer).
|
|
816
|
-
*
|
|
817
|
-
* @example
|
|
818
|
-
* const sa = parseGoogleCredentials(credentials);
|
|
819
|
-
* const tokenManager = new GoogleTokenManager(sa);
|
|
820
|
-
*
|
|
821
|
-
* // Get token (cached or fresh)
|
|
822
|
-
* const token = await tokenManager.getToken();
|
|
823
|
-
*
|
|
824
|
-
* // Force refresh
|
|
825
|
-
* tokenManager.invalidate();
|
|
826
|
-
* const newToken = await tokenManager.getToken();
|
|
827
|
-
*/
|
|
828
|
-
declare class GoogleTokenManager {
|
|
829
|
-
/**
|
|
830
|
-
* @param {object} serviceAccount - Parsed service account with client_email and private_key
|
|
831
|
-
* @param {object} options - Optional configuration
|
|
832
|
-
* @param {string} options.scope - OAuth2 scope (default: cloud-platform)
|
|
833
|
-
* @param {number} options.tokenLifetime - Token lifetime in seconds (default: 3600)
|
|
834
|
-
*/
|
|
835
|
-
constructor(serviceAccount: object, options?: {
|
|
836
|
-
scope: string;
|
|
837
|
-
tokenLifetime: number;
|
|
838
|
-
});
|
|
839
|
-
clientEmail: any;
|
|
840
|
-
privateKey: any;
|
|
841
|
-
projectId: any;
|
|
842
|
-
scope: string;
|
|
843
|
-
tokenLifetime: number;
|
|
844
|
-
_tokenCache: string;
|
|
845
|
-
_expiresAt: number;
|
|
846
|
-
/**
|
|
847
|
-
* Get a valid access token (cached or fresh)
|
|
848
|
-
*
|
|
849
|
-
* @returns {Promise<string>} OAuth2 access token
|
|
850
|
-
*/
|
|
851
|
-
getToken(): Promise<string>;
|
|
852
|
-
/**
|
|
853
|
-
* Clear cached token (force refresh on next getToken call)
|
|
854
|
-
*/
|
|
855
|
-
invalidate(): void;
|
|
856
|
-
/**
|
|
857
|
-
* Check if cached token is still valid
|
|
858
|
-
*
|
|
859
|
-
* @returns {boolean} True if token is valid
|
|
860
|
-
*/
|
|
861
|
-
isValid(): boolean;
|
|
862
|
-
/**
|
|
863
|
-
* Get time until token expires (in seconds)
|
|
864
|
-
*
|
|
865
|
-
* @returns {number} Seconds until expiration (0 if no token or expired)
|
|
866
|
-
*/
|
|
867
|
-
getTimeToExpiry(): number;
|
|
868
|
-
/**
|
|
869
|
-
* Generate OAuth2 token via JWT flow
|
|
870
|
-
*
|
|
871
|
-
* @private
|
|
872
|
-
* @returns {Promise<string>} Access token
|
|
873
|
-
*/
|
|
874
|
-
private _generateToken;
|
|
875
|
-
/**
|
|
876
|
-
* Sign JWT using service account private key
|
|
877
|
-
*
|
|
878
|
-
* @private
|
|
879
|
-
* @param {object} header - JWT header
|
|
880
|
-
* @param {object} payload - JWT payload
|
|
881
|
-
* @returns {Promise<string>} Signed JWT
|
|
882
|
-
*/
|
|
883
|
-
private _signJWT;
|
|
884
|
-
/**
|
|
885
|
-
* Import PEM private key for signing
|
|
886
|
-
*
|
|
887
|
-
* @private
|
|
888
|
-
* @param {string} pemKey - PEM formatted private key
|
|
889
|
-
* @returns {Promise<CryptoKey>} Imported key
|
|
890
|
-
*/
|
|
891
|
-
private _importPrivateKey;
|
|
892
|
-
/**
|
|
893
|
-
* Base64 URL encode (without padding)
|
|
894
|
-
*
|
|
895
|
-
* @private
|
|
896
|
-
* @param {string|ArrayBuffer} input - Data to encode
|
|
897
|
-
* @returns {string} Base64 URL encoded string
|
|
898
|
-
*/
|
|
899
|
-
private _base64UrlEncode;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
811
|
/**
|
|
903
812
|
* Transcription Service - Separate from LLM Service
|
|
904
813
|
* Handles audio-to-text transcription using various providers.
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import OpenAI from 'openai';
|
|
|
2
2
|
import Anthropic from '@anthropic-ai/sdk';
|
|
3
3
|
import { GoogleGenAI } from '@google/genai';
|
|
4
4
|
export { Modality } from '@google/genai';
|
|
5
|
+
import { GoogleTokenManager } from './utils/google-auth.js';
|
|
5
6
|
|
|
6
7
|
declare namespace FINISH_REASONS {
|
|
7
8
|
let COMPLETED: string;
|
|
@@ -807,98 +808,6 @@ declare function handleApiError(error: Error, operation?: string, context?: stri
|
|
|
807
808
|
*/
|
|
808
809
|
declare function sanitizeError(error: Error, context?: string): Error;
|
|
809
810
|
|
|
810
|
-
/**
|
|
811
|
-
* Google OAuth2 Token Manager
|
|
812
|
-
*
|
|
813
|
-
* Handles token generation, caching, and automatic refresh for
|
|
814
|
-
* Google Cloud service accounts. Tokens are cached and automatically
|
|
815
|
-
* refreshed when they expire (with a 5-minute safety buffer).
|
|
816
|
-
*
|
|
817
|
-
* @example
|
|
818
|
-
* const sa = parseGoogleCredentials(credentials);
|
|
819
|
-
* const tokenManager = new GoogleTokenManager(sa);
|
|
820
|
-
*
|
|
821
|
-
* // Get token (cached or fresh)
|
|
822
|
-
* const token = await tokenManager.getToken();
|
|
823
|
-
*
|
|
824
|
-
* // Force refresh
|
|
825
|
-
* tokenManager.invalidate();
|
|
826
|
-
* const newToken = await tokenManager.getToken();
|
|
827
|
-
*/
|
|
828
|
-
declare class GoogleTokenManager {
|
|
829
|
-
/**
|
|
830
|
-
* @param {object} serviceAccount - Parsed service account with client_email and private_key
|
|
831
|
-
* @param {object} options - Optional configuration
|
|
832
|
-
* @param {string} options.scope - OAuth2 scope (default: cloud-platform)
|
|
833
|
-
* @param {number} options.tokenLifetime - Token lifetime in seconds (default: 3600)
|
|
834
|
-
*/
|
|
835
|
-
constructor(serviceAccount: object, options?: {
|
|
836
|
-
scope: string;
|
|
837
|
-
tokenLifetime: number;
|
|
838
|
-
});
|
|
839
|
-
clientEmail: any;
|
|
840
|
-
privateKey: any;
|
|
841
|
-
projectId: any;
|
|
842
|
-
scope: string;
|
|
843
|
-
tokenLifetime: number;
|
|
844
|
-
_tokenCache: string;
|
|
845
|
-
_expiresAt: number;
|
|
846
|
-
/**
|
|
847
|
-
* Get a valid access token (cached or fresh)
|
|
848
|
-
*
|
|
849
|
-
* @returns {Promise<string>} OAuth2 access token
|
|
850
|
-
*/
|
|
851
|
-
getToken(): Promise<string>;
|
|
852
|
-
/**
|
|
853
|
-
* Clear cached token (force refresh on next getToken call)
|
|
854
|
-
*/
|
|
855
|
-
invalidate(): void;
|
|
856
|
-
/**
|
|
857
|
-
* Check if cached token is still valid
|
|
858
|
-
*
|
|
859
|
-
* @returns {boolean} True if token is valid
|
|
860
|
-
*/
|
|
861
|
-
isValid(): boolean;
|
|
862
|
-
/**
|
|
863
|
-
* Get time until token expires (in seconds)
|
|
864
|
-
*
|
|
865
|
-
* @returns {number} Seconds until expiration (0 if no token or expired)
|
|
866
|
-
*/
|
|
867
|
-
getTimeToExpiry(): number;
|
|
868
|
-
/**
|
|
869
|
-
* Generate OAuth2 token via JWT flow
|
|
870
|
-
*
|
|
871
|
-
* @private
|
|
872
|
-
* @returns {Promise<string>} Access token
|
|
873
|
-
*/
|
|
874
|
-
private _generateToken;
|
|
875
|
-
/**
|
|
876
|
-
* Sign JWT using service account private key
|
|
877
|
-
*
|
|
878
|
-
* @private
|
|
879
|
-
* @param {object} header - JWT header
|
|
880
|
-
* @param {object} payload - JWT payload
|
|
881
|
-
* @returns {Promise<string>} Signed JWT
|
|
882
|
-
*/
|
|
883
|
-
private _signJWT;
|
|
884
|
-
/**
|
|
885
|
-
* Import PEM private key for signing
|
|
886
|
-
*
|
|
887
|
-
* @private
|
|
888
|
-
* @param {string} pemKey - PEM formatted private key
|
|
889
|
-
* @returns {Promise<CryptoKey>} Imported key
|
|
890
|
-
*/
|
|
891
|
-
private _importPrivateKey;
|
|
892
|
-
/**
|
|
893
|
-
* Base64 URL encode (without padding)
|
|
894
|
-
*
|
|
895
|
-
* @private
|
|
896
|
-
* @param {string|ArrayBuffer} input - Data to encode
|
|
897
|
-
* @returns {string} Base64 URL encoded string
|
|
898
|
-
*/
|
|
899
|
-
private _base64UrlEncode;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
811
|
/**
|
|
903
812
|
* Transcription Service - Separate from LLM Service
|
|
904
813
|
* Handles audio-to-text transcription using various providers.
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/utils/google-auth.js
|
|
20
|
+
var google_auth_exports = {};
|
|
21
|
+
__export(google_auth_exports, {
|
|
22
|
+
GoogleTokenManager: () => GoogleTokenManager,
|
|
23
|
+
getGoogleOAuth2Token: () => getGoogleOAuth2Token,
|
|
24
|
+
parseGoogleCredentials: () => parseGoogleCredentials,
|
|
25
|
+
validateServiceAccount: () => validateServiceAccount
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(google_auth_exports);
|
|
28
|
+
var import_node_buffer = require("buffer");
|
|
29
|
+
function parseGoogleCredentials(input) {
|
|
30
|
+
if (!input) {
|
|
31
|
+
throw new Error("Google Cloud credentials not provided");
|
|
32
|
+
}
|
|
33
|
+
if (typeof input === "object") {
|
|
34
|
+
const { client_email, private_key } = input;
|
|
35
|
+
if (!client_email || !private_key) {
|
|
36
|
+
throw new Error("Google Cloud Service Account object missing client_email or private_key");
|
|
37
|
+
}
|
|
38
|
+
return input;
|
|
39
|
+
}
|
|
40
|
+
if (typeof input === "string") {
|
|
41
|
+
const trimmed = input.trim();
|
|
42
|
+
if (trimmed.startsWith("ya29.")) {
|
|
43
|
+
return trimmed;
|
|
44
|
+
}
|
|
45
|
+
if (trimmed.startsWith("AIzaSy")) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
"Google Cloud Service APIs (Text-to-Speech, Speech-to-Text) do not support API keys (AIzaSy...). Please provide a Service Account JSON key from GCP Console > IAM & Admin > Service Accounts."
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
let jsonString = trimmed;
|
|
51
|
+
if (!jsonString.startsWith("{")) {
|
|
52
|
+
try {
|
|
53
|
+
jsonString = import_node_buffer.Buffer.from(jsonString, "base64").toString("utf-8");
|
|
54
|
+
} catch (err) {
|
|
55
|
+
throw new Error(`Failed to decode base64 service account: ${err.message}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const parsed = JSON.parse(jsonString);
|
|
60
|
+
if (!parsed.client_email || !parsed.private_key) {
|
|
61
|
+
throw new Error("Service account missing required fields: client_email, private_key");
|
|
62
|
+
}
|
|
63
|
+
return parsed;
|
|
64
|
+
} catch (err) {
|
|
65
|
+
if (err.message.includes("missing required fields")) {
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`Failed to parse service account JSON: ${err.message}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
throw new Error(
|
|
72
|
+
"Invalid Google Cloud credentials. Expected a Service Account JSON (with client_email & private_key) or OAuth2 Bearer token."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
function validateServiceAccount(sa) {
|
|
76
|
+
if (!sa || typeof sa !== "object") {
|
|
77
|
+
throw new Error("Service account must be an object");
|
|
78
|
+
}
|
|
79
|
+
if (!sa.client_email) {
|
|
80
|
+
throw new Error("Service account missing client_email");
|
|
81
|
+
}
|
|
82
|
+
if (!sa.private_key) {
|
|
83
|
+
throw new Error("Service account missing private_key");
|
|
84
|
+
}
|
|
85
|
+
if (!sa.project_id) {
|
|
86
|
+
console.warn("[GoogleAuth] Service account missing project_id - may need to specify project explicitly");
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
var GoogleTokenManager = class {
|
|
91
|
+
/**
|
|
92
|
+
* @param {object} serviceAccount - Parsed service account with client_email and private_key
|
|
93
|
+
* @param {object} options - Optional configuration
|
|
94
|
+
* @param {string} options.scope - OAuth2 scope (default: cloud-platform)
|
|
95
|
+
* @param {number} options.tokenLifetime - Token lifetime in seconds (default: 3600)
|
|
96
|
+
*/
|
|
97
|
+
constructor(serviceAccount, options = {}) {
|
|
98
|
+
validateServiceAccount(serviceAccount);
|
|
99
|
+
this.clientEmail = serviceAccount.client_email;
|
|
100
|
+
this.privateKey = serviceAccount.private_key;
|
|
101
|
+
this.projectId = serviceAccount.project_id;
|
|
102
|
+
this.scope = options.scope || "https://www.googleapis.com/auth/cloud-platform";
|
|
103
|
+
this.tokenLifetime = options.tokenLifetime || 3600;
|
|
104
|
+
this._tokenCache = null;
|
|
105
|
+
this._expiresAt = 0;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get a valid access token (cached or fresh)
|
|
109
|
+
*
|
|
110
|
+
* @returns {Promise<string>} OAuth2 access token
|
|
111
|
+
*/
|
|
112
|
+
async getToken() {
|
|
113
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
114
|
+
if (this._tokenCache && now < this._expiresAt - 300) {
|
|
115
|
+
return this._tokenCache;
|
|
116
|
+
}
|
|
117
|
+
this._tokenCache = await this._generateToken();
|
|
118
|
+
this._expiresAt = now + this.tokenLifetime;
|
|
119
|
+
return this._tokenCache;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Clear cached token (force refresh on next getToken call)
|
|
123
|
+
*/
|
|
124
|
+
invalidate() {
|
|
125
|
+
this._tokenCache = null;
|
|
126
|
+
this._expiresAt = 0;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Check if cached token is still valid
|
|
130
|
+
*
|
|
131
|
+
* @returns {boolean} True if token is valid
|
|
132
|
+
*/
|
|
133
|
+
isValid() {
|
|
134
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
135
|
+
return this._tokenCache && now < this._expiresAt - 300;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get time until token expires (in seconds)
|
|
139
|
+
*
|
|
140
|
+
* @returns {number} Seconds until expiration (0 if no token or expired)
|
|
141
|
+
*/
|
|
142
|
+
getTimeToExpiry() {
|
|
143
|
+
if (!this._tokenCache) return 0;
|
|
144
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
145
|
+
return Math.max(0, this._expiresAt - now);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Generate OAuth2 token via JWT flow
|
|
149
|
+
*
|
|
150
|
+
* @private
|
|
151
|
+
* @returns {Promise<string>} Access token
|
|
152
|
+
*/
|
|
153
|
+
async _generateToken() {
|
|
154
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
155
|
+
const header = {
|
|
156
|
+
alg: "RS256",
|
|
157
|
+
typ: "JWT"
|
|
158
|
+
};
|
|
159
|
+
const payload = {
|
|
160
|
+
iss: this.clientEmail,
|
|
161
|
+
scope: this.scope,
|
|
162
|
+
aud: "https://oauth2.googleapis.com/token",
|
|
163
|
+
exp: now + this.tokenLifetime,
|
|
164
|
+
iat: now
|
|
165
|
+
};
|
|
166
|
+
const jwt = await this._signJWT(header, payload);
|
|
167
|
+
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
168
|
+
method: "POST",
|
|
169
|
+
headers: {
|
|
170
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
171
|
+
},
|
|
172
|
+
body: new URLSearchParams({
|
|
173
|
+
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
174
|
+
assertion: jwt
|
|
175
|
+
})
|
|
176
|
+
});
|
|
177
|
+
if (!response.ok) {
|
|
178
|
+
const error = await response.text();
|
|
179
|
+
throw new Error(`Failed to get OAuth2 token: ${response.status} - ${error}`);
|
|
180
|
+
}
|
|
181
|
+
const data = await response.json();
|
|
182
|
+
if (!data.access_token) {
|
|
183
|
+
throw new Error("No access_token in OAuth2 response");
|
|
184
|
+
}
|
|
185
|
+
return data.access_token;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Sign JWT using service account private key
|
|
189
|
+
*
|
|
190
|
+
* @private
|
|
191
|
+
* @param {object} header - JWT header
|
|
192
|
+
* @param {object} payload - JWT payload
|
|
193
|
+
* @returns {Promise<string>} Signed JWT
|
|
194
|
+
*/
|
|
195
|
+
async _signJWT(header, payload) {
|
|
196
|
+
const encoder = new TextEncoder();
|
|
197
|
+
const headerB64 = this._base64UrlEncode(JSON.stringify(header));
|
|
198
|
+
const payloadB64 = this._base64UrlEncode(JSON.stringify(payload));
|
|
199
|
+
const unsignedToken = `${headerB64}.${payloadB64}`;
|
|
200
|
+
const privateKey = await this._importPrivateKey(this.privateKey);
|
|
201
|
+
const signature = await crypto.subtle.sign(
|
|
202
|
+
{ name: "RSASSA-PKCS1-v1_5" },
|
|
203
|
+
privateKey,
|
|
204
|
+
encoder.encode(unsignedToken)
|
|
205
|
+
);
|
|
206
|
+
const signatureB64 = this._base64UrlEncode(signature);
|
|
207
|
+
return `${unsignedToken}.${signatureB64}`;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Import PEM private key for signing
|
|
211
|
+
*
|
|
212
|
+
* @private
|
|
213
|
+
* @param {string} pemKey - PEM formatted private key
|
|
214
|
+
* @returns {Promise<CryptoKey>} Imported key
|
|
215
|
+
*/
|
|
216
|
+
async _importPrivateKey(pemKey) {
|
|
217
|
+
const pemContents = pemKey.replace(/-----BEGIN PRIVATE KEY-----/, "").replace(/-----END PRIVATE KEY-----/, "").replace(/\\n/g, "").replace(/\n/g, "").trim();
|
|
218
|
+
const binaryKey = import_node_buffer.Buffer.from(pemContents, "base64");
|
|
219
|
+
return crypto.subtle.importKey(
|
|
220
|
+
"pkcs8",
|
|
221
|
+
binaryKey,
|
|
222
|
+
{
|
|
223
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
224
|
+
hash: "SHA-256"
|
|
225
|
+
},
|
|
226
|
+
false,
|
|
227
|
+
["sign"]
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Base64 URL encode (without padding)
|
|
232
|
+
*
|
|
233
|
+
* @private
|
|
234
|
+
* @param {string|ArrayBuffer} input - Data to encode
|
|
235
|
+
* @returns {string} Base64 URL encoded string
|
|
236
|
+
*/
|
|
237
|
+
_base64UrlEncode(input) {
|
|
238
|
+
const buffer = typeof input === "string" ? import_node_buffer.Buffer.from(input, "utf-8") : import_node_buffer.Buffer.from(input);
|
|
239
|
+
return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
async function getGoogleOAuth2Token(credentialInput, options = {}) {
|
|
243
|
+
const parsed = parseGoogleCredentials(credentialInput);
|
|
244
|
+
if (typeof parsed === "string") {
|
|
245
|
+
return parsed;
|
|
246
|
+
}
|
|
247
|
+
const manager = new GoogleTokenManager(parsed, options);
|
|
248
|
+
return manager.getToken();
|
|
249
|
+
}
|
|
250
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
251
|
+
0 && (module.exports = {
|
|
252
|
+
GoogleTokenManager,
|
|
253
|
+
getGoogleOAuth2Token,
|
|
254
|
+
parseGoogleCredentials,
|
|
255
|
+
validateServiceAccount
|
|
256
|
+
});
|
|
257
|
+
//# sourceMappingURL=google-auth.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/google-auth.js"],"sourcesContent":["/**\n * Google Cloud Authentication Utilities\n * \n * Provides service account parsing, OAuth2 token generation,\n * and token lifecycle management for Google Cloud services.\n * \n * These utilities are designed for edge runtime environments\n * (Cloudflare Workers, Vercel Edge, etc.) where traditional\n * ADC (Application Default Credentials) is not available.\n */\n\nimport { Buffer } from 'node:buffer';\n\n/**\n * Parses and normalizes Google Service Account credentials.\n * Accepts:\n * - Service account JSON string\n * - Base64-encoded service account JSON string\n * - JavaScript object { client_email, private_key }\n * - Direct OAuth2 token string (starts with ya29.)\n * \n * @param {string|object} input - Service account as JSON string, base64, object, or OAuth2 token\n * @returns {string|object} OAuth2 token string (if input is token) or service account object\n * @throws {Error} If input is invalid or missing required fields\n * \n * @example\n * // From JSON string\n * const sa = parseGoogleCredentials('{\"client_email\":\"...\",\"private_key\":\"...\"}');\n * // Returns: { client_email, private_key, ... }\n * \n * // From base64\n * const sa = parseGoogleCredentials('eyJjbGllbnRfZW1haWwiOi4uLn0=');\n * // Returns: { client_email, private_key, ... }\n * \n * // From object\n * const sa = parseGoogleCredentials({ client_email: '...', private_key: '...' });\n * // Returns: { client_email, private_key, ... }\n * \n * // From OAuth2 token (pass-through)\n * const token = parseGoogleCredentials('ya29.a0...');\n * // Returns: 'ya29.a0...'\n */\nexport function parseGoogleCredentials(input) {\n if (!input) {\n throw new Error('Google Cloud credentials not provided');\n }\n \n // Already an object with client_email and private_key\n if (typeof input === 'object') {\n const { client_email, private_key } = input;\n if (!client_email || !private_key) {\n throw new Error('Google Cloud Service Account object missing client_email or private_key');\n }\n return input;\n }\n \n if (typeof input === 'string') {\n const trimmed = input.trim();\n \n // Already a Google OAuth2 access token (starts with ya29.)\n if (trimmed.startsWith('ya29.')) {\n return trimmed;\n }\n \n // Detect API key and provide clear error message\n if (trimmed.startsWith('AIzaSy')) {\n throw new Error(\n 'Google Cloud Service APIs (Text-to-Speech, Speech-to-Text) do not support API keys (AIzaSy...). ' +\n 'Please provide a Service Account JSON key from GCP Console > IAM & Admin > Service Accounts.'\n );\n }\n \n let jsonString = trimmed;\n \n // Try base64 decode if doesn't look like JSON\n if (!jsonString.startsWith('{')) {\n try {\n jsonString = Buffer.from(jsonString, 'base64').toString('utf-8');\n } catch (err) {\n throw new Error(`Failed to decode base64 service account: ${err.message}`);\n }\n }\n \n // Parse JSON\n try {\n const parsed = JSON.parse(jsonString);\n \n if (!parsed.client_email || !parsed.private_key) {\n throw new Error('Service account missing required fields: client_email, private_key');\n }\n \n return parsed;\n } catch (err) {\n if (err.message.includes('missing required fields')) {\n throw err;\n }\n throw new Error(`Failed to parse service account JSON: ${err.message}`);\n }\n }\n \n throw new Error(\n 'Invalid Google Cloud credentials. Expected a Service Account JSON (with client_email & private_key) or OAuth2 Bearer token.'\n );\n}\n\n/**\n * Validate service account has required fields\n * \n * @param {object} sa - Service account object\n * @returns {boolean} True if valid\n * @throws {Error} If invalid\n */\nexport function validateServiceAccount(sa) {\n if (!sa || typeof sa !== 'object') {\n throw new Error('Service account must be an object');\n }\n \n if (!sa.client_email) {\n throw new Error('Service account missing client_email');\n }\n \n if (!sa.private_key) {\n throw new Error('Service account missing private_key');\n }\n \n if (!sa.project_id) {\n console.warn('[GoogleAuth] Service account missing project_id - may need to specify project explicitly');\n }\n \n return true;\n}\n\n/**\n * Google OAuth2 Token Manager\n * \n * Handles token generation, caching, and automatic refresh for\n * Google Cloud service accounts. Tokens are cached and automatically\n * refreshed when they expire (with a 5-minute safety buffer).\n * \n * @example\n * const sa = parseGoogleCredentials(credentials);\n * const tokenManager = new GoogleTokenManager(sa);\n * \n * // Get token (cached or fresh)\n * const token = await tokenManager.getToken();\n * \n * // Force refresh\n * tokenManager.invalidate();\n * const newToken = await tokenManager.getToken();\n */\nexport class GoogleTokenManager {\n /**\n * @param {object} serviceAccount - Parsed service account with client_email and private_key\n * @param {object} options - Optional configuration\n * @param {string} options.scope - OAuth2 scope (default: cloud-platform)\n * @param {number} options.tokenLifetime - Token lifetime in seconds (default: 3600)\n */\n constructor(serviceAccount, options = {}) {\n validateServiceAccount(serviceAccount);\n \n this.clientEmail = serviceAccount.client_email;\n this.privateKey = serviceAccount.private_key;\n this.projectId = serviceAccount.project_id;\n \n this.scope = options.scope || 'https://www.googleapis.com/auth/cloud-platform';\n this.tokenLifetime = options.tokenLifetime || 3600;\n \n this._tokenCache = null;\n this._expiresAt = 0;\n }\n \n /**\n * Get a valid access token (cached or fresh)\n * \n * @returns {Promise<string>} OAuth2 access token\n */\n async getToken() {\n const now = Math.floor(Date.now() / 1000);\n \n // Return cached token if still valid (with 5 min buffer)\n if (this._tokenCache && now < this._expiresAt - 300) {\n return this._tokenCache;\n }\n \n // Generate new token\n this._tokenCache = await this._generateToken();\n this._expiresAt = now + this.tokenLifetime;\n \n return this._tokenCache;\n }\n \n /**\n * Clear cached token (force refresh on next getToken call)\n */\n invalidate() {\n this._tokenCache = null;\n this._expiresAt = 0;\n }\n \n /**\n * Check if cached token is still valid\n * \n * @returns {boolean} True if token is valid\n */\n isValid() {\n const now = Math.floor(Date.now() / 1000);\n return this._tokenCache && now < this._expiresAt - 300;\n }\n \n /**\n * Get time until token expires (in seconds)\n * \n * @returns {number} Seconds until expiration (0 if no token or expired)\n */\n getTimeToExpiry() {\n if (!this._tokenCache) return 0;\n const now = Math.floor(Date.now() / 1000);\n return Math.max(0, this._expiresAt - now);\n }\n \n /**\n * Generate OAuth2 token via JWT flow\n * \n * @private\n * @returns {Promise<string>} Access token\n */\n async _generateToken() {\n const now = Math.floor(Date.now() / 1000);\n \n // Create JWT header\n const header = {\n alg: 'RS256',\n typ: 'JWT'\n };\n \n // Create JWT payload\n const payload = {\n iss: this.clientEmail,\n scope: this.scope,\n aud: 'https://oauth2.googleapis.com/token',\n exp: now + this.tokenLifetime,\n iat: now\n };\n \n // Sign JWT\n const jwt = await this._signJWT(header, payload);\n \n // Exchange JWT for access token\n const response = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded'\n },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',\n assertion: jwt\n })\n });\n \n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to get OAuth2 token: ${response.status} - ${error}`);\n }\n \n const data = await response.json();\n \n if (!data.access_token) {\n throw new Error('No access_token in OAuth2 response');\n }\n \n return data.access_token;\n }\n \n /**\n * Sign JWT using service account private key\n * \n * @private\n * @param {object} header - JWT header\n * @param {object} payload - JWT payload\n * @returns {Promise<string>} Signed JWT\n */\n async _signJWT(header, payload) {\n const encoder = new TextEncoder();\n \n // Encode header and payload\n const headerB64 = this._base64UrlEncode(JSON.stringify(header));\n const payloadB64 = this._base64UrlEncode(JSON.stringify(payload));\n const unsignedToken = `${headerB64}.${payloadB64}`;\n \n // Import private key\n const privateKey = await this._importPrivateKey(this.privateKey);\n \n // Sign\n const signature = await crypto.subtle.sign(\n { name: 'RSASSA-PKCS1-v1_5' },\n privateKey,\n encoder.encode(unsignedToken)\n );\n \n // Encode signature\n const signatureB64 = this._base64UrlEncode(signature);\n \n return `${unsignedToken}.${signatureB64}`;\n }\n \n /**\n * Import PEM private key for signing\n * \n * @private\n * @param {string} pemKey - PEM formatted private key\n * @returns {Promise<CryptoKey>} Imported key\n */\n async _importPrivateKey(pemKey) {\n // Remove PEM headers and newlines\n const pemContents = pemKey\n .replace(/-----BEGIN PRIVATE KEY-----/, '')\n .replace(/-----END PRIVATE KEY-----/, '')\n .replace(/\\\\n/g, '')\n .replace(/\\n/g, '')\n .trim();\n \n // Decode base64\n const binaryKey = Buffer.from(pemContents, 'base64');\n \n // Import key\n return crypto.subtle.importKey(\n 'pkcs8',\n binaryKey,\n {\n name: 'RSASSA-PKCS1-v1_5',\n hash: 'SHA-256'\n },\n false,\n ['sign']\n );\n }\n \n /**\n * Base64 URL encode (without padding)\n * \n * @private\n * @param {string|ArrayBuffer} input - Data to encode\n * @returns {string} Base64 URL encoded string\n */\n _base64UrlEncode(input) {\n const buffer = typeof input === 'string' \n ? Buffer.from(input, 'utf-8')\n : Buffer.from(input);\n \n return buffer\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n }\n}\n\n/**\n * Convenience function to get a token directly (no caching)\n * Handles both service accounts and pre-existing OAuth2 tokens\n * \n * @param {string|object} credentialInput - Service account or OAuth2 token\n * @param {object} options - Optional configuration\n * @param {string} options.scope - OAuth2 scope (default: cloud-platform)\n * @returns {Promise<string>} Access token\n * \n * @example\n * // From service account\n * const sa = { client_email: '...', private_key: '...' };\n * const token = await getGoogleOAuth2Token(sa);\n * \n * // From OAuth2 token (pass-through)\n * const token = await getGoogleOAuth2Token('ya29.a0...');\n */\nexport async function getGoogleOAuth2Token(credentialInput, options = {}) {\n const parsed = parseGoogleCredentials(credentialInput);\n \n // If already a token (string), return it\n if (typeof parsed === 'string') {\n return parsed;\n }\n \n // Generate token from service account\n const manager = new GoogleTokenManager(parsed, options);\n return manager.getToken();\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses and normalizes Google Service Account credentials.
|
|
3
|
+
* Accepts:
|
|
4
|
+
* - Service account JSON string
|
|
5
|
+
* - Base64-encoded service account JSON string
|
|
6
|
+
* - JavaScript object { client_email, private_key }
|
|
7
|
+
* - Direct OAuth2 token string (starts with ya29.)
|
|
8
|
+
*
|
|
9
|
+
* @param {string|object} input - Service account as JSON string, base64, object, or OAuth2 token
|
|
10
|
+
* @returns {string|object} OAuth2 token string (if input is token) or service account object
|
|
11
|
+
* @throws {Error} If input is invalid or missing required fields
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // From JSON string
|
|
15
|
+
* const sa = parseGoogleCredentials('{"client_email":"...","private_key":"..."}');
|
|
16
|
+
* // Returns: { client_email, private_key, ... }
|
|
17
|
+
*
|
|
18
|
+
* // From base64
|
|
19
|
+
* const sa = parseGoogleCredentials('eyJjbGllbnRfZW1haWwiOi4uLn0=');
|
|
20
|
+
* // Returns: { client_email, private_key, ... }
|
|
21
|
+
*
|
|
22
|
+
* // From object
|
|
23
|
+
* const sa = parseGoogleCredentials({ client_email: '...', private_key: '...' });
|
|
24
|
+
* // Returns: { client_email, private_key, ... }
|
|
25
|
+
*
|
|
26
|
+
* // From OAuth2 token (pass-through)
|
|
27
|
+
* const token = parseGoogleCredentials('ya29.a0...');
|
|
28
|
+
* // Returns: 'ya29.a0...'
|
|
29
|
+
*/
|
|
30
|
+
declare function parseGoogleCredentials(input: string | object): string | object;
|
|
31
|
+
/**
|
|
32
|
+
* Validate service account has required fields
|
|
33
|
+
*
|
|
34
|
+
* @param {object} sa - Service account object
|
|
35
|
+
* @returns {boolean} True if valid
|
|
36
|
+
* @throws {Error} If invalid
|
|
37
|
+
*/
|
|
38
|
+
declare function validateServiceAccount(sa: object): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Convenience function to get a token directly (no caching)
|
|
41
|
+
* Handles both service accounts and pre-existing OAuth2 tokens
|
|
42
|
+
*
|
|
43
|
+
* @param {string|object} credentialInput - Service account or OAuth2 token
|
|
44
|
+
* @param {object} options - Optional configuration
|
|
45
|
+
* @param {string} options.scope - OAuth2 scope (default: cloud-platform)
|
|
46
|
+
* @returns {Promise<string>} Access token
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // From service account
|
|
50
|
+
* const sa = { client_email: '...', private_key: '...' };
|
|
51
|
+
* const token = await getGoogleOAuth2Token(sa);
|
|
52
|
+
*
|
|
53
|
+
* // From OAuth2 token (pass-through)
|
|
54
|
+
* const token = await getGoogleOAuth2Token('ya29.a0...');
|
|
55
|
+
*/
|
|
56
|
+
declare function getGoogleOAuth2Token(credentialInput: string | object, options?: {
|
|
57
|
+
scope: string;
|
|
58
|
+
}): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Google OAuth2 Token Manager
|
|
61
|
+
*
|
|
62
|
+
* Handles token generation, caching, and automatic refresh for
|
|
63
|
+
* Google Cloud service accounts. Tokens are cached and automatically
|
|
64
|
+
* refreshed when they expire (with a 5-minute safety buffer).
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const sa = parseGoogleCredentials(credentials);
|
|
68
|
+
* const tokenManager = new GoogleTokenManager(sa);
|
|
69
|
+
*
|
|
70
|
+
* // Get token (cached or fresh)
|
|
71
|
+
* const token = await tokenManager.getToken();
|
|
72
|
+
*
|
|
73
|
+
* // Force refresh
|
|
74
|
+
* tokenManager.invalidate();
|
|
75
|
+
* const newToken = await tokenManager.getToken();
|
|
76
|
+
*/
|
|
77
|
+
declare class GoogleTokenManager {
|
|
78
|
+
/**
|
|
79
|
+
* @param {object} serviceAccount - Parsed service account with client_email and private_key
|
|
80
|
+
* @param {object} options - Optional configuration
|
|
81
|
+
* @param {string} options.scope - OAuth2 scope (default: cloud-platform)
|
|
82
|
+
* @param {number} options.tokenLifetime - Token lifetime in seconds (default: 3600)
|
|
83
|
+
*/
|
|
84
|
+
constructor(serviceAccount: object, options?: {
|
|
85
|
+
scope: string;
|
|
86
|
+
tokenLifetime: number;
|
|
87
|
+
});
|
|
88
|
+
clientEmail: any;
|
|
89
|
+
privateKey: any;
|
|
90
|
+
projectId: any;
|
|
91
|
+
scope: string;
|
|
92
|
+
tokenLifetime: number;
|
|
93
|
+
_tokenCache: string;
|
|
94
|
+
_expiresAt: number;
|
|
95
|
+
/**
|
|
96
|
+
* Get a valid access token (cached or fresh)
|
|
97
|
+
*
|
|
98
|
+
* @returns {Promise<string>} OAuth2 access token
|
|
99
|
+
*/
|
|
100
|
+
getToken(): Promise<string>;
|
|
101
|
+
/**
|
|
102
|
+
* Clear cached token (force refresh on next getToken call)
|
|
103
|
+
*/
|
|
104
|
+
invalidate(): void;
|
|
105
|
+
/**
|
|
106
|
+
* Check if cached token is still valid
|
|
107
|
+
*
|
|
108
|
+
* @returns {boolean} True if token is valid
|
|
109
|
+
*/
|
|
110
|
+
isValid(): boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Get time until token expires (in seconds)
|
|
113
|
+
*
|
|
114
|
+
* @returns {number} Seconds until expiration (0 if no token or expired)
|
|
115
|
+
*/
|
|
116
|
+
getTimeToExpiry(): number;
|
|
117
|
+
/**
|
|
118
|
+
* Generate OAuth2 token via JWT flow
|
|
119
|
+
*
|
|
120
|
+
* @private
|
|
121
|
+
* @returns {Promise<string>} Access token
|
|
122
|
+
*/
|
|
123
|
+
private _generateToken;
|
|
124
|
+
/**
|
|
125
|
+
* Sign JWT using service account private key
|
|
126
|
+
*
|
|
127
|
+
* @private
|
|
128
|
+
* @param {object} header - JWT header
|
|
129
|
+
* @param {object} payload - JWT payload
|
|
130
|
+
* @returns {Promise<string>} Signed JWT
|
|
131
|
+
*/
|
|
132
|
+
private _signJWT;
|
|
133
|
+
/**
|
|
134
|
+
* Import PEM private key for signing
|
|
135
|
+
*
|
|
136
|
+
* @private
|
|
137
|
+
* @param {string} pemKey - PEM formatted private key
|
|
138
|
+
* @returns {Promise<CryptoKey>} Imported key
|
|
139
|
+
*/
|
|
140
|
+
private _importPrivateKey;
|
|
141
|
+
/**
|
|
142
|
+
* Base64 URL encode (without padding)
|
|
143
|
+
*
|
|
144
|
+
* @private
|
|
145
|
+
* @param {string|ArrayBuffer} input - Data to encode
|
|
146
|
+
* @returns {string} Base64 URL encoded string
|
|
147
|
+
*/
|
|
148
|
+
private _base64UrlEncode;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export { GoogleTokenManager, getGoogleOAuth2Token, parseGoogleCredentials, validateServiceAccount };
|