@pierre/storage 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -11
- package/dist/index.cjs +2 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -9
- package/dist/index.d.ts +2 -9
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +3 -5
- package/src/types.ts +2 -9
package/README.md
CHANGED
|
@@ -77,12 +77,13 @@ const repo = await store.createRepo();
|
|
|
77
77
|
// or
|
|
78
78
|
const repo = await store.findOne({ id: 'existing-repo-id' });
|
|
79
79
|
|
|
80
|
-
// Get file content
|
|
81
|
-
const
|
|
80
|
+
// Get file content (streaming)
|
|
81
|
+
const resp = await repo.getFileStream({
|
|
82
82
|
path: 'README.md',
|
|
83
83
|
ref: 'main', // optional, defaults to default branch
|
|
84
84
|
});
|
|
85
|
-
|
|
85
|
+
const text = await resp.text();
|
|
86
|
+
console.log(text);
|
|
86
87
|
|
|
87
88
|
// List all files in the repository
|
|
88
89
|
const files = await repo.listFiles({
|
|
@@ -153,7 +154,8 @@ interface FindOneOptions {
|
|
|
153
154
|
interface Repo {
|
|
154
155
|
id: string;
|
|
155
156
|
getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
|
|
156
|
-
|
|
157
|
+
|
|
158
|
+
getFileStream(options: GetFileOptions): Promise<Response>;
|
|
157
159
|
listFiles(options?: ListFilesOptions): Promise<ListFilesResponse>;
|
|
158
160
|
listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse>;
|
|
159
161
|
listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse>;
|
|
@@ -172,13 +174,7 @@ interface GetFileOptions {
|
|
|
172
174
|
ref?: string; // Branch, tag, or commit SHA
|
|
173
175
|
}
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
path: string;
|
|
177
|
-
ref: string;
|
|
178
|
-
content: string;
|
|
179
|
-
size: number;
|
|
180
|
-
is_binary: boolean;
|
|
181
|
-
}
|
|
177
|
+
// getFileStream() returns a standard Fetch Response for streaming bytes
|
|
182
178
|
|
|
183
179
|
interface ListFilesOptions {
|
|
184
180
|
ref?: string; // Branch, tag, or commit SHA
|
package/dist/index.cjs
CHANGED
|
@@ -266,7 +266,7 @@ var RepoImpl = class {
|
|
|
266
266
|
url.password = await this.generateJWT(this.id, urlOptions);
|
|
267
267
|
return url.toString();
|
|
268
268
|
}
|
|
269
|
-
async
|
|
269
|
+
async getFileStream(options) {
|
|
270
270
|
const jwt = await this.generateJWT(this.id, {
|
|
271
271
|
permissions: ["git:read"],
|
|
272
272
|
ttl: options?.ttl ?? 1 * 60 * 60
|
|
@@ -278,8 +278,7 @@ var RepoImpl = class {
|
|
|
278
278
|
if (options.ref) {
|
|
279
279
|
params.ref = options.ref;
|
|
280
280
|
}
|
|
281
|
-
|
|
282
|
-
return await response.json();
|
|
281
|
+
return this.api.get({ path: "repos/file", params }, jwt);
|
|
283
282
|
}
|
|
284
283
|
async listFiles(options) {
|
|
285
284
|
const jwt = await this.generateJWT(this.id, {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/fetch.ts","../src/util.ts","../src/webhook.ts","../src/index.ts"],"names":["API_BASE_URL","crypto","snakecaseKeys","importPKCS8","SignJWT"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ValidAPIVersion, ValidMethod, ValidPath } from './types';\n\ninterface RequestOptions {\n\tallowedStatus?: number[];\n}\n\nexport class ApiFetcher {\n\tconstructor(\n\t\tprivate readonly API_BASE_URL: string,\n\t\tprivate readonly version: ValidAPIVersion,\n\t) {\n\t\tconsole.log('api fetcher created', API_BASE_URL, version);\n\t}\n\n\tprivate getBaseUrl() {\n\t\treturn `${this.API_BASE_URL}/api/v${this.version}`;\n\t}\n\n\tprivate getRequestUrl(path: ValidPath) {\n\t\tif (typeof path === 'string') {\n\t\t\treturn `${this.getBaseUrl()}/${path}`;\n\t\t} else if (path.params) {\n\t\t\tconst paramStr = new URLSearchParams(path.params).toString();\n\t\t\treturn `${this.getBaseUrl()}/${path.path}${paramStr ? `?${paramStr}` : ''}`;\n\t\t} else {\n\t\t\treturn `${this.getBaseUrl()}/${path.path}`;\n\t\t}\n\t}\n\n\tprivate async fetch(path: ValidPath, method: ValidMethod, jwt: string, options?: RequestOptions) {\n\t\tconst requestUrl = this.getRequestUrl(path);\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${jwt}`,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t};\n\n\t\tif (method !== 'GET' && typeof path !== 'string' && path.body) {\n\t\t\trequestOptions.body = JSON.stringify(path.body);\n\t\t}\n\n\t\tconst response = await fetch(requestUrl, requestOptions);\n\n\t\tif (!response.ok) {\n\t\t\tconst allowed = options?.allowedStatus ?? [];\n\t\t\tif (!allowed.includes(response.status)) {\n\t\t\t\tthrow new Error(`Failed to fetch ${method} ${requestUrl}: ${response.statusText}`);\n\t\t\t}\n\t\t}\n\t\treturn response;\n\t}\n\n\tasync get(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'GET', jwt, options);\n\t}\n\n\tasync post(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'POST', jwt, options);\n\t}\n\n\tasync put(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'PUT', jwt, options);\n\t}\n\n\tasync delete(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'DELETE', jwt, options);\n\t}\n}\n","export function timingSafeEqual(a: string | Uint8Array, b: string | Uint8Array): boolean {\n\tconst bufferA = typeof a === 'string' ? new TextEncoder().encode(a) : a;\n\tconst bufferB = typeof b === 'string' ? new TextEncoder().encode(b) : b;\n\n\tif (bufferA.length !== bufferB.length) return false;\n\n\tlet result = 0;\n\tfor (let i = 0; i < bufferA.length; i++) {\n\t\tresult |= bufferA[i] ^ bufferB[i];\n\t}\n\treturn result === 0;\n}\n\nexport async function getEnvironmentCrypto() {\n\tif (!globalThis.crypto) {\n\t\tconst { webcrypto } = await import('node:crypto');\n\t\treturn webcrypto;\n\t}\n\treturn globalThis.crypto;\n}\n\nexport async function createHmac(algorithm: string, secret: string, data: string): Promise<string> {\n\tif (algorithm !== 'sha256') {\n\t\tthrow new Error('Only sha256 algorithm is supported');\n\t}\n\tif (!secret || secret.length === 0) {\n\t\tthrow new Error('Secret is required');\n\t}\n\n\tconst crypto = await getEnvironmentCrypto();\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tencoder.encode(secret),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\n\tconst signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));\n\treturn Array.from(new Uint8Array(signature))\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n\n// Keep the legacy async function for backward compatibility\nexport async function createHmacAsync(secret: string, data: string): Promise<string> {\n\tconst crypto = await getEnvironmentCrypto();\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tencoder.encode(secret),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\n\tconst signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));\n\treturn Array.from(new Uint8Array(signature))\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n","/**\n * Webhook validation utilities for Pierre Git Storage\n */\n\nimport type {\n\tParsedWebhookSignature,\n\tWebhookEventPayload,\n\tWebhookValidationOptions,\n\tWebhookValidationResult,\n} from './types';\n\nimport { createHmac, timingSafeEqual } from './util';\n\nconst DEFAULT_MAX_AGE_SECONDS = 300; // 5 minutes\n\n/**\n * Parse the X-Pierre-Signature header\n * Format: t=<timestamp>,sha256=<signature>\n */\nexport function parseSignatureHeader(header: string): ParsedWebhookSignature | null {\n\tif (!header || typeof header !== 'string') {\n\t\treturn null;\n\t}\n\n\tlet timestamp = '';\n\tlet signature = '';\n\n\t// Split by comma and parse each element\n\tconst elements = header.split(',');\n\tfor (const element of elements) {\n\t\tconst trimmedElement = element.trim();\n\t\tconst parts = trimmedElement.split('=', 2);\n\t\tif (parts.length !== 2) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst [key, value] = parts;\n\t\tswitch (key) {\n\t\t\tcase 't':\n\t\t\t\ttimestamp = value;\n\t\t\t\tbreak;\n\t\t\tcase 'sha256':\n\t\t\t\tsignature = value;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!timestamp || !signature) {\n\t\treturn null;\n\t}\n\n\treturn { timestamp, signature };\n}\n\n/**\n * Validate a webhook signature and timestamp\n *\n * @param payload - The raw webhook payload (request body)\n * @param signatureHeader - The X-Pierre-Signature header value\n * @param secret - The webhook secret for HMAC verification\n * @param options - Validation options\n * @returns Validation result with details\n *\n * @example\n * ```typescript\n * const result = await validateWebhookSignature(\n * requestBody,\n * request.headers['x-pierre-signature'],\n * webhookSecret\n * );\n *\n * if (!result.valid) {\n * console.error('Invalid webhook:', result.error);\n * return;\n * }\n * ```\n */\nexport async function validateWebhookSignature(\n\tpayload: string | Buffer,\n\tsignatureHeader: string,\n\tsecret: string,\n\toptions: WebhookValidationOptions = {},\n): Promise<WebhookValidationResult> {\n\tif (!secret || secret.length === 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Empty secret is not allowed',\n\t\t};\n\t}\n\n\t// Parse the signature header\n\tconst parsed = parseSignatureHeader(signatureHeader);\n\tif (!parsed) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature header format',\n\t\t};\n\t}\n\n\t// Parse timestamp\n\tconst timestamp = Number.parseInt(parsed.timestamp, 10);\n\tif (isNaN(timestamp)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid timestamp in signature',\n\t\t};\n\t}\n\n\t// Validate timestamp age (prevent replay attacks)\n\tconst maxAge = options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;\n\tif (maxAge > 0) {\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst age = now - timestamp;\n\n\t\tif (age > maxAge) {\n\t\t\treturn {\n\t\t\t\tvalid: false,\n\t\t\t\terror: `Webhook timestamp too old (${age} seconds)`,\n\t\t\t\ttimestamp,\n\t\t\t};\n\t\t}\n\n\t\t// Also reject timestamps from the future (clock skew tolerance of 60 seconds)\n\t\tif (age < -60) {\n\t\t\treturn {\n\t\t\t\tvalid: false,\n\t\t\t\terror: 'Webhook timestamp is in the future',\n\t\t\t\ttimestamp,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Convert payload to string if it's a Buffer\n\tconst payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n\n\t// Compute expected signature\n\t// Format: HMAC-SHA256(secret, timestamp + \".\" + payload)\n\tconst signedData = `${parsed.timestamp}.${payloadStr}`;\n\tconst expectedSignature = await createHmac('sha256', secret, signedData);\n\n\t// Compare signatures using constant-time comparison\n\tconst expectedBuffer = Buffer.from(expectedSignature);\n\tconst actualBuffer = Buffer.from(parsed.signature);\n\n\t// Ensure both buffers are the same length for timing-safe comparison\n\tif (expectedBuffer.length !== actualBuffer.length) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature',\n\t\t\ttimestamp,\n\t\t};\n\t}\n\n\tconst signaturesMatch = timingSafeEqual(expectedBuffer, actualBuffer);\n\tif (!signaturesMatch) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature',\n\t\t\ttimestamp,\n\t\t};\n\t}\n\n\treturn {\n\t\tvalid: true,\n\t\ttimestamp,\n\t};\n}\n\n/**\n * Validate a webhook request\n *\n * This is a convenience function that validates the signature and parses the payload.\n *\n * @param payload - The raw webhook payload (request body)\n * @param headers - The request headers (must include x-pierre-signature and x-pierre-event)\n * @param secret - The webhook secret for HMAC verification\n * @param options - Validation options\n * @returns The parsed webhook payload if valid, or validation error\n *\n * @example\n * ```typescript\n * const result = await validateWebhook(\n * request.body,\n * request.headers,\n * process.env.WEBHOOK_SECRET\n * );\n *\n * if (!result.valid) {\n * return new Response('Invalid webhook', { status: 401 });\n * }\n *\n * // Type-safe access to the webhook payload\n * console.log('Push event:', result.payload);\n * ```\n */\nexport async function validateWebhook(\n\tpayload: string | Buffer,\n\theaders: Record<string, string | string[] | undefined>,\n\tsecret: string,\n\toptions: WebhookValidationOptions = {},\n): Promise<WebhookValidationResult & { payload?: WebhookEventPayload }> {\n\t// Get signature header\n\tconst signatureHeader = headers['x-pierre-signature'] || headers['X-Pierre-Signature'];\n\tif (!signatureHeader || Array.isArray(signatureHeader)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Missing or invalid X-Pierre-Signature header',\n\t\t};\n\t}\n\n\t// Get event type header\n\tconst eventType = headers['x-pierre-event'] || headers['X-Pierre-Event'];\n\tif (!eventType || Array.isArray(eventType)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Missing or invalid X-Pierre-Event header',\n\t\t};\n\t}\n\n\t// Validate signature\n\tconst validationResult = await validateWebhookSignature(\n\t\tpayload,\n\t\tsignatureHeader,\n\t\tsecret,\n\t\toptions,\n\t);\n\n\tif (!validationResult.valid) {\n\t\treturn validationResult;\n\t}\n\n\t// Parse payload\n\tconst payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n\tlet parsedPayload: WebhookEventPayload;\n\ttry {\n\t\tparsedPayload = JSON.parse(payloadStr);\n\t} catch {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid JSON payload',\n\t\t\ttimestamp: validationResult.timestamp,\n\t\t};\n\t}\n\n\treturn {\n\t\tvalid: true,\n\t\teventType,\n\t\ttimestamp: validationResult.timestamp,\n\t\tpayload: parsedPayload,\n\t};\n}\n","/**\n * Pierre Git Storage SDK\n *\n * A TypeScript SDK for interacting with Pierre's git storage system\n */\n\nimport { importPKCS8, SignJWT } from 'jose';\nimport snakecaseKeys from 'snakecase-keys';\nimport { ApiFetcher } from './fetch';\nimport type {\n\tCreateRepoOptions,\n\tFindOneOptions,\n\tGetBranchDiffOptions,\n\tGetBranchDiffResponse,\n\tGetCommitDiffOptions,\n\tGetCommitDiffResponse,\n\tGetCommitOptions,\n\tGetCommitResponse,\n\tGetFileOptions,\n\tGetFileResponse,\n\tGetRemoteURLOptions,\n\tGitStorageOptions,\n\tListBranchesOptions,\n\tListBranchesResponse,\n\tListCommitsOptions,\n\tListCommitsResponse,\n\tListFilesOptions,\n\tListFilesResponse,\n\tOverrideableGitStorageOptions,\n\tRepo,\n\tRepullOptions,\n\tValidAPIVersion,\n} from './types';\n\n/**\n * Type definitions for Pierre Git Storage SDK\n */\n\n// Import additional types from types.ts\nexport * from './types';\n\n// Export webhook validation utilities\nexport { parseSignatureHeader, validateWebhook, validateWebhookSignature } from './webhook';\n\n/**\n * Git Storage API\n */\n\ndeclare const __STORAGE_BASE_URL__: string;\ndeclare const __API_BASE_URL__: string;\n\nconst API_BASE_URL = __API_BASE_URL__;\nconst STORAGE_BASE_URL = __STORAGE_BASE_URL__;\nconst API_VERSION: ValidAPIVersion = 1;\n\nconst apiInstanceMap = new Map<string, ApiFetcher>();\n\nfunction getApiInstance(baseUrl: string, version: ValidAPIVersion) {\n\tif (!apiInstanceMap.has(`${baseUrl}--${version}`)) {\n\t\tapiInstanceMap.set(`${baseUrl}--${version}`, new ApiFetcher(baseUrl, version));\n\t}\n\treturn apiInstanceMap.get(`${baseUrl}--${version}`)!;\n}\n\n/**\n * Implementation of the Repo interface\n */\nclass RepoImpl implements Repo {\n\tprivate readonly api: ApiFetcher;\n\n\tconstructor(\n\t\tpublic readonly id: string,\n\t\tprivate readonly options: GitStorageOptions,\n\t\tprivate readonly generateJWT: (\n\t\t\trepoId: string,\n\t\t\toptions?: GetRemoteURLOptions,\n\t\t) => Promise<string>,\n\t) {\n\t\tthis.api = getApiInstance(\n\t\t\tthis.options.apiBaseUrl ?? API_BASE_URL,\n\t\t\tthis.options.apiVersion ?? API_VERSION,\n\t\t);\n\t}\n\n\tasync getRemoteURL(urlOptions?: GetRemoteURLOptions): Promise<string> {\n\t\tconst storageBaseUrl = this.options.storageBaseUrl ?? STORAGE_BASE_URL;\n\t\tconst url = new URL(`https://${this.options.name}.${storageBaseUrl}/${this.id}.git`);\n\t\turl.username = `t`;\n\t\turl.password = await this.generateJWT(this.id, urlOptions);\n\t\treturn url.toString();\n\t}\n\n\tasync getFile(options: GetFileOptions): Promise<GetFileResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tpath: options.path,\n\t\t};\n\n\t\tif (options.ref) {\n\t\t\tparams.ref = options.ref;\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/file', params }, jwt);\n\n\t\treturn (await response.json()) as GetFileResponse;\n\t}\n\n\tasync listFiles(options?: ListFilesOptions): Promise<ListFilesResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> | undefined = options?.ref\n\t\t\t? { ref: options.ref }\n\t\t\t: undefined;\n\t\tconst response = await this.api.get({ path: 'repos/files', params }, jwt);\n\n\t\treturn (await response.json()) as ListFilesResponse;\n\t}\n\n\tasync listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tlet params: Record<string, string> | undefined;\n\n\t\tif (options?.cursor || !options?.limit) {\n\t\t\tparams = {};\n\t\t\tif (options?.cursor) {\n\t\t\t\tparams.cursor = options.cursor;\n\t\t\t}\n\t\t\tif (typeof options?.limit == 'number') {\n\t\t\t\tparams.limit = options.limit.toString();\n\t\t\t}\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/branches', params }, jwt);\n\n\t\treturn (await response.json()) as ListBranchesResponse;\n\t}\n\n\tasync listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tlet params: Record<string, string> | undefined;\n\n\t\tif (options?.branch || options?.cursor || options?.limit) {\n\t\t\tparams = {};\n\t\t\tif (options?.branch) {\n\t\t\t\tparams.branch = options.branch;\n\t\t\t}\n\t\t\tif (options?.cursor) {\n\t\t\t\tparams.cursor = options.cursor;\n\t\t\t}\n\t\t\tif (typeof options?.limit == 'number') {\n\t\t\t\tparams.limit = options.limit.toString();\n\t\t\t}\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/commits', params }, jwt);\n\n\t\treturn (await response.json()) as ListCommitsResponse;\n\t}\n\n\tasync getBranchDiff(options: GetBranchDiffOptions): Promise<GetBranchDiffResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tbranch: options.branch,\n\t\t};\n\n\t\tif (options.base) {\n\t\t\tparams.base = options.base;\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/branches/diff', params }, jwt);\n\n\t\treturn (await response.json()) as GetBranchDiffResponse;\n\t}\n\n\tasync getCommitDiff(options: GetCommitDiffOptions): Promise<GetCommitDiffResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tsha: options.sha,\n\t\t};\n\n\t\tconst response = await this.api.get({ path: 'repos/diff', params }, jwt);\n\n\t\treturn (await response.json()) as GetCommitDiffResponse;\n\t}\n\n\tasync getCommit(options: GetCommitOptions): Promise<GetCommitResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\trepo: this.id,\n\t\t\tsha: options.sha,\n\t\t};\n\t\tconst response = await this.api.get({ path: 'commit', params }, jwt);\n\n\t\treturn (await response.json()) as GetCommitResponse;\n\t}\n\n\tasync repull(options: RepullOptions): Promise<void> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:write'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst body: Record<string, string> = {};\n\n\t\tif (options.ref) {\n\t\t\tbody.ref = options.ref;\n\t\t}\n\n\t\tconst response = await this.api.post({ path: 'repos/repull', body }, jwt);\n\n\t\tif (response.status !== 202) {\n\t\t\tthrow new Error(`Repull failed: ${response.status} ${await response.text()}`);\n\t\t}\n\n\t\treturn;\n\t}\n}\n\nexport class GitStorage {\n\tprivate static overrides: OverrideableGitStorageOptions = {};\n\tprivate options: GitStorageOptions;\n\tprivate api: ApiFetcher;\n\n\tconstructor(options: GitStorageOptions) {\n\t\tif (\n\t\t\t!options ||\n\t\t\toptions.name === undefined ||\n\t\t\toptions.key === undefined ||\n\t\t\toptions.name === null ||\n\t\t\toptions.key === null\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t'GitStorage requires a name and key. Please check your configuration and try again.',\n\t\t\t);\n\t\t}\n\n\t\tif (typeof options.name !== 'string' || options.name.trim() === '') {\n\t\t\tthrow new Error('GitStorage name must be a non-empty string.');\n\t\t}\n\n\t\tif (typeof options.key !== 'string' || options.key.trim() === '') {\n\t\t\tthrow new Error('GitStorage key must be a non-empty string.');\n\t\t}\n\n\t\tconst resolvedApiBaseUrl =\n\t\t\toptions.apiBaseUrl ?? GitStorage.overrides.apiBaseUrl ?? API_BASE_URL;\n\t\tconst resolvedApiVersion = options.apiVersion ?? GitStorage.overrides.apiVersion ?? API_VERSION;\n\t\tconst resolvedStorageBaseUrl =\n\t\t\toptions.storageBaseUrl ?? GitStorage.overrides.storageBaseUrl ?? STORAGE_BASE_URL;\n\n\t\tthis.api = getApiInstance(resolvedApiBaseUrl, resolvedApiVersion);\n\n\t\tthis.options = {\n\t\t\tkey: options.key,\n\t\t\tname: options.name,\n\t\t\tapiBaseUrl: resolvedApiBaseUrl,\n\t\t\tapiVersion: resolvedApiVersion,\n\t\t\tstorageBaseUrl: resolvedStorageBaseUrl,\n\t\t};\n\t}\n\n\tstatic override(options: OverrideableGitStorageOptions): void {\n\t\tthis.overrides = Object.assign({}, this.overrides, options);\n\t}\n\n\t/**\n\t * Create a new repository\n\t * @returns The created repository\n\t */\n\tasync createRepo(options?: CreateRepoOptions): Promise<Repo> {\n\t\tconst repoId = options?.id || crypto.randomUUID();\n\n\t\tconst jwt = await this.generateJWT(repoId, {\n\t\t\tpermissions: ['repo:write'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst baseRepoOptions = options?.baseRepo\n\t\t\t? {\n\t\t\t\t\tprovider: 'github',\n\t\t\t\t\t...snakecaseKeys(options.baseRepo as unknown as Record<string, unknown>),\n\t\t\t\t}\n\t\t\t: null;\n\n\t\t// Default defaultBranch to 'main' if not provided\n\t\tconst defaultBranch = options?.defaultBranch ?? 'main';\n\n\t\tconst createRepoPath =\n\t\t\tbaseRepoOptions || defaultBranch\n\t\t\t\t? {\n\t\t\t\t\t\tpath: 'repos',\n\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t...(baseRepoOptions && { base_repo: baseRepoOptions }),\n\t\t\t\t\t\t\tdefault_branch: defaultBranch,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: 'repos';\n\n\t\t// Allow 409 so we can map it to a clearer error message\n\t\tconst resp = await this.api.post(createRepoPath, jwt, { allowedStatus: [409] });\n\t\tif (resp.status === 409) {\n\t\t\tthrow new Error('Repository already exists');\n\t\t}\n\n\t\treturn new RepoImpl(repoId, this.options, this.generateJWT.bind(this));\n\t}\n\n\t/**\n\t * Find a repository by ID\n\t * @param options The search options\n\t * @returns The found repository\n\t */\n\tasync findOne(options: FindOneOptions): Promise<Repo | null> {\n\t\tconst jwt = await this.generateJWT(options.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: 1 * 60 * 60,\n\t\t});\n\n\t\t// Allow 404 to indicate \"not found\" without throwing\n\t\tconst resp = await this.api.get('repo', jwt, { allowedStatus: [404] });\n\t\tif (resp.status === 404) {\n\t\t\treturn null;\n\t\t}\n\t\t// On 200, we could validate response, but RepoImpl only needs the repo URL/id\n\t\t// const body = await resp.json(); // not required for now\n\t\treturn new RepoImpl(options.id, this.options, this.generateJWT.bind(this));\n\t}\n\n\t/**\n\t * Get the current configuration\n\t * @returns The client configuration\n\t */\n\tgetConfig(): GitStorageOptions {\n\t\treturn { ...this.options };\n\t}\n\n\t/**\n\t * Generate a JWT token for git storage URL authentication\n\t * @private\n\t */\n\tprivate async generateJWT(repoId: string, options?: GetRemoteURLOptions): Promise<string> {\n\t\t// Default permissions and TTL\n\t\tconst permissions = options?.permissions || ['git:write', 'git:read'];\n\t\tconst ttl = options?.ttl || 365 * 24 * 60 * 60; // 1 year in seconds\n\n\t\t// Create the JWT payload\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst payload = {\n\t\t\tiss: this.options.name,\n\t\t\tsub: '@pierre/storage',\n\t\t\trepo: repoId,\n\t\t\tscopes: permissions,\n\t\t\tiat: now,\n\t\t\texp: now + ttl,\n\t\t};\n\n\t\t// Sign the JWT with the key as the secret\n\t\t// Using HS256 for symmetric signing with the key\n\t\tconst key = await importPKCS8(this.options.key, 'ES256');\n\t\t// Sign the JWT with the key as the secret\n\t\tconst jwt = await new SignJWT(payload)\n\t\t\t.setProtectedHeader({ alg: 'ES256', typ: 'JWT' })\n\t\t\t.sign(key);\n\n\t\treturn jwt;\n\t}\n}\n\n// Export a default client factory\nexport function createClient(options: GitStorageOptions): GitStorage {\n\treturn new GitStorage(options);\n}\n\n// Type alias for backward compatibility\nexport type StorageOptions = GitStorageOptions;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/fetch.ts","../src/util.ts","../src/webhook.ts","../src/index.ts"],"names":["API_BASE_URL","crypto","snakecaseKeys","importPKCS8","SignJWT"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ValidAPIVersion, ValidMethod, ValidPath } from './types';\n\ninterface RequestOptions {\n\tallowedStatus?: number[];\n}\n\nexport class ApiFetcher {\n\tconstructor(\n\t\tprivate readonly API_BASE_URL: string,\n\t\tprivate readonly version: ValidAPIVersion,\n\t) {\n\t\tconsole.log('api fetcher created', API_BASE_URL, version);\n\t}\n\n\tprivate getBaseUrl() {\n\t\treturn `${this.API_BASE_URL}/api/v${this.version}`;\n\t}\n\n\tprivate getRequestUrl(path: ValidPath) {\n\t\tif (typeof path === 'string') {\n\t\t\treturn `${this.getBaseUrl()}/${path}`;\n\t\t} else if (path.params) {\n\t\t\tconst paramStr = new URLSearchParams(path.params).toString();\n\t\t\treturn `${this.getBaseUrl()}/${path.path}${paramStr ? `?${paramStr}` : ''}`;\n\t\t} else {\n\t\t\treturn `${this.getBaseUrl()}/${path.path}`;\n\t\t}\n\t}\n\n\tprivate async fetch(path: ValidPath, method: ValidMethod, jwt: string, options?: RequestOptions) {\n\t\tconst requestUrl = this.getRequestUrl(path);\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${jwt}`,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t};\n\n\t\tif (method !== 'GET' && typeof path !== 'string' && path.body) {\n\t\t\trequestOptions.body = JSON.stringify(path.body);\n\t\t}\n\n\t\tconst response = await fetch(requestUrl, requestOptions);\n\n\t\tif (!response.ok) {\n\t\t\tconst allowed = options?.allowedStatus ?? [];\n\t\t\tif (!allowed.includes(response.status)) {\n\t\t\t\tthrow new Error(`Failed to fetch ${method} ${requestUrl}: ${response.statusText}`);\n\t\t\t}\n\t\t}\n\t\treturn response;\n\t}\n\n\tasync get(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'GET', jwt, options);\n\t}\n\n\tasync post(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'POST', jwt, options);\n\t}\n\n\tasync put(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'PUT', jwt, options);\n\t}\n\n\tasync delete(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'DELETE', jwt, options);\n\t}\n}\n","export function timingSafeEqual(a: string | Uint8Array, b: string | Uint8Array): boolean {\n\tconst bufferA = typeof a === 'string' ? new TextEncoder().encode(a) : a;\n\tconst bufferB = typeof b === 'string' ? new TextEncoder().encode(b) : b;\n\n\tif (bufferA.length !== bufferB.length) return false;\n\n\tlet result = 0;\n\tfor (let i = 0; i < bufferA.length; i++) {\n\t\tresult |= bufferA[i] ^ bufferB[i];\n\t}\n\treturn result === 0;\n}\n\nexport async function getEnvironmentCrypto() {\n\tif (!globalThis.crypto) {\n\t\tconst { webcrypto } = await import('node:crypto');\n\t\treturn webcrypto;\n\t}\n\treturn globalThis.crypto;\n}\n\nexport async function createHmac(algorithm: string, secret: string, data: string): Promise<string> {\n\tif (algorithm !== 'sha256') {\n\t\tthrow new Error('Only sha256 algorithm is supported');\n\t}\n\tif (!secret || secret.length === 0) {\n\t\tthrow new Error('Secret is required');\n\t}\n\n\tconst crypto = await getEnvironmentCrypto();\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tencoder.encode(secret),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\n\tconst signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));\n\treturn Array.from(new Uint8Array(signature))\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n\n// Keep the legacy async function for backward compatibility\nexport async function createHmacAsync(secret: string, data: string): Promise<string> {\n\tconst crypto = await getEnvironmentCrypto();\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tencoder.encode(secret),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\n\tconst signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));\n\treturn Array.from(new Uint8Array(signature))\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n","/**\n * Webhook validation utilities for Pierre Git Storage\n */\n\nimport type {\n\tParsedWebhookSignature,\n\tWebhookEventPayload,\n\tWebhookValidationOptions,\n\tWebhookValidationResult,\n} from './types';\n\nimport { createHmac, timingSafeEqual } from './util';\n\nconst DEFAULT_MAX_AGE_SECONDS = 300; // 5 minutes\n\n/**\n * Parse the X-Pierre-Signature header\n * Format: t=<timestamp>,sha256=<signature>\n */\nexport function parseSignatureHeader(header: string): ParsedWebhookSignature | null {\n\tif (!header || typeof header !== 'string') {\n\t\treturn null;\n\t}\n\n\tlet timestamp = '';\n\tlet signature = '';\n\n\t// Split by comma and parse each element\n\tconst elements = header.split(',');\n\tfor (const element of elements) {\n\t\tconst trimmedElement = element.trim();\n\t\tconst parts = trimmedElement.split('=', 2);\n\t\tif (parts.length !== 2) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst [key, value] = parts;\n\t\tswitch (key) {\n\t\t\tcase 't':\n\t\t\t\ttimestamp = value;\n\t\t\t\tbreak;\n\t\t\tcase 'sha256':\n\t\t\t\tsignature = value;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!timestamp || !signature) {\n\t\treturn null;\n\t}\n\n\treturn { timestamp, signature };\n}\n\n/**\n * Validate a webhook signature and timestamp\n *\n * @param payload - The raw webhook payload (request body)\n * @param signatureHeader - The X-Pierre-Signature header value\n * @param secret - The webhook secret for HMAC verification\n * @param options - Validation options\n * @returns Validation result with details\n *\n * @example\n * ```typescript\n * const result = await validateWebhookSignature(\n * requestBody,\n * request.headers['x-pierre-signature'],\n * webhookSecret\n * );\n *\n * if (!result.valid) {\n * console.error('Invalid webhook:', result.error);\n * return;\n * }\n * ```\n */\nexport async function validateWebhookSignature(\n\tpayload: string | Buffer,\n\tsignatureHeader: string,\n\tsecret: string,\n\toptions: WebhookValidationOptions = {},\n): Promise<WebhookValidationResult> {\n\tif (!secret || secret.length === 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Empty secret is not allowed',\n\t\t};\n\t}\n\n\t// Parse the signature header\n\tconst parsed = parseSignatureHeader(signatureHeader);\n\tif (!parsed) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature header format',\n\t\t};\n\t}\n\n\t// Parse timestamp\n\tconst timestamp = Number.parseInt(parsed.timestamp, 10);\n\tif (isNaN(timestamp)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid timestamp in signature',\n\t\t};\n\t}\n\n\t// Validate timestamp age (prevent replay attacks)\n\tconst maxAge = options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;\n\tif (maxAge > 0) {\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst age = now - timestamp;\n\n\t\tif (age > maxAge) {\n\t\t\treturn {\n\t\t\t\tvalid: false,\n\t\t\t\terror: `Webhook timestamp too old (${age} seconds)`,\n\t\t\t\ttimestamp,\n\t\t\t};\n\t\t}\n\n\t\t// Also reject timestamps from the future (clock skew tolerance of 60 seconds)\n\t\tif (age < -60) {\n\t\t\treturn {\n\t\t\t\tvalid: false,\n\t\t\t\terror: 'Webhook timestamp is in the future',\n\t\t\t\ttimestamp,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Convert payload to string if it's a Buffer\n\tconst payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n\n\t// Compute expected signature\n\t// Format: HMAC-SHA256(secret, timestamp + \".\" + payload)\n\tconst signedData = `${parsed.timestamp}.${payloadStr}`;\n\tconst expectedSignature = await createHmac('sha256', secret, signedData);\n\n\t// Compare signatures using constant-time comparison\n\tconst expectedBuffer = Buffer.from(expectedSignature);\n\tconst actualBuffer = Buffer.from(parsed.signature);\n\n\t// Ensure both buffers are the same length for timing-safe comparison\n\tif (expectedBuffer.length !== actualBuffer.length) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature',\n\t\t\ttimestamp,\n\t\t};\n\t}\n\n\tconst signaturesMatch = timingSafeEqual(expectedBuffer, actualBuffer);\n\tif (!signaturesMatch) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature',\n\t\t\ttimestamp,\n\t\t};\n\t}\n\n\treturn {\n\t\tvalid: true,\n\t\ttimestamp,\n\t};\n}\n\n/**\n * Validate a webhook request\n *\n * This is a convenience function that validates the signature and parses the payload.\n *\n * @param payload - The raw webhook payload (request body)\n * @param headers - The request headers (must include x-pierre-signature and x-pierre-event)\n * @param secret - The webhook secret for HMAC verification\n * @param options - Validation options\n * @returns The parsed webhook payload if valid, or validation error\n *\n * @example\n * ```typescript\n * const result = await validateWebhook(\n * request.body,\n * request.headers,\n * process.env.WEBHOOK_SECRET\n * );\n *\n * if (!result.valid) {\n * return new Response('Invalid webhook', { status: 401 });\n * }\n *\n * // Type-safe access to the webhook payload\n * console.log('Push event:', result.payload);\n * ```\n */\nexport async function validateWebhook(\n\tpayload: string | Buffer,\n\theaders: Record<string, string | string[] | undefined>,\n\tsecret: string,\n\toptions: WebhookValidationOptions = {},\n): Promise<WebhookValidationResult & { payload?: WebhookEventPayload }> {\n\t// Get signature header\n\tconst signatureHeader = headers['x-pierre-signature'] || headers['X-Pierre-Signature'];\n\tif (!signatureHeader || Array.isArray(signatureHeader)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Missing or invalid X-Pierre-Signature header',\n\t\t};\n\t}\n\n\t// Get event type header\n\tconst eventType = headers['x-pierre-event'] || headers['X-Pierre-Event'];\n\tif (!eventType || Array.isArray(eventType)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Missing or invalid X-Pierre-Event header',\n\t\t};\n\t}\n\n\t// Validate signature\n\tconst validationResult = await validateWebhookSignature(\n\t\tpayload,\n\t\tsignatureHeader,\n\t\tsecret,\n\t\toptions,\n\t);\n\n\tif (!validationResult.valid) {\n\t\treturn validationResult;\n\t}\n\n\t// Parse payload\n\tconst payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n\tlet parsedPayload: WebhookEventPayload;\n\ttry {\n\t\tparsedPayload = JSON.parse(payloadStr);\n\t} catch {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid JSON payload',\n\t\t\ttimestamp: validationResult.timestamp,\n\t\t};\n\t}\n\n\treturn {\n\t\tvalid: true,\n\t\teventType,\n\t\ttimestamp: validationResult.timestamp,\n\t\tpayload: parsedPayload,\n\t};\n}\n","/**\n * Pierre Git Storage SDK\n *\n * A TypeScript SDK for interacting with Pierre's git storage system\n */\n\nimport { importPKCS8, SignJWT } from 'jose';\nimport snakecaseKeys from 'snakecase-keys';\nimport { ApiFetcher } from './fetch';\nimport type {\n\tCreateRepoOptions,\n\tFindOneOptions,\n\tGetBranchDiffOptions,\n\tGetBranchDiffResponse,\n\tGetCommitDiffOptions,\n\tGetCommitDiffResponse,\n\tGetCommitOptions,\n\tGetCommitResponse,\n\tGetFileOptions,\n\tGetRemoteURLOptions,\n\tGitStorageOptions,\n\tListBranchesOptions,\n\tListBranchesResponse,\n\tListCommitsOptions,\n\tListCommitsResponse,\n\tListFilesOptions,\n\tListFilesResponse,\n\tOverrideableGitStorageOptions,\n\tRepo,\n\tRepullOptions,\n\tValidAPIVersion,\n} from './types';\n\n/**\n * Type definitions for Pierre Git Storage SDK\n */\n\n// Import additional types from types.ts\nexport * from './types';\n\n// Export webhook validation utilities\nexport { parseSignatureHeader, validateWebhook, validateWebhookSignature } from './webhook';\n\n/**\n * Git Storage API\n */\n\ndeclare const __STORAGE_BASE_URL__: string;\ndeclare const __API_BASE_URL__: string;\n\nconst API_BASE_URL = __API_BASE_URL__;\nconst STORAGE_BASE_URL = __STORAGE_BASE_URL__;\nconst API_VERSION: ValidAPIVersion = 1;\n\nconst apiInstanceMap = new Map<string, ApiFetcher>();\n\nfunction getApiInstance(baseUrl: string, version: ValidAPIVersion) {\n\tif (!apiInstanceMap.has(`${baseUrl}--${version}`)) {\n\t\tapiInstanceMap.set(`${baseUrl}--${version}`, new ApiFetcher(baseUrl, version));\n\t}\n\treturn apiInstanceMap.get(`${baseUrl}--${version}`)!;\n}\n\n/**\n * Implementation of the Repo interface\n */\nclass RepoImpl implements Repo {\n\tprivate readonly api: ApiFetcher;\n\n\tconstructor(\n\t\tpublic readonly id: string,\n\t\tprivate readonly options: GitStorageOptions,\n\t\tprivate readonly generateJWT: (\n\t\t\trepoId: string,\n\t\t\toptions?: GetRemoteURLOptions,\n\t\t) => Promise<string>,\n\t) {\n\t\tthis.api = getApiInstance(\n\t\t\tthis.options.apiBaseUrl ?? API_BASE_URL,\n\t\t\tthis.options.apiVersion ?? API_VERSION,\n\t\t);\n\t}\n\n\tasync getRemoteURL(urlOptions?: GetRemoteURLOptions): Promise<string> {\n\t\tconst storageBaseUrl = this.options.storageBaseUrl ?? STORAGE_BASE_URL;\n\t\tconst url = new URL(`https://${this.options.name}.${storageBaseUrl}/${this.id}.git`);\n\t\turl.username = `t`;\n\t\turl.password = await this.generateJWT(this.id, urlOptions);\n\t\treturn url.toString();\n\t}\n\n\tasync getFileStream(options: GetFileOptions): Promise<Response> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tpath: options.path,\n\t\t};\n\n\t\tif (options.ref) {\n\t\t\tparams.ref = options.ref;\n\t\t}\n\n\t\t// Return the raw fetch Response for streaming\n\t\treturn this.api.get({ path: 'repos/file', params }, jwt);\n\t}\n\n\tasync listFiles(options?: ListFilesOptions): Promise<ListFilesResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> | undefined = options?.ref\n\t\t\t? { ref: options.ref }\n\t\t\t: undefined;\n\t\tconst response = await this.api.get({ path: 'repos/files', params }, jwt);\n\n\t\treturn (await response.json()) as ListFilesResponse;\n\t}\n\n\tasync listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tlet params: Record<string, string> | undefined;\n\n\t\tif (options?.cursor || !options?.limit) {\n\t\t\tparams = {};\n\t\t\tif (options?.cursor) {\n\t\t\t\tparams.cursor = options.cursor;\n\t\t\t}\n\t\t\tif (typeof options?.limit == 'number') {\n\t\t\t\tparams.limit = options.limit.toString();\n\t\t\t}\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/branches', params }, jwt);\n\n\t\treturn (await response.json()) as ListBranchesResponse;\n\t}\n\n\tasync listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tlet params: Record<string, string> | undefined;\n\n\t\tif (options?.branch || options?.cursor || options?.limit) {\n\t\t\tparams = {};\n\t\t\tif (options?.branch) {\n\t\t\t\tparams.branch = options.branch;\n\t\t\t}\n\t\t\tif (options?.cursor) {\n\t\t\t\tparams.cursor = options.cursor;\n\t\t\t}\n\t\t\tif (typeof options?.limit == 'number') {\n\t\t\t\tparams.limit = options.limit.toString();\n\t\t\t}\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/commits', params }, jwt);\n\n\t\treturn (await response.json()) as ListCommitsResponse;\n\t}\n\n\tasync getBranchDiff(options: GetBranchDiffOptions): Promise<GetBranchDiffResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tbranch: options.branch,\n\t\t};\n\n\t\tif (options.base) {\n\t\t\tparams.base = options.base;\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/branches/diff', params }, jwt);\n\n\t\treturn (await response.json()) as GetBranchDiffResponse;\n\t}\n\n\tasync getCommitDiff(options: GetCommitDiffOptions): Promise<GetCommitDiffResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tsha: options.sha,\n\t\t};\n\n\t\tconst response = await this.api.get({ path: 'repos/diff', params }, jwt);\n\n\t\treturn (await response.json()) as GetCommitDiffResponse;\n\t}\n\n\tasync getCommit(options: GetCommitOptions): Promise<GetCommitResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\trepo: this.id,\n\t\t\tsha: options.sha,\n\t\t};\n\t\tconst response = await this.api.get({ path: 'commit', params }, jwt);\n\n\t\treturn (await response.json()) as GetCommitResponse;\n\t}\n\n\tasync repull(options: RepullOptions): Promise<void> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:write'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst body: Record<string, string> = {};\n\n\t\tif (options.ref) {\n\t\t\tbody.ref = options.ref;\n\t\t}\n\n\t\tconst response = await this.api.post({ path: 'repos/repull', body }, jwt);\n\n\t\tif (response.status !== 202) {\n\t\t\tthrow new Error(`Repull failed: ${response.status} ${await response.text()}`);\n\t\t}\n\n\t\treturn;\n\t}\n}\n\nexport class GitStorage {\n\tprivate static overrides: OverrideableGitStorageOptions = {};\n\tprivate options: GitStorageOptions;\n\tprivate api: ApiFetcher;\n\n\tconstructor(options: GitStorageOptions) {\n\t\tif (\n\t\t\t!options ||\n\t\t\toptions.name === undefined ||\n\t\t\toptions.key === undefined ||\n\t\t\toptions.name === null ||\n\t\t\toptions.key === null\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t'GitStorage requires a name and key. Please check your configuration and try again.',\n\t\t\t);\n\t\t}\n\n\t\tif (typeof options.name !== 'string' || options.name.trim() === '') {\n\t\t\tthrow new Error('GitStorage name must be a non-empty string.');\n\t\t}\n\n\t\tif (typeof options.key !== 'string' || options.key.trim() === '') {\n\t\t\tthrow new Error('GitStorage key must be a non-empty string.');\n\t\t}\n\n\t\tconst resolvedApiBaseUrl =\n\t\t\toptions.apiBaseUrl ?? GitStorage.overrides.apiBaseUrl ?? API_BASE_URL;\n\t\tconst resolvedApiVersion = options.apiVersion ?? GitStorage.overrides.apiVersion ?? API_VERSION;\n\t\tconst resolvedStorageBaseUrl =\n\t\t\toptions.storageBaseUrl ?? GitStorage.overrides.storageBaseUrl ?? STORAGE_BASE_URL;\n\n\t\tthis.api = getApiInstance(resolvedApiBaseUrl, resolvedApiVersion);\n\n\t\tthis.options = {\n\t\t\tkey: options.key,\n\t\t\tname: options.name,\n\t\t\tapiBaseUrl: resolvedApiBaseUrl,\n\t\t\tapiVersion: resolvedApiVersion,\n\t\t\tstorageBaseUrl: resolvedStorageBaseUrl,\n\t\t};\n\t}\n\n\tstatic override(options: OverrideableGitStorageOptions): void {\n\t\tthis.overrides = Object.assign({}, this.overrides, options);\n\t}\n\n\t/**\n\t * Create a new repository\n\t * @returns The created repository\n\t */\n\tasync createRepo(options?: CreateRepoOptions): Promise<Repo> {\n\t\tconst repoId = options?.id || crypto.randomUUID();\n\n\t\tconst jwt = await this.generateJWT(repoId, {\n\t\t\tpermissions: ['repo:write'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst baseRepoOptions = options?.baseRepo\n\t\t\t? {\n\t\t\t\t\tprovider: 'github',\n\t\t\t\t\t...snakecaseKeys(options.baseRepo as unknown as Record<string, unknown>),\n\t\t\t\t}\n\t\t\t: null;\n\n\t\t// Default defaultBranch to 'main' if not provided\n\t\tconst defaultBranch = options?.defaultBranch ?? 'main';\n\n\t\tconst createRepoPath =\n\t\t\tbaseRepoOptions || defaultBranch\n\t\t\t\t? {\n\t\t\t\t\t\tpath: 'repos',\n\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t...(baseRepoOptions && { base_repo: baseRepoOptions }),\n\t\t\t\t\t\t\tdefault_branch: defaultBranch,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: 'repos';\n\n\t\t// Allow 409 so we can map it to a clearer error message\n\t\tconst resp = await this.api.post(createRepoPath, jwt, { allowedStatus: [409] });\n\t\tif (resp.status === 409) {\n\t\t\tthrow new Error('Repository already exists');\n\t\t}\n\n\t\treturn new RepoImpl(repoId, this.options, this.generateJWT.bind(this));\n\t}\n\n\t/**\n\t * Find a repository by ID\n\t * @param options The search options\n\t * @returns The found repository\n\t */\n\tasync findOne(options: FindOneOptions): Promise<Repo | null> {\n\t\tconst jwt = await this.generateJWT(options.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: 1 * 60 * 60,\n\t\t});\n\n\t\t// Allow 404 to indicate \"not found\" without throwing\n\t\tconst resp = await this.api.get('repo', jwt, { allowedStatus: [404] });\n\t\tif (resp.status === 404) {\n\t\t\treturn null;\n\t\t}\n\t\t// On 200, we could validate response, but RepoImpl only needs the repo URL/id\n\t\t// const body = await resp.json(); // not required for now\n\t\treturn new RepoImpl(options.id, this.options, this.generateJWT.bind(this));\n\t}\n\n\t/**\n\t * Get the current configuration\n\t * @returns The client configuration\n\t */\n\tgetConfig(): GitStorageOptions {\n\t\treturn { ...this.options };\n\t}\n\n\t/**\n\t * Generate a JWT token for git storage URL authentication\n\t * @private\n\t */\n\tprivate async generateJWT(repoId: string, options?: GetRemoteURLOptions): Promise<string> {\n\t\t// Default permissions and TTL\n\t\tconst permissions = options?.permissions || ['git:write', 'git:read'];\n\t\tconst ttl = options?.ttl || 365 * 24 * 60 * 60; // 1 year in seconds\n\n\t\t// Create the JWT payload\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst payload = {\n\t\t\tiss: this.options.name,\n\t\t\tsub: '@pierre/storage',\n\t\t\trepo: repoId,\n\t\t\tscopes: permissions,\n\t\t\tiat: now,\n\t\t\texp: now + ttl,\n\t\t};\n\n\t\t// Sign the JWT with the key as the secret\n\t\t// Using HS256 for symmetric signing with the key\n\t\tconst key = await importPKCS8(this.options.key, 'ES256');\n\t\t// Sign the JWT with the key as the secret\n\t\tconst jwt = await new SignJWT(payload)\n\t\t\t.setProtectedHeader({ alg: 'ES256', typ: 'JWT' })\n\t\t\t.sign(key);\n\n\t\treturn jwt;\n\t}\n}\n\n// Export a default client factory\nexport function createClient(options: GitStorageOptions): GitStorage {\n\treturn new GitStorage(options);\n}\n\n// Type alias for backward compatibility\nexport type StorageOptions = GitStorageOptions;\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -19,7 +19,7 @@ interface GetRemoteURLOptions {
|
|
|
19
19
|
interface Repo {
|
|
20
20
|
id: string;
|
|
21
21
|
getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
|
|
22
|
-
|
|
22
|
+
getFileStream(options: GetFileOptions): Promise<Response>;
|
|
23
23
|
listFiles(options?: ListFilesOptions): Promise<ListFilesResponse>;
|
|
24
24
|
listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse>;
|
|
25
25
|
listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse>;
|
|
@@ -64,13 +64,6 @@ interface GetFileOptions extends GitStorageInvocationOptions {
|
|
|
64
64
|
path: string;
|
|
65
65
|
ref?: string;
|
|
66
66
|
}
|
|
67
|
-
interface GetFileResponse {
|
|
68
|
-
path: string;
|
|
69
|
-
ref: string;
|
|
70
|
-
content: string;
|
|
71
|
-
size: number;
|
|
72
|
-
is_binary: boolean;
|
|
73
|
-
}
|
|
74
67
|
interface RepullOptions extends GitStorageInvocationOptions {
|
|
75
68
|
ref?: string;
|
|
76
69
|
}
|
|
@@ -320,4 +313,4 @@ declare class GitStorage {
|
|
|
320
313
|
declare function createClient(options: GitStorageOptions): GitStorage;
|
|
321
314
|
type StorageOptions = GitStorageOptions;
|
|
322
315
|
|
|
323
|
-
export { type BaseRepo, type BranchInfo, type CommitInfo, type CreateRepoOptions, type CreateRepoResponse, type DiffStats, type FileDiff, type FilteredFile, type FindOneOptions, type GetBranchDiffOptions, type GetBranchDiffResponse, type GetCommitDiffOptions, type GetCommitDiffResponse, type GetCommitOptions, type GetCommitResponse, type GetFileOptions, type
|
|
316
|
+
export { type BaseRepo, type BranchInfo, type CommitInfo, type CreateRepoOptions, type CreateRepoResponse, type DiffStats, type FileDiff, type FilteredFile, type FindOneOptions, type GetBranchDiffOptions, type GetBranchDiffResponse, type GetCommitDiffOptions, type GetCommitDiffResponse, type GetCommitOptions, type GetCommitResponse, type GetFileOptions, type GetRemoteURLOptions, GitStorage, type GitStorageOptions, type ListBranchesOptions, type ListBranchesResponse, type ListCommitsOptions, type ListCommitsResponse, type ListFilesOptions, type ListFilesResponse, type OverrideableGitStorageOptions, type ParsedWebhookSignature, type Repo, type RepullOptions, type StorageOptions, type SupportedRepoProvider, type ValidAPIVersion, type ValidMethod, type ValidPath, type WebhookEventPayload, type WebhookPushEvent, type WebhookValidationOptions, type WebhookValidationResult, createClient, parseSignatureHeader, validateWebhook, validateWebhookSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ interface GetRemoteURLOptions {
|
|
|
19
19
|
interface Repo {
|
|
20
20
|
id: string;
|
|
21
21
|
getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
|
|
22
|
-
|
|
22
|
+
getFileStream(options: GetFileOptions): Promise<Response>;
|
|
23
23
|
listFiles(options?: ListFilesOptions): Promise<ListFilesResponse>;
|
|
24
24
|
listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse>;
|
|
25
25
|
listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse>;
|
|
@@ -64,13 +64,6 @@ interface GetFileOptions extends GitStorageInvocationOptions {
|
|
|
64
64
|
path: string;
|
|
65
65
|
ref?: string;
|
|
66
66
|
}
|
|
67
|
-
interface GetFileResponse {
|
|
68
|
-
path: string;
|
|
69
|
-
ref: string;
|
|
70
|
-
content: string;
|
|
71
|
-
size: number;
|
|
72
|
-
is_binary: boolean;
|
|
73
|
-
}
|
|
74
67
|
interface RepullOptions extends GitStorageInvocationOptions {
|
|
75
68
|
ref?: string;
|
|
76
69
|
}
|
|
@@ -320,4 +313,4 @@ declare class GitStorage {
|
|
|
320
313
|
declare function createClient(options: GitStorageOptions): GitStorage;
|
|
321
314
|
type StorageOptions = GitStorageOptions;
|
|
322
315
|
|
|
323
|
-
export { type BaseRepo, type BranchInfo, type CommitInfo, type CreateRepoOptions, type CreateRepoResponse, type DiffStats, type FileDiff, type FilteredFile, type FindOneOptions, type GetBranchDiffOptions, type GetBranchDiffResponse, type GetCommitDiffOptions, type GetCommitDiffResponse, type GetCommitOptions, type GetCommitResponse, type GetFileOptions, type
|
|
316
|
+
export { type BaseRepo, type BranchInfo, type CommitInfo, type CreateRepoOptions, type CreateRepoResponse, type DiffStats, type FileDiff, type FilteredFile, type FindOneOptions, type GetBranchDiffOptions, type GetBranchDiffResponse, type GetCommitDiffOptions, type GetCommitDiffResponse, type GetCommitOptions, type GetCommitResponse, type GetFileOptions, type GetRemoteURLOptions, GitStorage, type GitStorageOptions, type ListBranchesOptions, type ListBranchesResponse, type ListCommitsOptions, type ListCommitsResponse, type ListFilesOptions, type ListFilesResponse, type OverrideableGitStorageOptions, type ParsedWebhookSignature, type Repo, type RepullOptions, type StorageOptions, type SupportedRepoProvider, type ValidAPIVersion, type ValidMethod, type ValidPath, type WebhookEventPayload, type WebhookPushEvent, type WebhookValidationOptions, type WebhookValidationResult, createClient, parseSignatureHeader, validateWebhook, validateWebhookSignature };
|
package/dist/index.js
CHANGED
|
@@ -260,7 +260,7 @@ var RepoImpl = class {
|
|
|
260
260
|
url.password = await this.generateJWT(this.id, urlOptions);
|
|
261
261
|
return url.toString();
|
|
262
262
|
}
|
|
263
|
-
async
|
|
263
|
+
async getFileStream(options) {
|
|
264
264
|
const jwt = await this.generateJWT(this.id, {
|
|
265
265
|
permissions: ["git:read"],
|
|
266
266
|
ttl: options?.ttl ?? 1 * 60 * 60
|
|
@@ -272,8 +272,7 @@ var RepoImpl = class {
|
|
|
272
272
|
if (options.ref) {
|
|
273
273
|
params.ref = options.ref;
|
|
274
274
|
}
|
|
275
|
-
|
|
276
|
-
return await response.json();
|
|
275
|
+
return this.api.get({ path: "repos/file", params }, jwt);
|
|
277
276
|
}
|
|
278
277
|
async listFiles(options) {
|
|
279
278
|
const jwt = await this.generateJWT(this.id, {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/fetch.ts","../src/util.ts","../src/webhook.ts","../src/index.ts"],"names":["API_BASE_URL","crypto"],"mappings":";;;;;;AAMO,IAAM,aAAN,MAAiB;AAAA,EACvB,WAAA,CACkBA,eACA,OAChB,EAAA;AAFgB,IAAAA,IAAAA,CAAAA,YAAAA,GAAAA,aAAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAEjB,IAAQ,OAAA,CAAA,GAAA,CAAI,qBAAuBA,EAAAA,aAAAA,EAAc,OAAO,CAAA;AAAA;AACzD,EAEQ,UAAa,GAAA;AACpB,IAAA,OAAO,CAAG,EAAA,IAAA,CAAK,YAAY,CAAA,MAAA,EAAS,KAAK,OAAO,CAAA,CAAA;AAAA;AACjD,EAEQ,cAAc,IAAiB,EAAA;AACtC,IAAI,IAAA,OAAO,SAAS,QAAU,EAAA;AAC7B,MAAA,OAAO,CAAG,EAAA,IAAA,CAAK,UAAW,EAAC,IAAI,IAAI,CAAA,CAAA;AAAA,KACpC,MAAA,IAAW,KAAK,MAAQ,EAAA;AACvB,MAAA,MAAM,WAAW,IAAI,eAAA,CAAgB,IAAK,CAAA,MAAM,EAAE,QAAS,EAAA;AAC3D,MAAA,OAAO,CAAG,EAAA,IAAA,CAAK,UAAW,EAAC,CAAI,CAAA,EAAA,IAAA,CAAK,IAAI,CAAA,EAAG,QAAW,GAAA,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,GAAK,EAAE,CAAA,CAAA;AAAA,KACnE,MAAA;AACN,MAAA,OAAO,GAAG,IAAK,CAAA,UAAA,EAAY,CAAA,CAAA,EAAI,KAAK,IAAI,CAAA,CAAA;AAAA;AACzC;AACD,EAEA,MAAc,KAAA,CAAM,IAAiB,EAAA,MAAA,EAAqB,KAAa,OAA0B,EAAA;AAChG,IAAM,MAAA,UAAA,GAAa,IAAK,CAAA,aAAA,CAAc,IAAI,CAAA;AAE1C,IAAA,MAAM,cAA8B,GAAA;AAAA,MACnC,MAAA;AAAA,MACA,OAAS,EAAA;AAAA,QACR,aAAA,EAAe,UAAU,GAAG,CAAA,CAAA;AAAA,QAC5B,cAAgB,EAAA;AAAA;AACjB,KACD;AAEA,IAAA,IAAI,WAAW,KAAS,IAAA,OAAO,IAAS,KAAA,QAAA,IAAY,KAAK,IAAM,EAAA;AAC9D,MAAA,cAAA,CAAe,IAAO,GAAA,IAAA,CAAK,SAAU,CAAA,IAAA,CAAK,IAAI,CAAA;AAAA;AAG/C,IAAA,MAAM,QAAW,GAAA,MAAM,KAAM,CAAA,UAAA,EAAY,cAAc,CAAA;AAEvD,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AACjB,MAAM,MAAA,OAAA,GAAU,OAAS,EAAA,aAAA,IAAiB,EAAC;AAC3C,MAAA,IAAI,CAAC,OAAA,CAAQ,QAAS,CAAA,QAAA,CAAS,MAAM,CAAG,EAAA;AACvC,QAAM,MAAA,IAAI,MAAM,CAAmB,gBAAA,EAAA,MAAM,IAAI,UAAU,CAAA,EAAA,EAAK,QAAS,CAAA,UAAU,CAAE,CAAA,CAAA;AAAA;AAClF;AAED,IAAO,OAAA,QAAA;AAAA;AACR,EAEA,MAAM,GAAA,CAAI,IAAiB,EAAA,GAAA,EAAa,OAA0B,EAAA;AACjE,IAAA,OAAO,IAAK,CAAA,KAAA,CAAM,IAAM,EAAA,KAAA,EAAO,KAAK,OAAO,CAAA;AAAA;AAC5C,EAEA,MAAM,IAAA,CAAK,IAAiB,EAAA,GAAA,EAAa,OAA0B,EAAA;AAClE,IAAA,OAAO,IAAK,CAAA,KAAA,CAAM,IAAM,EAAA,MAAA,EAAQ,KAAK,OAAO,CAAA;AAAA;AAC7C,EAEA,MAAM,GAAA,CAAI,IAAiB,EAAA,GAAA,EAAa,OAA0B,EAAA;AACjE,IAAA,OAAO,IAAK,CAAA,KAAA,CAAM,IAAM,EAAA,KAAA,EAAO,KAAK,OAAO,CAAA;AAAA;AAC5C,EAEA,MAAM,MAAA,CAAO,IAAiB,EAAA,GAAA,EAAa,OAA0B,EAAA;AACpE,IAAA,OAAO,IAAK,CAAA,KAAA,CAAM,IAAM,EAAA,QAAA,EAAU,KAAK,OAAO,CAAA;AAAA;AAEhD,CAAA;;;ACtEO,SAAS,eAAA,CAAgB,GAAwB,CAAiC,EAAA;AACxF,EAAM,MAAA,OAAA,GAAU,OAAO,CAAM,KAAA,QAAA,GAAW,IAAI,WAAY,EAAA,CAAE,MAAO,CAAA,CAAC,CAAI,GAAA,CAAA;AACtE,EAAM,MAAA,OAAA,GAAU,OAAO,CAAM,KAAA,QAAA,GAAW,IAAI,WAAY,EAAA,CAAE,MAAO,CAAA,CAAC,CAAI,GAAA,CAAA;AAEtE,EAAA,IAAI,OAAQ,CAAA,MAAA,KAAW,OAAQ,CAAA,MAAA,EAAe,OAAA,KAAA;AAE9C,EAAA,IAAI,MAAS,GAAA,CAAA;AACb,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,OAAA,CAAQ,QAAQ,CAAK,EAAA,EAAA;AACxC,IAAA,MAAA,IAAU,OAAQ,CAAA,CAAC,CAAI,GAAA,OAAA,CAAQ,CAAC,CAAA;AAAA;AAEjC,EAAA,OAAO,MAAW,KAAA,CAAA;AACnB;AAEA,eAAsB,oBAAuB,GAAA;AAC5C,EAAI,IAAA,CAAC,WAAW,MAAQ,EAAA;AACvB,IAAA,MAAM,EAAE,SAAA,EAAc,GAAA,MAAM,OAAO,QAAa,CAAA;AAChD,IAAO,OAAA,SAAA;AAAA;AAER,EAAA,OAAO,UAAW,CAAA,MAAA;AACnB;AAEA,eAAsB,UAAA,CAAW,SAAmB,EAAA,MAAA,EAAgB,IAA+B,EAAA;AAIlG,EAAA,IAAI,CAAC,MAAA,IAAU,MAAO,CAAA,MAAA,KAAW,CAAG,EAAA;AACnC,IAAM,MAAA,IAAI,MAAM,oBAAoB,CAAA;AAAA;AAGrC,EAAMC,MAAAA,OAAAA,GAAS,MAAM,oBAAqB,EAAA;AAC1C,EAAM,MAAA,OAAA,GAAU,IAAI,WAAY,EAAA;AAChC,EAAM,MAAA,GAAA,GAAM,MAAMA,OAAAA,CAAO,MAAO,CAAA,SAAA;AAAA,IAC/B,KAAA;AAAA,IACA,OAAA,CAAQ,OAAO,MAAM,CAAA;AAAA,IACrB,EAAE,IAAA,EAAM,MAAQ,EAAA,IAAA,EAAM,SAAU,EAAA;AAAA,IAChC,KAAA;AAAA,IACA,CAAC,MAAM;AAAA,GACR;AAEA,EAAM,MAAA,SAAA,GAAY,MAAMA,OAAAA,CAAO,MAAO,CAAA,IAAA,CAAK,QAAQ,GAAK,EAAA,OAAA,CAAQ,MAAO,CAAA,IAAI,CAAC,CAAA;AAC5E,EAAO,OAAA,KAAA,CAAM,KAAK,IAAI,UAAA,CAAW,SAAS,CAAC,CAAA,CACzC,IAAI,CAAC,CAAA,KAAM,EAAE,QAAS,CAAA,EAAE,EAAE,QAAS,CAAA,CAAA,EAAG,GAAG,CAAC,CAAA,CAC1C,KAAK,EAAE,CAAA;AACV;;;AC9BA,IAAM,uBAA0B,GAAA,GAAA;AAMzB,SAAS,qBAAqB,MAA+C,EAAA;AACnF,EAAA,IAAI,CAAC,MAAA,IAAU,OAAO,MAAA,KAAW,QAAU,EAAA;AAC1C,IAAO,OAAA,IAAA;AAAA;AAGR,EAAA,IAAI,SAAY,GAAA,EAAA;AAChB,EAAA,IAAI,SAAY,GAAA,EAAA;AAGhB,EAAM,MAAA,QAAA,GAAW,MAAO,CAAA,KAAA,CAAM,GAAG,CAAA;AACjC,EAAA,KAAA,MAAW,WAAW,QAAU,EAAA;AAC/B,IAAM,MAAA,cAAA,GAAiB,QAAQ,IAAK,EAAA;AACpC,IAAA,MAAM,KAAQ,GAAA,cAAA,CAAe,KAAM,CAAA,GAAA,EAAK,CAAC,CAAA;AACzC,IAAI,IAAA,KAAA,CAAM,WAAW,CAAG,EAAA;AACvB,MAAA;AAAA;AAGD,IAAM,MAAA,CAAC,GAAK,EAAA,KAAK,CAAI,GAAA,KAAA;AACrB,IAAA,QAAQ,GAAK;AAAA,MACZ,KAAK,GAAA;AACJ,QAAY,SAAA,GAAA,KAAA;AACZ,QAAA;AAAA,MACD,KAAK,QAAA;AACJ,QAAY,SAAA,GAAA,KAAA;AACZ,QAAA;AAAA;AACF;AAGD,EAAI,IAAA,CAAC,SAAa,IAAA,CAAC,SAAW,EAAA;AAC7B,IAAO,OAAA,IAAA;AAAA;AAGR,EAAO,OAAA,EAAE,WAAW,SAAU,EAAA;AAC/B;AAyBA,eAAsB,yBACrB,OACA,EAAA,eAAA,EACA,MACA,EAAA,OAAA,GAAoC,EACD,EAAA;AACnC,EAAA,IAAI,CAAC,MAAA,IAAU,MAAO,CAAA,MAAA,KAAW,CAAG,EAAA;AACnC,IAAO,OAAA;AAAA,MACN,KAAO,EAAA,KAAA;AAAA,MACP,KAAO,EAAA;AAAA,KACR;AAAA;AAID,EAAM,MAAA,MAAA,GAAS,qBAAqB,eAAe,CAAA;AACnD,EAAA,IAAI,CAAC,MAAQ,EAAA;AACZ,IAAO,OAAA;AAAA,MACN,KAAO,EAAA,KAAA;AAAA,MACP,KAAO,EAAA;AAAA,KACR;AAAA;AAID,EAAA,MAAM,SAAY,GAAA,MAAA,CAAO,QAAS,CAAA,MAAA,CAAO,WAAW,EAAE,CAAA;AACtD,EAAI,IAAA,KAAA,CAAM,SAAS,CAAG,EAAA;AACrB,IAAO,OAAA;AAAA,MACN,KAAO,EAAA,KAAA;AAAA,MACP,KAAO,EAAA;AAAA,KACR;AAAA;AAID,EAAM,MAAA,MAAA,GAAS,QAAQ,aAAiB,IAAA,uBAAA;AACxC,EAAA,IAAI,SAAS,CAAG,EAAA;AACf,IAAA,MAAM,MAAM,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,GAAA,KAAQ,GAAI,CAAA;AACxC,IAAA,MAAM,MAAM,GAAM,GAAA,SAAA;AAElB,IAAA,IAAI,MAAM,MAAQ,EAAA;AACjB,MAAO,OAAA;AAAA,QACN,KAAO,EAAA,KAAA;AAAA,QACP,KAAA,EAAO,8BAA8B,GAAG,CAAA,SAAA,CAAA;AAAA,QACxC;AAAA,OACD;AAAA;AAID,IAAA,IAAI,MAAM,GAAK,EAAA;AACd,MAAO,OAAA;AAAA,QACN,KAAO,EAAA,KAAA;AAAA,QACP,KAAO,EAAA,oCAAA;AAAA,QACP;AAAA,OACD;AAAA;AACD;AAID,EAAA,MAAM,aAAa,OAAO,OAAA,KAAY,WAAW,OAAU,GAAA,OAAA,CAAQ,SAAS,MAAM,CAAA;AAIlF,EAAA,MAAM,UAAa,GAAA,CAAA,EAAG,MAAO,CAAA,SAAS,IAAI,UAAU,CAAA,CAAA;AACpD,EAAA,MAAM,iBAAoB,GAAA,MAAM,UAAW,CAAA,QAAA,EAAU,QAAQ,UAAU,CAAA;AAGvE,EAAM,MAAA,cAAA,GAAiB,MAAO,CAAA,IAAA,CAAK,iBAAiB,CAAA;AACpD,EAAA,MAAM,YAAe,GAAA,MAAA,CAAO,IAAK,CAAA,MAAA,CAAO,SAAS,CAAA;AAGjD,EAAI,IAAA,cAAA,CAAe,MAAW,KAAA,YAAA,CAAa,MAAQ,EAAA;AAClD,IAAO,OAAA;AAAA,MACN,KAAO,EAAA,KAAA;AAAA,MACP,KAAO,EAAA,mBAAA;AAAA,MACP;AAAA,KACD;AAAA;AAGD,EAAM,MAAA,eAAA,GAAkB,eAAgB,CAAA,cAAA,EAAgB,YAAY,CAAA;AACpE,EAAA,IAAI,CAAC,eAAiB,EAAA;AACrB,IAAO,OAAA;AAAA,MACN,KAAO,EAAA,KAAA;AAAA,MACP,KAAO,EAAA,mBAAA;AAAA,MACP;AAAA,KACD;AAAA;AAGD,EAAO,OAAA;AAAA,IACN,KAAO,EAAA,IAAA;AAAA,IACP;AAAA,GACD;AACD;AA6BA,eAAsB,gBACrB,OACA,EAAA,OAAA,EACA,MACA,EAAA,OAAA,GAAoC,EACmC,EAAA;AAEvE,EAAA,MAAM,eAAkB,GAAA,OAAA,CAAQ,oBAAoB,CAAA,IAAK,QAAQ,oBAAoB,CAAA;AACrF,EAAA,IAAI,CAAC,eAAA,IAAmB,KAAM,CAAA,OAAA,CAAQ,eAAe,CAAG,EAAA;AACvD,IAAO,OAAA;AAAA,MACN,KAAO,EAAA,KAAA;AAAA,MACP,KAAO,EAAA;AAAA,KACR;AAAA;AAID,EAAA,MAAM,SAAY,GAAA,OAAA,CAAQ,gBAAgB,CAAA,IAAK,QAAQ,gBAAgB,CAAA;AACvE,EAAA,IAAI,CAAC,SAAA,IAAa,KAAM,CAAA,OAAA,CAAQ,SAAS,CAAG,EAAA;AAC3C,IAAO,OAAA;AAAA,MACN,KAAO,EAAA,KAAA;AAAA,MACP,KAAO,EAAA;AAAA,KACR;AAAA;AAID,EAAA,MAAM,mBAAmB,MAAM,wBAAA;AAAA,IAC9B,OAAA;AAAA,IACA,eAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACD;AAEA,EAAI,IAAA,CAAC,iBAAiB,KAAO,EAAA;AAC5B,IAAO,OAAA,gBAAA;AAAA;AAIR,EAAA,MAAM,aAAa,OAAO,OAAA,KAAY,WAAW,OAAU,GAAA,OAAA,CAAQ,SAAS,MAAM,CAAA;AAClF,EAAI,IAAA,aAAA;AACJ,EAAI,IAAA;AACH,IAAgB,aAAA,GAAA,IAAA,CAAK,MAAM,UAAU,CAAA;AAAA,GAC9B,CAAA,MAAA;AACP,IAAO,OAAA;AAAA,MACN,KAAO,EAAA,KAAA;AAAA,MACP,KAAO,EAAA,sBAAA;AAAA,MACP,WAAW,gBAAiB,CAAA;AAAA,KAC7B;AAAA;AAGD,EAAO,OAAA;AAAA,IACN,KAAO,EAAA,IAAA;AAAA,IACP,SAAA;AAAA,IACA,WAAW,gBAAiB,CAAA,SAAA;AAAA,IAC5B,OAAS,EAAA;AAAA,GACV;AACD;;;ACvMA,IAAM,YAAe,GAAA,yBAAA;AACrB,IAAM,gBAAmB,GAAA,aAAA;AACzB,IAAM,WAA+B,GAAA,CAAA;AAErC,IAAM,cAAA,uBAAqB,GAAwB,EAAA;AAEnD,SAAS,cAAA,CAAe,SAAiB,OAA0B,EAAA;AAClE,EAAI,IAAA,CAAC,eAAe,GAAI,CAAA,CAAA,EAAG,OAAO,CAAK,EAAA,EAAA,OAAO,EAAE,CAAG,EAAA;AAClD,IAAe,cAAA,CAAA,GAAA,CAAI,CAAG,EAAA,OAAO,CAAK,EAAA,EAAA,OAAO,IAAI,IAAI,UAAA,CAAW,OAAS,EAAA,OAAO,CAAC,CAAA;AAAA;AAE9E,EAAA,OAAO,eAAe,GAAI,CAAA,CAAA,EAAG,OAAO,CAAA,EAAA,EAAK,OAAO,CAAE,CAAA,CAAA;AACnD;AAKA,IAAM,WAAN,MAA+B;AAAA,EAG9B,WAAA,CACiB,EACC,EAAA,OAAA,EACA,WAIhB,EAAA;AANe,IAAA,IAAA,CAAA,EAAA,GAAA,EAAA;AACC,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AAKjB,IAAA,IAAA,CAAK,GAAM,GAAA,cAAA;AAAA,MACV,IAAA,CAAK,QAAQ,UAAc,IAAA,YAAA;AAAA,MAC3B,IAAA,CAAK,QAAQ,UAAc,IAAA;AAAA,KAC5B;AAAA;AACD,EAdiB,GAAA;AAAA,EAgBjB,MAAM,aAAa,UAAmD,EAAA;AACrE,IAAM,MAAA,cAAA,GAAiB,IAAK,CAAA,OAAA,CAAQ,cAAkB,IAAA,gBAAA;AACtD,IAAA,MAAM,GAAM,GAAA,IAAI,GAAI,CAAA,CAAA,QAAA,EAAW,IAAK,CAAA,OAAA,CAAQ,IAAI,CAAA,CAAA,EAAI,cAAc,CAAA,CAAA,EAAI,IAAK,CAAA,EAAE,CAAM,IAAA,CAAA,CAAA;AACnF,IAAA,GAAA,CAAI,QAAW,GAAA,CAAA,CAAA,CAAA;AACf,IAAA,GAAA,CAAI,WAAW,MAAM,IAAA,CAAK,WAAY,CAAA,IAAA,CAAK,IAAI,UAAU,CAAA;AACzD,IAAA,OAAO,IAAI,QAAS,EAAA;AAAA;AACrB,EAEA,MAAM,QAAQ,OAAmD,EAAA;AAChE,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,KAAK,EAAI,EAAA;AAAA,MAC3C,WAAA,EAAa,CAAC,UAAU,CAAA;AAAA,MACxB,GAAK,EAAA,OAAA,EAAS,GAAO,IAAA,CAAA,GAAI,EAAK,GAAA;AAAA;AAAA,KAC9B,CAAA;AAED,IAAA,MAAM,MAAiC,GAAA;AAAA,MACtC,MAAM,OAAQ,CAAA;AAAA,KACf;AAEA,IAAA,IAAI,QAAQ,GAAK,EAAA;AAChB,MAAA,MAAA,CAAO,MAAM,OAAQ,CAAA,GAAA;AAAA;AAGtB,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,GAAI,CAAA,GAAA,CAAI,EAAE,IAAM,EAAA,YAAA,EAAc,MAAO,EAAA,EAAG,GAAG,CAAA;AAEvE,IAAQ,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA;AAC7B,EAEA,MAAM,UAAU,OAAwD,EAAA;AACvE,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,KAAK,EAAI,EAAA;AAAA,MAC3C,WAAA,EAAa,CAAC,UAAU,CAAA;AAAA,MACxB,GAAK,EAAA,OAAA,EAAS,GAAO,IAAA,CAAA,GAAI,EAAK,GAAA;AAAA;AAAA,KAC9B,CAAA;AAED,IAAA,MAAM,SAA6C,OAAS,EAAA,GAAA,GACzD,EAAE,GAAK,EAAA,OAAA,CAAQ,KACf,GAAA,MAAA;AACH,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,GAAI,CAAA,GAAA,CAAI,EAAE,IAAM,EAAA,aAAA,EAAe,MAAO,EAAA,EAAG,GAAG,CAAA;AAExE,IAAQ,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA;AAC7B,EAEA,MAAM,aAAa,OAA8D,EAAA;AAChF,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,KAAK,EAAI,EAAA;AAAA,MAC3C,WAAA,EAAa,CAAC,UAAU,CAAA;AAAA,MACxB,GAAK,EAAA,OAAA,EAAS,GAAO,IAAA,CAAA,GAAI,EAAK,GAAA;AAAA;AAAA,KAC9B,CAAA;AAED,IAAI,IAAA,MAAA;AAEJ,IAAA,IAAI,OAAS,EAAA,MAAA,IAAU,CAAC,OAAA,EAAS,KAAO,EAAA;AACvC,MAAA,MAAA,GAAS,EAAC;AACV,MAAA,IAAI,SAAS,MAAQ,EAAA;AACpB,QAAA,MAAA,CAAO,SAAS,OAAQ,CAAA,MAAA;AAAA;AAEzB,MAAI,IAAA,OAAO,OAAS,EAAA,KAAA,IAAS,QAAU,EAAA;AACtC,QAAO,MAAA,CAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAM,QAAS,EAAA;AAAA;AACvC;AAGD,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,GAAI,CAAA,GAAA,CAAI,EAAE,IAAM,EAAA,gBAAA,EAAkB,MAAO,EAAA,EAAG,GAAG,CAAA;AAE3E,IAAQ,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA;AAC7B,EAEA,MAAM,YAAY,OAA4D,EAAA;AAC7E,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,KAAK,EAAI,EAAA;AAAA,MAC3C,WAAA,EAAa,CAAC,UAAU,CAAA;AAAA,MACxB,GAAK,EAAA,OAAA,EAAS,GAAO,IAAA,CAAA,GAAI,EAAK,GAAA;AAAA;AAAA,KAC9B,CAAA;AAED,IAAI,IAAA,MAAA;AAEJ,IAAA,IAAI,OAAS,EAAA,MAAA,IAAU,OAAS,EAAA,MAAA,IAAU,SAAS,KAAO,EAAA;AACzD,MAAA,MAAA,GAAS,EAAC;AACV,MAAA,IAAI,SAAS,MAAQ,EAAA;AACpB,QAAA,MAAA,CAAO,SAAS,OAAQ,CAAA,MAAA;AAAA;AAEzB,MAAA,IAAI,SAAS,MAAQ,EAAA;AACpB,QAAA,MAAA,CAAO,SAAS,OAAQ,CAAA,MAAA;AAAA;AAEzB,MAAI,IAAA,OAAO,OAAS,EAAA,KAAA,IAAS,QAAU,EAAA;AACtC,QAAO,MAAA,CAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAM,QAAS,EAAA;AAAA;AACvC;AAGD,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,GAAI,CAAA,GAAA,CAAI,EAAE,IAAM,EAAA,eAAA,EAAiB,MAAO,EAAA,EAAG,GAAG,CAAA;AAE1E,IAAQ,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA;AAC7B,EAEA,MAAM,cAAc,OAA+D,EAAA;AAClF,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,KAAK,EAAI,EAAA;AAAA,MAC3C,WAAA,EAAa,CAAC,UAAU,CAAA;AAAA,MACxB,GAAK,EAAA,OAAA,EAAS,GAAO,IAAA,CAAA,GAAI,EAAK,GAAA;AAAA;AAAA,KAC9B,CAAA;AAED,IAAA,MAAM,MAAiC,GAAA;AAAA,MACtC,QAAQ,OAAQ,CAAA;AAAA,KACjB;AAEA,IAAA,IAAI,QAAQ,IAAM,EAAA;AACjB,MAAA,MAAA,CAAO,OAAO,OAAQ,CAAA,IAAA;AAAA;AAGvB,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,GAAI,CAAA,GAAA,CAAI,EAAE,IAAM,EAAA,qBAAA,EAAuB,MAAO,EAAA,EAAG,GAAG,CAAA;AAEhF,IAAQ,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA;AAC7B,EAEA,MAAM,cAAc,OAA+D,EAAA;AAClF,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,KAAK,EAAI,EAAA;AAAA,MAC3C,WAAA,EAAa,CAAC,UAAU,CAAA;AAAA,MACxB,GAAK,EAAA,OAAA,EAAS,GAAO,IAAA,CAAA,GAAI,EAAK,GAAA;AAAA;AAAA,KAC9B,CAAA;AAED,IAAA,MAAM,MAAiC,GAAA;AAAA,MACtC,KAAK,OAAQ,CAAA;AAAA,KACd;AAEA,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,GAAI,CAAA,GAAA,CAAI,EAAE,IAAM,EAAA,YAAA,EAAc,MAAO,EAAA,EAAG,GAAG,CAAA;AAEvE,IAAQ,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA;AAC7B,EAEA,MAAM,UAAU,OAAuD,EAAA;AACtE,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,KAAK,EAAI,EAAA;AAAA,MAC3C,WAAA,EAAa,CAAC,UAAU,CAAA;AAAA,MACxB,GAAK,EAAA,OAAA,EAAS,GAAO,IAAA,CAAA,GAAI,EAAK,GAAA;AAAA;AAAA,KAC9B,CAAA;AAED,IAAA,MAAM,MAAiC,GAAA;AAAA,MACtC,MAAM,IAAK,CAAA,EAAA;AAAA,MACX,KAAK,OAAQ,CAAA;AAAA,KACd;AACA,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,GAAI,CAAA,GAAA,CAAI,EAAE,IAAM,EAAA,QAAA,EAAU,MAAO,EAAA,EAAG,GAAG,CAAA;AAEnE,IAAQ,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA;AAC7B,EAEA,MAAM,OAAO,OAAuC,EAAA;AACnD,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,KAAK,EAAI,EAAA;AAAA,MAC3C,WAAA,EAAa,CAAC,WAAW,CAAA;AAAA,MACzB,GAAK,EAAA,OAAA,EAAS,GAAO,IAAA,CAAA,GAAI,EAAK,GAAA;AAAA;AAAA,KAC9B,CAAA;AAED,IAAA,MAAM,OAA+B,EAAC;AAEtC,IAAA,IAAI,QAAQ,GAAK,EAAA;AAChB,MAAA,IAAA,CAAK,MAAM,OAAQ,CAAA,GAAA;AAAA;AAGpB,IAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,GAAI,CAAA,IAAA,CAAK,EAAE,IAAM,EAAA,cAAA,EAAgB,IAAK,EAAA,EAAG,GAAG,CAAA;AAExE,IAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC5B,MAAM,MAAA,IAAI,KAAM,CAAA,CAAA,eAAA,EAAkB,QAAS,CAAA,MAAM,IAAI,MAAM,QAAA,CAAS,IAAK,EAAC,CAAE,CAAA,CAAA;AAAA;AAG7E,IAAA;AAAA;AAEF,CAAA;AAEa,IAAA,UAAA,GAAN,MAAM,WAAW,CAAA;AAAA,EACvB,OAAe,YAA2C,EAAC;AAAA,EACnD,OAAA;AAAA,EACA,GAAA;AAAA,EAER,YAAY,OAA4B,EAAA;AACvC,IAAA,IACC,CAAC,OAAA,IACD,OAAQ,CAAA,IAAA,KAAS,MACjB,IAAA,OAAA,CAAQ,GAAQ,KAAA,MAAA,IAChB,OAAQ,CAAA,IAAA,KAAS,IACjB,IAAA,OAAA,CAAQ,QAAQ,IACf,EAAA;AACD,MAAA,MAAM,IAAI,KAAA;AAAA,QACT;AAAA,OACD;AAAA;AAGD,IAAI,IAAA,OAAO,QAAQ,IAAS,KAAA,QAAA,IAAY,QAAQ,IAAK,CAAA,IAAA,OAAW,EAAI,EAAA;AACnE,MAAM,MAAA,IAAI,MAAM,6CAA6C,CAAA;AAAA;AAG9D,IAAI,IAAA,OAAO,QAAQ,GAAQ,KAAA,QAAA,IAAY,QAAQ,GAAI,CAAA,IAAA,OAAW,EAAI,EAAA;AACjE,MAAM,MAAA,IAAI,MAAM,4CAA4C,CAAA;AAAA;AAG7D,IAAA,MAAM,kBACL,GAAA,OAAA,CAAQ,UAAc,IAAA,WAAA,CAAW,UAAU,UAAc,IAAA,YAAA;AAC1D,IAAA,MAAM,kBAAqB,GAAA,OAAA,CAAQ,UAAc,IAAA,WAAA,CAAW,UAAU,UAAc,IAAA,WAAA;AACpF,IAAA,MAAM,sBACL,GAAA,OAAA,CAAQ,cAAkB,IAAA,WAAA,CAAW,UAAU,cAAkB,IAAA,gBAAA;AAElE,IAAK,IAAA,CAAA,GAAA,GAAM,cAAe,CAAA,kBAAA,EAAoB,kBAAkB,CAAA;AAEhE,IAAA,IAAA,CAAK,OAAU,GAAA;AAAA,MACd,KAAK,OAAQ,CAAA,GAAA;AAAA,MACb,MAAM,OAAQ,CAAA,IAAA;AAAA,MACd,UAAY,EAAA,kBAAA;AAAA,MACZ,UAAY,EAAA,kBAAA;AAAA,MACZ,cAAgB,EAAA;AAAA,KACjB;AAAA;AACD,EAEA,OAAO,SAAS,OAA8C,EAAA;AAC7D,IAAA,IAAA,CAAK,YAAY,MAAO,CAAA,MAAA,CAAO,EAAI,EAAA,IAAA,CAAK,WAAW,OAAO,CAAA;AAAA;AAC3D;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,OAA4C,EAAA;AAC5D,IAAA,MAAM,MAAS,GAAA,OAAA,EAAS,EAAM,IAAA,MAAA,CAAO,UAAW,EAAA;AAEhD,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,MAAQ,EAAA;AAAA,MAC1C,WAAA,EAAa,CAAC,YAAY,CAAA;AAAA,MAC1B,GAAK,EAAA,OAAA,EAAS,GAAO,IAAA,CAAA,GAAI,EAAK,GAAA;AAAA;AAAA,KAC9B,CAAA;AAED,IAAM,MAAA,eAAA,GAAkB,SAAS,QAC9B,GAAA;AAAA,MACA,QAAU,EAAA,QAAA;AAAA,MACV,GAAG,aAAc,CAAA,OAAA,CAAQ,QAA8C;AAAA,KAEvE,GAAA,IAAA;AAGH,IAAM,MAAA,aAAA,GAAgB,SAAS,aAAiB,IAAA,MAAA;AAEhD,IAAM,MAAA,cAAA,GACL,mBAAmB,aAChB,GAAA;AAAA,MACA,IAAM,EAAA,OAAA;AAAA,MACN,IAAM,EAAA;AAAA,QACL,GAAI,eAAA,IAAmB,EAAE,SAAA,EAAW,eAAgB,EAAA;AAAA,QACpD,cAAgB,EAAA;AAAA;AACjB,KAEA,GAAA,OAAA;AAGJ,IAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,GAAA,CAAI,IAAK,CAAA,cAAA,EAAgB,GAAK,EAAA,EAAE,aAAe,EAAA,CAAC,GAAG,CAAA,EAAG,CAAA;AAC9E,IAAI,IAAA,IAAA,CAAK,WAAW,GAAK,EAAA;AACxB,MAAM,MAAA,IAAI,MAAM,2BAA2B,CAAA;AAAA;AAG5C,IAAO,OAAA,IAAI,SAAS,MAAQ,EAAA,IAAA,CAAK,SAAS,IAAK,CAAA,WAAA,CAAY,IAAK,CAAA,IAAI,CAAC,CAAA;AAAA;AACtE;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAQ,OAA+C,EAAA;AAC5D,IAAA,MAAM,GAAM,GAAA,MAAM,IAAK,CAAA,WAAA,CAAY,QAAQ,EAAI,EAAA;AAAA,MAC9C,WAAA,EAAa,CAAC,UAAU,CAAA;AAAA,MACxB,GAAA,EAAK,IAAI,EAAK,GAAA;AAAA,KACd,CAAA;AAGD,IAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,GAAA,CAAI,GAAI,CAAA,MAAA,EAAQ,GAAK,EAAA,EAAE,aAAe,EAAA,CAAC,GAAG,CAAA,EAAG,CAAA;AACrE,IAAI,IAAA,IAAA,CAAK,WAAW,GAAK,EAAA;AACxB,MAAO,OAAA,IAAA;AAAA;AAIR,IAAO,OAAA,IAAI,QAAS,CAAA,OAAA,CAAQ,EAAI,EAAA,IAAA,CAAK,SAAS,IAAK,CAAA,WAAA,CAAY,IAAK,CAAA,IAAI,CAAC,CAAA;AAAA;AAC1E;AAAA;AAAA;AAAA;AAAA,EAMA,SAA+B,GAAA;AAC9B,IAAO,OAAA,EAAE,GAAG,IAAA,CAAK,OAAQ,EAAA;AAAA;AAC1B;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,WAAY,CAAA,MAAA,EAAgB,OAAgD,EAAA;AAEzF,IAAA,MAAM,WAAc,GAAA,OAAA,EAAS,WAAe,IAAA,CAAC,aAAa,UAAU,CAAA;AACpE,IAAA,MAAM,GAAM,GAAA,OAAA,EAAS,GAAO,IAAA,GAAA,GAAM,KAAK,EAAK,GAAA,EAAA;AAG5C,IAAA,MAAM,MAAM,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,GAAA,KAAQ,GAAI,CAAA;AACxC,IAAA,MAAM,OAAU,GAAA;AAAA,MACf,GAAA,EAAK,KAAK,OAAQ,CAAA,IAAA;AAAA,MAClB,GAAK,EAAA,iBAAA;AAAA,MACL,IAAM,EAAA,MAAA;AAAA,MACN,MAAQ,EAAA,WAAA;AAAA,MACR,GAAK,EAAA,GAAA;AAAA,MACL,KAAK,GAAM,GAAA;AAAA,KACZ;AAIA,IAAA,MAAM,MAAM,MAAM,WAAA,CAAY,IAAK,CAAA,OAAA,CAAQ,KAAK,OAAO,CAAA;AAEvD,IAAA,MAAM,GAAM,GAAA,MAAM,IAAI,OAAA,CAAQ,OAAO,CACnC,CAAA,kBAAA,CAAmB,EAAE,GAAA,EAAK,SAAS,GAAK,EAAA,KAAA,EAAO,CAAA,CAC/C,KAAK,GAAG,CAAA;AAEV,IAAO,OAAA,GAAA;AAAA;AAET;AAGO,SAAS,aAAa,OAAwC,EAAA;AACpE,EAAO,OAAA,IAAI,WAAW,OAAO,CAAA;AAC9B","file":"index.js","sourcesContent":["import type { ValidAPIVersion, ValidMethod, ValidPath } from './types';\n\ninterface RequestOptions {\n\tallowedStatus?: number[];\n}\n\nexport class ApiFetcher {\n\tconstructor(\n\t\tprivate readonly API_BASE_URL: string,\n\t\tprivate readonly version: ValidAPIVersion,\n\t) {\n\t\tconsole.log('api fetcher created', API_BASE_URL, version);\n\t}\n\n\tprivate getBaseUrl() {\n\t\treturn `${this.API_BASE_URL}/api/v${this.version}`;\n\t}\n\n\tprivate getRequestUrl(path: ValidPath) {\n\t\tif (typeof path === 'string') {\n\t\t\treturn `${this.getBaseUrl()}/${path}`;\n\t\t} else if (path.params) {\n\t\t\tconst paramStr = new URLSearchParams(path.params).toString();\n\t\t\treturn `${this.getBaseUrl()}/${path.path}${paramStr ? `?${paramStr}` : ''}`;\n\t\t} else {\n\t\t\treturn `${this.getBaseUrl()}/${path.path}`;\n\t\t}\n\t}\n\n\tprivate async fetch(path: ValidPath, method: ValidMethod, jwt: string, options?: RequestOptions) {\n\t\tconst requestUrl = this.getRequestUrl(path);\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${jwt}`,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t};\n\n\t\tif (method !== 'GET' && typeof path !== 'string' && path.body) {\n\t\t\trequestOptions.body = JSON.stringify(path.body);\n\t\t}\n\n\t\tconst response = await fetch(requestUrl, requestOptions);\n\n\t\tif (!response.ok) {\n\t\t\tconst allowed = options?.allowedStatus ?? [];\n\t\t\tif (!allowed.includes(response.status)) {\n\t\t\t\tthrow new Error(`Failed to fetch ${method} ${requestUrl}: ${response.statusText}`);\n\t\t\t}\n\t\t}\n\t\treturn response;\n\t}\n\n\tasync get(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'GET', jwt, options);\n\t}\n\n\tasync post(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'POST', jwt, options);\n\t}\n\n\tasync put(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'PUT', jwt, options);\n\t}\n\n\tasync delete(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'DELETE', jwt, options);\n\t}\n}\n","export function timingSafeEqual(a: string | Uint8Array, b: string | Uint8Array): boolean {\n\tconst bufferA = typeof a === 'string' ? new TextEncoder().encode(a) : a;\n\tconst bufferB = typeof b === 'string' ? new TextEncoder().encode(b) : b;\n\n\tif (bufferA.length !== bufferB.length) return false;\n\n\tlet result = 0;\n\tfor (let i = 0; i < bufferA.length; i++) {\n\t\tresult |= bufferA[i] ^ bufferB[i];\n\t}\n\treturn result === 0;\n}\n\nexport async function getEnvironmentCrypto() {\n\tif (!globalThis.crypto) {\n\t\tconst { webcrypto } = await import('node:crypto');\n\t\treturn webcrypto;\n\t}\n\treturn globalThis.crypto;\n}\n\nexport async function createHmac(algorithm: string, secret: string, data: string): Promise<string> {\n\tif (algorithm !== 'sha256') {\n\t\tthrow new Error('Only sha256 algorithm is supported');\n\t}\n\tif (!secret || secret.length === 0) {\n\t\tthrow new Error('Secret is required');\n\t}\n\n\tconst crypto = await getEnvironmentCrypto();\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tencoder.encode(secret),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\n\tconst signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));\n\treturn Array.from(new Uint8Array(signature))\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n\n// Keep the legacy async function for backward compatibility\nexport async function createHmacAsync(secret: string, data: string): Promise<string> {\n\tconst crypto = await getEnvironmentCrypto();\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tencoder.encode(secret),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\n\tconst signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));\n\treturn Array.from(new Uint8Array(signature))\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n","/**\n * Webhook validation utilities for Pierre Git Storage\n */\n\nimport type {\n\tParsedWebhookSignature,\n\tWebhookEventPayload,\n\tWebhookValidationOptions,\n\tWebhookValidationResult,\n} from './types';\n\nimport { createHmac, timingSafeEqual } from './util';\n\nconst DEFAULT_MAX_AGE_SECONDS = 300; // 5 minutes\n\n/**\n * Parse the X-Pierre-Signature header\n * Format: t=<timestamp>,sha256=<signature>\n */\nexport function parseSignatureHeader(header: string): ParsedWebhookSignature | null {\n\tif (!header || typeof header !== 'string') {\n\t\treturn null;\n\t}\n\n\tlet timestamp = '';\n\tlet signature = '';\n\n\t// Split by comma and parse each element\n\tconst elements = header.split(',');\n\tfor (const element of elements) {\n\t\tconst trimmedElement = element.trim();\n\t\tconst parts = trimmedElement.split('=', 2);\n\t\tif (parts.length !== 2) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst [key, value] = parts;\n\t\tswitch (key) {\n\t\t\tcase 't':\n\t\t\t\ttimestamp = value;\n\t\t\t\tbreak;\n\t\t\tcase 'sha256':\n\t\t\t\tsignature = value;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!timestamp || !signature) {\n\t\treturn null;\n\t}\n\n\treturn { timestamp, signature };\n}\n\n/**\n * Validate a webhook signature and timestamp\n *\n * @param payload - The raw webhook payload (request body)\n * @param signatureHeader - The X-Pierre-Signature header value\n * @param secret - The webhook secret for HMAC verification\n * @param options - Validation options\n * @returns Validation result with details\n *\n * @example\n * ```typescript\n * const result = await validateWebhookSignature(\n * requestBody,\n * request.headers['x-pierre-signature'],\n * webhookSecret\n * );\n *\n * if (!result.valid) {\n * console.error('Invalid webhook:', result.error);\n * return;\n * }\n * ```\n */\nexport async function validateWebhookSignature(\n\tpayload: string | Buffer,\n\tsignatureHeader: string,\n\tsecret: string,\n\toptions: WebhookValidationOptions = {},\n): Promise<WebhookValidationResult> {\n\tif (!secret || secret.length === 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Empty secret is not allowed',\n\t\t};\n\t}\n\n\t// Parse the signature header\n\tconst parsed = parseSignatureHeader(signatureHeader);\n\tif (!parsed) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature header format',\n\t\t};\n\t}\n\n\t// Parse timestamp\n\tconst timestamp = Number.parseInt(parsed.timestamp, 10);\n\tif (isNaN(timestamp)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid timestamp in signature',\n\t\t};\n\t}\n\n\t// Validate timestamp age (prevent replay attacks)\n\tconst maxAge = options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;\n\tif (maxAge > 0) {\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst age = now - timestamp;\n\n\t\tif (age > maxAge) {\n\t\t\treturn {\n\t\t\t\tvalid: false,\n\t\t\t\terror: `Webhook timestamp too old (${age} seconds)`,\n\t\t\t\ttimestamp,\n\t\t\t};\n\t\t}\n\n\t\t// Also reject timestamps from the future (clock skew tolerance of 60 seconds)\n\t\tif (age < -60) {\n\t\t\treturn {\n\t\t\t\tvalid: false,\n\t\t\t\terror: 'Webhook timestamp is in the future',\n\t\t\t\ttimestamp,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Convert payload to string if it's a Buffer\n\tconst payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n\n\t// Compute expected signature\n\t// Format: HMAC-SHA256(secret, timestamp + \".\" + payload)\n\tconst signedData = `${parsed.timestamp}.${payloadStr}`;\n\tconst expectedSignature = await createHmac('sha256', secret, signedData);\n\n\t// Compare signatures using constant-time comparison\n\tconst expectedBuffer = Buffer.from(expectedSignature);\n\tconst actualBuffer = Buffer.from(parsed.signature);\n\n\t// Ensure both buffers are the same length for timing-safe comparison\n\tif (expectedBuffer.length !== actualBuffer.length) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature',\n\t\t\ttimestamp,\n\t\t};\n\t}\n\n\tconst signaturesMatch = timingSafeEqual(expectedBuffer, actualBuffer);\n\tif (!signaturesMatch) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature',\n\t\t\ttimestamp,\n\t\t};\n\t}\n\n\treturn {\n\t\tvalid: true,\n\t\ttimestamp,\n\t};\n}\n\n/**\n * Validate a webhook request\n *\n * This is a convenience function that validates the signature and parses the payload.\n *\n * @param payload - The raw webhook payload (request body)\n * @param headers - The request headers (must include x-pierre-signature and x-pierre-event)\n * @param secret - The webhook secret for HMAC verification\n * @param options - Validation options\n * @returns The parsed webhook payload if valid, or validation error\n *\n * @example\n * ```typescript\n * const result = await validateWebhook(\n * request.body,\n * request.headers,\n * process.env.WEBHOOK_SECRET\n * );\n *\n * if (!result.valid) {\n * return new Response('Invalid webhook', { status: 401 });\n * }\n *\n * // Type-safe access to the webhook payload\n * console.log('Push event:', result.payload);\n * ```\n */\nexport async function validateWebhook(\n\tpayload: string | Buffer,\n\theaders: Record<string, string | string[] | undefined>,\n\tsecret: string,\n\toptions: WebhookValidationOptions = {},\n): Promise<WebhookValidationResult & { payload?: WebhookEventPayload }> {\n\t// Get signature header\n\tconst signatureHeader = headers['x-pierre-signature'] || headers['X-Pierre-Signature'];\n\tif (!signatureHeader || Array.isArray(signatureHeader)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Missing or invalid X-Pierre-Signature header',\n\t\t};\n\t}\n\n\t// Get event type header\n\tconst eventType = headers['x-pierre-event'] || headers['X-Pierre-Event'];\n\tif (!eventType || Array.isArray(eventType)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Missing or invalid X-Pierre-Event header',\n\t\t};\n\t}\n\n\t// Validate signature\n\tconst validationResult = await validateWebhookSignature(\n\t\tpayload,\n\t\tsignatureHeader,\n\t\tsecret,\n\t\toptions,\n\t);\n\n\tif (!validationResult.valid) {\n\t\treturn validationResult;\n\t}\n\n\t// Parse payload\n\tconst payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n\tlet parsedPayload: WebhookEventPayload;\n\ttry {\n\t\tparsedPayload = JSON.parse(payloadStr);\n\t} catch {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid JSON payload',\n\t\t\ttimestamp: validationResult.timestamp,\n\t\t};\n\t}\n\n\treturn {\n\t\tvalid: true,\n\t\teventType,\n\t\ttimestamp: validationResult.timestamp,\n\t\tpayload: parsedPayload,\n\t};\n}\n","/**\n * Pierre Git Storage SDK\n *\n * A TypeScript SDK for interacting with Pierre's git storage system\n */\n\nimport { importPKCS8, SignJWT } from 'jose';\nimport snakecaseKeys from 'snakecase-keys';\nimport { ApiFetcher } from './fetch';\nimport type {\n\tCreateRepoOptions,\n\tFindOneOptions,\n\tGetBranchDiffOptions,\n\tGetBranchDiffResponse,\n\tGetCommitDiffOptions,\n\tGetCommitDiffResponse,\n\tGetCommitOptions,\n\tGetCommitResponse,\n\tGetFileOptions,\n\tGetFileResponse,\n\tGetRemoteURLOptions,\n\tGitStorageOptions,\n\tListBranchesOptions,\n\tListBranchesResponse,\n\tListCommitsOptions,\n\tListCommitsResponse,\n\tListFilesOptions,\n\tListFilesResponse,\n\tOverrideableGitStorageOptions,\n\tRepo,\n\tRepullOptions,\n\tValidAPIVersion,\n} from './types';\n\n/**\n * Type definitions for Pierre Git Storage SDK\n */\n\n// Import additional types from types.ts\nexport * from './types';\n\n// Export webhook validation utilities\nexport { parseSignatureHeader, validateWebhook, validateWebhookSignature } from './webhook';\n\n/**\n * Git Storage API\n */\n\ndeclare const __STORAGE_BASE_URL__: string;\ndeclare const __API_BASE_URL__: string;\n\nconst API_BASE_URL = __API_BASE_URL__;\nconst STORAGE_BASE_URL = __STORAGE_BASE_URL__;\nconst API_VERSION: ValidAPIVersion = 1;\n\nconst apiInstanceMap = new Map<string, ApiFetcher>();\n\nfunction getApiInstance(baseUrl: string, version: ValidAPIVersion) {\n\tif (!apiInstanceMap.has(`${baseUrl}--${version}`)) {\n\t\tapiInstanceMap.set(`${baseUrl}--${version}`, new ApiFetcher(baseUrl, version));\n\t}\n\treturn apiInstanceMap.get(`${baseUrl}--${version}`)!;\n}\n\n/**\n * Implementation of the Repo interface\n */\nclass RepoImpl implements Repo {\n\tprivate readonly api: ApiFetcher;\n\n\tconstructor(\n\t\tpublic readonly id: string,\n\t\tprivate readonly options: GitStorageOptions,\n\t\tprivate readonly generateJWT: (\n\t\t\trepoId: string,\n\t\t\toptions?: GetRemoteURLOptions,\n\t\t) => Promise<string>,\n\t) {\n\t\tthis.api = getApiInstance(\n\t\t\tthis.options.apiBaseUrl ?? API_BASE_URL,\n\t\t\tthis.options.apiVersion ?? API_VERSION,\n\t\t);\n\t}\n\n\tasync getRemoteURL(urlOptions?: GetRemoteURLOptions): Promise<string> {\n\t\tconst storageBaseUrl = this.options.storageBaseUrl ?? STORAGE_BASE_URL;\n\t\tconst url = new URL(`https://${this.options.name}.${storageBaseUrl}/${this.id}.git`);\n\t\turl.username = `t`;\n\t\turl.password = await this.generateJWT(this.id, urlOptions);\n\t\treturn url.toString();\n\t}\n\n\tasync getFile(options: GetFileOptions): Promise<GetFileResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tpath: options.path,\n\t\t};\n\n\t\tif (options.ref) {\n\t\t\tparams.ref = options.ref;\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/file', params }, jwt);\n\n\t\treturn (await response.json()) as GetFileResponse;\n\t}\n\n\tasync listFiles(options?: ListFilesOptions): Promise<ListFilesResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> | undefined = options?.ref\n\t\t\t? { ref: options.ref }\n\t\t\t: undefined;\n\t\tconst response = await this.api.get({ path: 'repos/files', params }, jwt);\n\n\t\treturn (await response.json()) as ListFilesResponse;\n\t}\n\n\tasync listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tlet params: Record<string, string> | undefined;\n\n\t\tif (options?.cursor || !options?.limit) {\n\t\t\tparams = {};\n\t\t\tif (options?.cursor) {\n\t\t\t\tparams.cursor = options.cursor;\n\t\t\t}\n\t\t\tif (typeof options?.limit == 'number') {\n\t\t\t\tparams.limit = options.limit.toString();\n\t\t\t}\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/branches', params }, jwt);\n\n\t\treturn (await response.json()) as ListBranchesResponse;\n\t}\n\n\tasync listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tlet params: Record<string, string> | undefined;\n\n\t\tif (options?.branch || options?.cursor || options?.limit) {\n\t\t\tparams = {};\n\t\t\tif (options?.branch) {\n\t\t\t\tparams.branch = options.branch;\n\t\t\t}\n\t\t\tif (options?.cursor) {\n\t\t\t\tparams.cursor = options.cursor;\n\t\t\t}\n\t\t\tif (typeof options?.limit == 'number') {\n\t\t\t\tparams.limit = options.limit.toString();\n\t\t\t}\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/commits', params }, jwt);\n\n\t\treturn (await response.json()) as ListCommitsResponse;\n\t}\n\n\tasync getBranchDiff(options: GetBranchDiffOptions): Promise<GetBranchDiffResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tbranch: options.branch,\n\t\t};\n\n\t\tif (options.base) {\n\t\t\tparams.base = options.base;\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/branches/diff', params }, jwt);\n\n\t\treturn (await response.json()) as GetBranchDiffResponse;\n\t}\n\n\tasync getCommitDiff(options: GetCommitDiffOptions): Promise<GetCommitDiffResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tsha: options.sha,\n\t\t};\n\n\t\tconst response = await this.api.get({ path: 'repos/diff', params }, jwt);\n\n\t\treturn (await response.json()) as GetCommitDiffResponse;\n\t}\n\n\tasync getCommit(options: GetCommitOptions): Promise<GetCommitResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\trepo: this.id,\n\t\t\tsha: options.sha,\n\t\t};\n\t\tconst response = await this.api.get({ path: 'commit', params }, jwt);\n\n\t\treturn (await response.json()) as GetCommitResponse;\n\t}\n\n\tasync repull(options: RepullOptions): Promise<void> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:write'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst body: Record<string, string> = {};\n\n\t\tif (options.ref) {\n\t\t\tbody.ref = options.ref;\n\t\t}\n\n\t\tconst response = await this.api.post({ path: 'repos/repull', body }, jwt);\n\n\t\tif (response.status !== 202) {\n\t\t\tthrow new Error(`Repull failed: ${response.status} ${await response.text()}`);\n\t\t}\n\n\t\treturn;\n\t}\n}\n\nexport class GitStorage {\n\tprivate static overrides: OverrideableGitStorageOptions = {};\n\tprivate options: GitStorageOptions;\n\tprivate api: ApiFetcher;\n\n\tconstructor(options: GitStorageOptions) {\n\t\tif (\n\t\t\t!options ||\n\t\t\toptions.name === undefined ||\n\t\t\toptions.key === undefined ||\n\t\t\toptions.name === null ||\n\t\t\toptions.key === null\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t'GitStorage requires a name and key. Please check your configuration and try again.',\n\t\t\t);\n\t\t}\n\n\t\tif (typeof options.name !== 'string' || options.name.trim() === '') {\n\t\t\tthrow new Error('GitStorage name must be a non-empty string.');\n\t\t}\n\n\t\tif (typeof options.key !== 'string' || options.key.trim() === '') {\n\t\t\tthrow new Error('GitStorage key must be a non-empty string.');\n\t\t}\n\n\t\tconst resolvedApiBaseUrl =\n\t\t\toptions.apiBaseUrl ?? GitStorage.overrides.apiBaseUrl ?? API_BASE_URL;\n\t\tconst resolvedApiVersion = options.apiVersion ?? GitStorage.overrides.apiVersion ?? API_VERSION;\n\t\tconst resolvedStorageBaseUrl =\n\t\t\toptions.storageBaseUrl ?? GitStorage.overrides.storageBaseUrl ?? STORAGE_BASE_URL;\n\n\t\tthis.api = getApiInstance(resolvedApiBaseUrl, resolvedApiVersion);\n\n\t\tthis.options = {\n\t\t\tkey: options.key,\n\t\t\tname: options.name,\n\t\t\tapiBaseUrl: resolvedApiBaseUrl,\n\t\t\tapiVersion: resolvedApiVersion,\n\t\t\tstorageBaseUrl: resolvedStorageBaseUrl,\n\t\t};\n\t}\n\n\tstatic override(options: OverrideableGitStorageOptions): void {\n\t\tthis.overrides = Object.assign({}, this.overrides, options);\n\t}\n\n\t/**\n\t * Create a new repository\n\t * @returns The created repository\n\t */\n\tasync createRepo(options?: CreateRepoOptions): Promise<Repo> {\n\t\tconst repoId = options?.id || crypto.randomUUID();\n\n\t\tconst jwt = await this.generateJWT(repoId, {\n\t\t\tpermissions: ['repo:write'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst baseRepoOptions = options?.baseRepo\n\t\t\t? {\n\t\t\t\t\tprovider: 'github',\n\t\t\t\t\t...snakecaseKeys(options.baseRepo as unknown as Record<string, unknown>),\n\t\t\t\t}\n\t\t\t: null;\n\n\t\t// Default defaultBranch to 'main' if not provided\n\t\tconst defaultBranch = options?.defaultBranch ?? 'main';\n\n\t\tconst createRepoPath =\n\t\t\tbaseRepoOptions || defaultBranch\n\t\t\t\t? {\n\t\t\t\t\t\tpath: 'repos',\n\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t...(baseRepoOptions && { base_repo: baseRepoOptions }),\n\t\t\t\t\t\t\tdefault_branch: defaultBranch,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: 'repos';\n\n\t\t// Allow 409 so we can map it to a clearer error message\n\t\tconst resp = await this.api.post(createRepoPath, jwt, { allowedStatus: [409] });\n\t\tif (resp.status === 409) {\n\t\t\tthrow new Error('Repository already exists');\n\t\t}\n\n\t\treturn new RepoImpl(repoId, this.options, this.generateJWT.bind(this));\n\t}\n\n\t/**\n\t * Find a repository by ID\n\t * @param options The search options\n\t * @returns The found repository\n\t */\n\tasync findOne(options: FindOneOptions): Promise<Repo | null> {\n\t\tconst jwt = await this.generateJWT(options.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: 1 * 60 * 60,\n\t\t});\n\n\t\t// Allow 404 to indicate \"not found\" without throwing\n\t\tconst resp = await this.api.get('repo', jwt, { allowedStatus: [404] });\n\t\tif (resp.status === 404) {\n\t\t\treturn null;\n\t\t}\n\t\t// On 200, we could validate response, but RepoImpl only needs the repo URL/id\n\t\t// const body = await resp.json(); // not required for now\n\t\treturn new RepoImpl(options.id, this.options, this.generateJWT.bind(this));\n\t}\n\n\t/**\n\t * Get the current configuration\n\t * @returns The client configuration\n\t */\n\tgetConfig(): GitStorageOptions {\n\t\treturn { ...this.options };\n\t}\n\n\t/**\n\t * Generate a JWT token for git storage URL authentication\n\t * @private\n\t */\n\tprivate async generateJWT(repoId: string, options?: GetRemoteURLOptions): Promise<string> {\n\t\t// Default permissions and TTL\n\t\tconst permissions = options?.permissions || ['git:write', 'git:read'];\n\t\tconst ttl = options?.ttl || 365 * 24 * 60 * 60; // 1 year in seconds\n\n\t\t// Create the JWT payload\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst payload = {\n\t\t\tiss: this.options.name,\n\t\t\tsub: '@pierre/storage',\n\t\t\trepo: repoId,\n\t\t\tscopes: permissions,\n\t\t\tiat: now,\n\t\t\texp: now + ttl,\n\t\t};\n\n\t\t// Sign the JWT with the key as the secret\n\t\t// Using HS256 for symmetric signing with the key\n\t\tconst key = await importPKCS8(this.options.key, 'ES256');\n\t\t// Sign the JWT with the key as the secret\n\t\tconst jwt = await new SignJWT(payload)\n\t\t\t.setProtectedHeader({ alg: 'ES256', typ: 'JWT' })\n\t\t\t.sign(key);\n\n\t\treturn jwt;\n\t}\n}\n\n// Export a default client factory\nexport function createClient(options: GitStorageOptions): GitStorage {\n\treturn new GitStorage(options);\n}\n\n// Type alias for backward compatibility\nexport type StorageOptions = GitStorageOptions;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/fetch.ts","../src/util.ts","../src/webhook.ts","../src/index.ts"],"names":["API_BASE_URL","crypto"],"mappings":"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","file":"index.js","sourcesContent":["import type { ValidAPIVersion, ValidMethod, ValidPath } from './types';\n\ninterface RequestOptions {\n\tallowedStatus?: number[];\n}\n\nexport class ApiFetcher {\n\tconstructor(\n\t\tprivate readonly API_BASE_URL: string,\n\t\tprivate readonly version: ValidAPIVersion,\n\t) {\n\t\tconsole.log('api fetcher created', API_BASE_URL, version);\n\t}\n\n\tprivate getBaseUrl() {\n\t\treturn `${this.API_BASE_URL}/api/v${this.version}`;\n\t}\n\n\tprivate getRequestUrl(path: ValidPath) {\n\t\tif (typeof path === 'string') {\n\t\t\treturn `${this.getBaseUrl()}/${path}`;\n\t\t} else if (path.params) {\n\t\t\tconst paramStr = new URLSearchParams(path.params).toString();\n\t\t\treturn `${this.getBaseUrl()}/${path.path}${paramStr ? `?${paramStr}` : ''}`;\n\t\t} else {\n\t\t\treturn `${this.getBaseUrl()}/${path.path}`;\n\t\t}\n\t}\n\n\tprivate async fetch(path: ValidPath, method: ValidMethod, jwt: string, options?: RequestOptions) {\n\t\tconst requestUrl = this.getRequestUrl(path);\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${jwt}`,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t};\n\n\t\tif (method !== 'GET' && typeof path !== 'string' && path.body) {\n\t\t\trequestOptions.body = JSON.stringify(path.body);\n\t\t}\n\n\t\tconst response = await fetch(requestUrl, requestOptions);\n\n\t\tif (!response.ok) {\n\t\t\tconst allowed = options?.allowedStatus ?? [];\n\t\t\tif (!allowed.includes(response.status)) {\n\t\t\t\tthrow new Error(`Failed to fetch ${method} ${requestUrl}: ${response.statusText}`);\n\t\t\t}\n\t\t}\n\t\treturn response;\n\t}\n\n\tasync get(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'GET', jwt, options);\n\t}\n\n\tasync post(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'POST', jwt, options);\n\t}\n\n\tasync put(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'PUT', jwt, options);\n\t}\n\n\tasync delete(path: ValidPath, jwt: string, options?: RequestOptions) {\n\t\treturn this.fetch(path, 'DELETE', jwt, options);\n\t}\n}\n","export function timingSafeEqual(a: string | Uint8Array, b: string | Uint8Array): boolean {\n\tconst bufferA = typeof a === 'string' ? new TextEncoder().encode(a) : a;\n\tconst bufferB = typeof b === 'string' ? new TextEncoder().encode(b) : b;\n\n\tif (bufferA.length !== bufferB.length) return false;\n\n\tlet result = 0;\n\tfor (let i = 0; i < bufferA.length; i++) {\n\t\tresult |= bufferA[i] ^ bufferB[i];\n\t}\n\treturn result === 0;\n}\n\nexport async function getEnvironmentCrypto() {\n\tif (!globalThis.crypto) {\n\t\tconst { webcrypto } = await import('node:crypto');\n\t\treturn webcrypto;\n\t}\n\treturn globalThis.crypto;\n}\n\nexport async function createHmac(algorithm: string, secret: string, data: string): Promise<string> {\n\tif (algorithm !== 'sha256') {\n\t\tthrow new Error('Only sha256 algorithm is supported');\n\t}\n\tif (!secret || secret.length === 0) {\n\t\tthrow new Error('Secret is required');\n\t}\n\n\tconst crypto = await getEnvironmentCrypto();\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tencoder.encode(secret),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\n\tconst signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));\n\treturn Array.from(new Uint8Array(signature))\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n\n// Keep the legacy async function for backward compatibility\nexport async function createHmacAsync(secret: string, data: string): Promise<string> {\n\tconst crypto = await getEnvironmentCrypto();\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tencoder.encode(secret),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\n\tconst signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));\n\treturn Array.from(new Uint8Array(signature))\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n","/**\n * Webhook validation utilities for Pierre Git Storage\n */\n\nimport type {\n\tParsedWebhookSignature,\n\tWebhookEventPayload,\n\tWebhookValidationOptions,\n\tWebhookValidationResult,\n} from './types';\n\nimport { createHmac, timingSafeEqual } from './util';\n\nconst DEFAULT_MAX_AGE_SECONDS = 300; // 5 minutes\n\n/**\n * Parse the X-Pierre-Signature header\n * Format: t=<timestamp>,sha256=<signature>\n */\nexport function parseSignatureHeader(header: string): ParsedWebhookSignature | null {\n\tif (!header || typeof header !== 'string') {\n\t\treturn null;\n\t}\n\n\tlet timestamp = '';\n\tlet signature = '';\n\n\t// Split by comma and parse each element\n\tconst elements = header.split(',');\n\tfor (const element of elements) {\n\t\tconst trimmedElement = element.trim();\n\t\tconst parts = trimmedElement.split('=', 2);\n\t\tif (parts.length !== 2) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst [key, value] = parts;\n\t\tswitch (key) {\n\t\t\tcase 't':\n\t\t\t\ttimestamp = value;\n\t\t\t\tbreak;\n\t\t\tcase 'sha256':\n\t\t\t\tsignature = value;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!timestamp || !signature) {\n\t\treturn null;\n\t}\n\n\treturn { timestamp, signature };\n}\n\n/**\n * Validate a webhook signature and timestamp\n *\n * @param payload - The raw webhook payload (request body)\n * @param signatureHeader - The X-Pierre-Signature header value\n * @param secret - The webhook secret for HMAC verification\n * @param options - Validation options\n * @returns Validation result with details\n *\n * @example\n * ```typescript\n * const result = await validateWebhookSignature(\n * requestBody,\n * request.headers['x-pierre-signature'],\n * webhookSecret\n * );\n *\n * if (!result.valid) {\n * console.error('Invalid webhook:', result.error);\n * return;\n * }\n * ```\n */\nexport async function validateWebhookSignature(\n\tpayload: string | Buffer,\n\tsignatureHeader: string,\n\tsecret: string,\n\toptions: WebhookValidationOptions = {},\n): Promise<WebhookValidationResult> {\n\tif (!secret || secret.length === 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Empty secret is not allowed',\n\t\t};\n\t}\n\n\t// Parse the signature header\n\tconst parsed = parseSignatureHeader(signatureHeader);\n\tif (!parsed) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature header format',\n\t\t};\n\t}\n\n\t// Parse timestamp\n\tconst timestamp = Number.parseInt(parsed.timestamp, 10);\n\tif (isNaN(timestamp)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid timestamp in signature',\n\t\t};\n\t}\n\n\t// Validate timestamp age (prevent replay attacks)\n\tconst maxAge = options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;\n\tif (maxAge > 0) {\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst age = now - timestamp;\n\n\t\tif (age > maxAge) {\n\t\t\treturn {\n\t\t\t\tvalid: false,\n\t\t\t\terror: `Webhook timestamp too old (${age} seconds)`,\n\t\t\t\ttimestamp,\n\t\t\t};\n\t\t}\n\n\t\t// Also reject timestamps from the future (clock skew tolerance of 60 seconds)\n\t\tif (age < -60) {\n\t\t\treturn {\n\t\t\t\tvalid: false,\n\t\t\t\terror: 'Webhook timestamp is in the future',\n\t\t\t\ttimestamp,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Convert payload to string if it's a Buffer\n\tconst payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n\n\t// Compute expected signature\n\t// Format: HMAC-SHA256(secret, timestamp + \".\" + payload)\n\tconst signedData = `${parsed.timestamp}.${payloadStr}`;\n\tconst expectedSignature = await createHmac('sha256', secret, signedData);\n\n\t// Compare signatures using constant-time comparison\n\tconst expectedBuffer = Buffer.from(expectedSignature);\n\tconst actualBuffer = Buffer.from(parsed.signature);\n\n\t// Ensure both buffers are the same length for timing-safe comparison\n\tif (expectedBuffer.length !== actualBuffer.length) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature',\n\t\t\ttimestamp,\n\t\t};\n\t}\n\n\tconst signaturesMatch = timingSafeEqual(expectedBuffer, actualBuffer);\n\tif (!signaturesMatch) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid signature',\n\t\t\ttimestamp,\n\t\t};\n\t}\n\n\treturn {\n\t\tvalid: true,\n\t\ttimestamp,\n\t};\n}\n\n/**\n * Validate a webhook request\n *\n * This is a convenience function that validates the signature and parses the payload.\n *\n * @param payload - The raw webhook payload (request body)\n * @param headers - The request headers (must include x-pierre-signature and x-pierre-event)\n * @param secret - The webhook secret for HMAC verification\n * @param options - Validation options\n * @returns The parsed webhook payload if valid, or validation error\n *\n * @example\n * ```typescript\n * const result = await validateWebhook(\n * request.body,\n * request.headers,\n * process.env.WEBHOOK_SECRET\n * );\n *\n * if (!result.valid) {\n * return new Response('Invalid webhook', { status: 401 });\n * }\n *\n * // Type-safe access to the webhook payload\n * console.log('Push event:', result.payload);\n * ```\n */\nexport async function validateWebhook(\n\tpayload: string | Buffer,\n\theaders: Record<string, string | string[] | undefined>,\n\tsecret: string,\n\toptions: WebhookValidationOptions = {},\n): Promise<WebhookValidationResult & { payload?: WebhookEventPayload }> {\n\t// Get signature header\n\tconst signatureHeader = headers['x-pierre-signature'] || headers['X-Pierre-Signature'];\n\tif (!signatureHeader || Array.isArray(signatureHeader)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Missing or invalid X-Pierre-Signature header',\n\t\t};\n\t}\n\n\t// Get event type header\n\tconst eventType = headers['x-pierre-event'] || headers['X-Pierre-Event'];\n\tif (!eventType || Array.isArray(eventType)) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Missing or invalid X-Pierre-Event header',\n\t\t};\n\t}\n\n\t// Validate signature\n\tconst validationResult = await validateWebhookSignature(\n\t\tpayload,\n\t\tsignatureHeader,\n\t\tsecret,\n\t\toptions,\n\t);\n\n\tif (!validationResult.valid) {\n\t\treturn validationResult;\n\t}\n\n\t// Parse payload\n\tconst payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n\tlet parsedPayload: WebhookEventPayload;\n\ttry {\n\t\tparsedPayload = JSON.parse(payloadStr);\n\t} catch {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: 'Invalid JSON payload',\n\t\t\ttimestamp: validationResult.timestamp,\n\t\t};\n\t}\n\n\treturn {\n\t\tvalid: true,\n\t\teventType,\n\t\ttimestamp: validationResult.timestamp,\n\t\tpayload: parsedPayload,\n\t};\n}\n","/**\n * Pierre Git Storage SDK\n *\n * A TypeScript SDK for interacting with Pierre's git storage system\n */\n\nimport { importPKCS8, SignJWT } from 'jose';\nimport snakecaseKeys from 'snakecase-keys';\nimport { ApiFetcher } from './fetch';\nimport type {\n\tCreateRepoOptions,\n\tFindOneOptions,\n\tGetBranchDiffOptions,\n\tGetBranchDiffResponse,\n\tGetCommitDiffOptions,\n\tGetCommitDiffResponse,\n\tGetCommitOptions,\n\tGetCommitResponse,\n\tGetFileOptions,\n\tGetRemoteURLOptions,\n\tGitStorageOptions,\n\tListBranchesOptions,\n\tListBranchesResponse,\n\tListCommitsOptions,\n\tListCommitsResponse,\n\tListFilesOptions,\n\tListFilesResponse,\n\tOverrideableGitStorageOptions,\n\tRepo,\n\tRepullOptions,\n\tValidAPIVersion,\n} from './types';\n\n/**\n * Type definitions for Pierre Git Storage SDK\n */\n\n// Import additional types from types.ts\nexport * from './types';\n\n// Export webhook validation utilities\nexport { parseSignatureHeader, validateWebhook, validateWebhookSignature } from './webhook';\n\n/**\n * Git Storage API\n */\n\ndeclare const __STORAGE_BASE_URL__: string;\ndeclare const __API_BASE_URL__: string;\n\nconst API_BASE_URL = __API_BASE_URL__;\nconst STORAGE_BASE_URL = __STORAGE_BASE_URL__;\nconst API_VERSION: ValidAPIVersion = 1;\n\nconst apiInstanceMap = new Map<string, ApiFetcher>();\n\nfunction getApiInstance(baseUrl: string, version: ValidAPIVersion) {\n\tif (!apiInstanceMap.has(`${baseUrl}--${version}`)) {\n\t\tapiInstanceMap.set(`${baseUrl}--${version}`, new ApiFetcher(baseUrl, version));\n\t}\n\treturn apiInstanceMap.get(`${baseUrl}--${version}`)!;\n}\n\n/**\n * Implementation of the Repo interface\n */\nclass RepoImpl implements Repo {\n\tprivate readonly api: ApiFetcher;\n\n\tconstructor(\n\t\tpublic readonly id: string,\n\t\tprivate readonly options: GitStorageOptions,\n\t\tprivate readonly generateJWT: (\n\t\t\trepoId: string,\n\t\t\toptions?: GetRemoteURLOptions,\n\t\t) => Promise<string>,\n\t) {\n\t\tthis.api = getApiInstance(\n\t\t\tthis.options.apiBaseUrl ?? API_BASE_URL,\n\t\t\tthis.options.apiVersion ?? API_VERSION,\n\t\t);\n\t}\n\n\tasync getRemoteURL(urlOptions?: GetRemoteURLOptions): Promise<string> {\n\t\tconst storageBaseUrl = this.options.storageBaseUrl ?? STORAGE_BASE_URL;\n\t\tconst url = new URL(`https://${this.options.name}.${storageBaseUrl}/${this.id}.git`);\n\t\turl.username = `t`;\n\t\turl.password = await this.generateJWT(this.id, urlOptions);\n\t\treturn url.toString();\n\t}\n\n\tasync getFileStream(options: GetFileOptions): Promise<Response> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tpath: options.path,\n\t\t};\n\n\t\tif (options.ref) {\n\t\t\tparams.ref = options.ref;\n\t\t}\n\n\t\t// Return the raw fetch Response for streaming\n\t\treturn this.api.get({ path: 'repos/file', params }, jwt);\n\t}\n\n\tasync listFiles(options?: ListFilesOptions): Promise<ListFilesResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> | undefined = options?.ref\n\t\t\t? { ref: options.ref }\n\t\t\t: undefined;\n\t\tconst response = await this.api.get({ path: 'repos/files', params }, jwt);\n\n\t\treturn (await response.json()) as ListFilesResponse;\n\t}\n\n\tasync listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tlet params: Record<string, string> | undefined;\n\n\t\tif (options?.cursor || !options?.limit) {\n\t\t\tparams = {};\n\t\t\tif (options?.cursor) {\n\t\t\t\tparams.cursor = options.cursor;\n\t\t\t}\n\t\t\tif (typeof options?.limit == 'number') {\n\t\t\t\tparams.limit = options.limit.toString();\n\t\t\t}\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/branches', params }, jwt);\n\n\t\treturn (await response.json()) as ListBranchesResponse;\n\t}\n\n\tasync listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tlet params: Record<string, string> | undefined;\n\n\t\tif (options?.branch || options?.cursor || options?.limit) {\n\t\t\tparams = {};\n\t\t\tif (options?.branch) {\n\t\t\t\tparams.branch = options.branch;\n\t\t\t}\n\t\t\tif (options?.cursor) {\n\t\t\t\tparams.cursor = options.cursor;\n\t\t\t}\n\t\t\tif (typeof options?.limit == 'number') {\n\t\t\t\tparams.limit = options.limit.toString();\n\t\t\t}\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/commits', params }, jwt);\n\n\t\treturn (await response.json()) as ListCommitsResponse;\n\t}\n\n\tasync getBranchDiff(options: GetBranchDiffOptions): Promise<GetBranchDiffResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tbranch: options.branch,\n\t\t};\n\n\t\tif (options.base) {\n\t\t\tparams.base = options.base;\n\t\t}\n\n\t\tconst response = await this.api.get({ path: 'repos/branches/diff', params }, jwt);\n\n\t\treturn (await response.json()) as GetBranchDiffResponse;\n\t}\n\n\tasync getCommitDiff(options: GetCommitDiffOptions): Promise<GetCommitDiffResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\tsha: options.sha,\n\t\t};\n\n\t\tconst response = await this.api.get({ path: 'repos/diff', params }, jwt);\n\n\t\treturn (await response.json()) as GetCommitDiffResponse;\n\t}\n\n\tasync getCommit(options: GetCommitOptions): Promise<GetCommitResponse> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst params: Record<string, string> = {\n\t\t\trepo: this.id,\n\t\t\tsha: options.sha,\n\t\t};\n\t\tconst response = await this.api.get({ path: 'commit', params }, jwt);\n\n\t\treturn (await response.json()) as GetCommitResponse;\n\t}\n\n\tasync repull(options: RepullOptions): Promise<void> {\n\t\tconst jwt = await this.generateJWT(this.id, {\n\t\t\tpermissions: ['git:write'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst body: Record<string, string> = {};\n\n\t\tif (options.ref) {\n\t\t\tbody.ref = options.ref;\n\t\t}\n\n\t\tconst response = await this.api.post({ path: 'repos/repull', body }, jwt);\n\n\t\tif (response.status !== 202) {\n\t\t\tthrow new Error(`Repull failed: ${response.status} ${await response.text()}`);\n\t\t}\n\n\t\treturn;\n\t}\n}\n\nexport class GitStorage {\n\tprivate static overrides: OverrideableGitStorageOptions = {};\n\tprivate options: GitStorageOptions;\n\tprivate api: ApiFetcher;\n\n\tconstructor(options: GitStorageOptions) {\n\t\tif (\n\t\t\t!options ||\n\t\t\toptions.name === undefined ||\n\t\t\toptions.key === undefined ||\n\t\t\toptions.name === null ||\n\t\t\toptions.key === null\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t'GitStorage requires a name and key. Please check your configuration and try again.',\n\t\t\t);\n\t\t}\n\n\t\tif (typeof options.name !== 'string' || options.name.trim() === '') {\n\t\t\tthrow new Error('GitStorage name must be a non-empty string.');\n\t\t}\n\n\t\tif (typeof options.key !== 'string' || options.key.trim() === '') {\n\t\t\tthrow new Error('GitStorage key must be a non-empty string.');\n\t\t}\n\n\t\tconst resolvedApiBaseUrl =\n\t\t\toptions.apiBaseUrl ?? GitStorage.overrides.apiBaseUrl ?? API_BASE_URL;\n\t\tconst resolvedApiVersion = options.apiVersion ?? GitStorage.overrides.apiVersion ?? API_VERSION;\n\t\tconst resolvedStorageBaseUrl =\n\t\t\toptions.storageBaseUrl ?? GitStorage.overrides.storageBaseUrl ?? STORAGE_BASE_URL;\n\n\t\tthis.api = getApiInstance(resolvedApiBaseUrl, resolvedApiVersion);\n\n\t\tthis.options = {\n\t\t\tkey: options.key,\n\t\t\tname: options.name,\n\t\t\tapiBaseUrl: resolvedApiBaseUrl,\n\t\t\tapiVersion: resolvedApiVersion,\n\t\t\tstorageBaseUrl: resolvedStorageBaseUrl,\n\t\t};\n\t}\n\n\tstatic override(options: OverrideableGitStorageOptions): void {\n\t\tthis.overrides = Object.assign({}, this.overrides, options);\n\t}\n\n\t/**\n\t * Create a new repository\n\t * @returns The created repository\n\t */\n\tasync createRepo(options?: CreateRepoOptions): Promise<Repo> {\n\t\tconst repoId = options?.id || crypto.randomUUID();\n\n\t\tconst jwt = await this.generateJWT(repoId, {\n\t\t\tpermissions: ['repo:write'],\n\t\t\tttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst baseRepoOptions = options?.baseRepo\n\t\t\t? {\n\t\t\t\t\tprovider: 'github',\n\t\t\t\t\t...snakecaseKeys(options.baseRepo as unknown as Record<string, unknown>),\n\t\t\t\t}\n\t\t\t: null;\n\n\t\t// Default defaultBranch to 'main' if not provided\n\t\tconst defaultBranch = options?.defaultBranch ?? 'main';\n\n\t\tconst createRepoPath =\n\t\t\tbaseRepoOptions || defaultBranch\n\t\t\t\t? {\n\t\t\t\t\t\tpath: 'repos',\n\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t...(baseRepoOptions && { base_repo: baseRepoOptions }),\n\t\t\t\t\t\t\tdefault_branch: defaultBranch,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: 'repos';\n\n\t\t// Allow 409 so we can map it to a clearer error message\n\t\tconst resp = await this.api.post(createRepoPath, jwt, { allowedStatus: [409] });\n\t\tif (resp.status === 409) {\n\t\t\tthrow new Error('Repository already exists');\n\t\t}\n\n\t\treturn new RepoImpl(repoId, this.options, this.generateJWT.bind(this));\n\t}\n\n\t/**\n\t * Find a repository by ID\n\t * @param options The search options\n\t * @returns The found repository\n\t */\n\tasync findOne(options: FindOneOptions): Promise<Repo | null> {\n\t\tconst jwt = await this.generateJWT(options.id, {\n\t\t\tpermissions: ['git:read'],\n\t\t\tttl: 1 * 60 * 60,\n\t\t});\n\n\t\t// Allow 404 to indicate \"not found\" without throwing\n\t\tconst resp = await this.api.get('repo', jwt, { allowedStatus: [404] });\n\t\tif (resp.status === 404) {\n\t\t\treturn null;\n\t\t}\n\t\t// On 200, we could validate response, but RepoImpl only needs the repo URL/id\n\t\t// const body = await resp.json(); // not required for now\n\t\treturn new RepoImpl(options.id, this.options, this.generateJWT.bind(this));\n\t}\n\n\t/**\n\t * Get the current configuration\n\t * @returns The client configuration\n\t */\n\tgetConfig(): GitStorageOptions {\n\t\treturn { ...this.options };\n\t}\n\n\t/**\n\t * Generate a JWT token for git storage URL authentication\n\t * @private\n\t */\n\tprivate async generateJWT(repoId: string, options?: GetRemoteURLOptions): Promise<string> {\n\t\t// Default permissions and TTL\n\t\tconst permissions = options?.permissions || ['git:write', 'git:read'];\n\t\tconst ttl = options?.ttl || 365 * 24 * 60 * 60; // 1 year in seconds\n\n\t\t// Create the JWT payload\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst payload = {\n\t\t\tiss: this.options.name,\n\t\t\tsub: '@pierre/storage',\n\t\t\trepo: repoId,\n\t\t\tscopes: permissions,\n\t\t\tiat: now,\n\t\t\texp: now + ttl,\n\t\t};\n\n\t\t// Sign the JWT with the key as the secret\n\t\t// Using HS256 for symmetric signing with the key\n\t\tconst key = await importPKCS8(this.options.key, 'ES256');\n\t\t// Sign the JWT with the key as the secret\n\t\tconst jwt = await new SignJWT(payload)\n\t\t\t.setProtectedHeader({ alg: 'ES256', typ: 'JWT' })\n\t\t\t.sign(key);\n\n\t\treturn jwt;\n\t}\n}\n\n// Export a default client factory\nexport function createClient(options: GitStorageOptions): GitStorage {\n\treturn new GitStorage(options);\n}\n\n// Type alias for backward compatibility\nexport type StorageOptions = GitStorageOptions;\n"]}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -17,7 +17,6 @@ import type {
|
|
|
17
17
|
GetCommitOptions,
|
|
18
18
|
GetCommitResponse,
|
|
19
19
|
GetFileOptions,
|
|
20
|
-
GetFileResponse,
|
|
21
20
|
GetRemoteURLOptions,
|
|
22
21
|
GitStorageOptions,
|
|
23
22
|
ListBranchesOptions,
|
|
@@ -90,7 +89,7 @@ class RepoImpl implements Repo {
|
|
|
90
89
|
return url.toString();
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
async
|
|
92
|
+
async getFileStream(options: GetFileOptions): Promise<Response> {
|
|
94
93
|
const jwt = await this.generateJWT(this.id, {
|
|
95
94
|
permissions: ['git:read'],
|
|
96
95
|
ttl: options?.ttl ?? 1 * 60 * 60, // 1hr in seconds
|
|
@@ -104,9 +103,8 @@ class RepoImpl implements Repo {
|
|
|
104
103
|
params.ref = options.ref;
|
|
105
104
|
}
|
|
106
105
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return (await response.json()) as GetFileResponse;
|
|
106
|
+
// Return the raw fetch Response for streaming
|
|
107
|
+
return this.api.get({ path: 'repos/file', params }, jwt);
|
|
110
108
|
}
|
|
111
109
|
|
|
112
110
|
async listFiles(options?: ListFilesOptions): Promise<ListFilesResponse> {
|
package/src/types.ts
CHANGED
|
@@ -24,7 +24,8 @@ export interface GetRemoteURLOptions {
|
|
|
24
24
|
export interface Repo {
|
|
25
25
|
id: string;
|
|
26
26
|
getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
getFileStream(options: GetFileOptions): Promise<Response>;
|
|
28
29
|
listFiles(options?: ListFilesOptions): Promise<ListFilesResponse>;
|
|
29
30
|
listBranches(options?: ListBranchesOptions): Promise<ListBranchesResponse>;
|
|
30
31
|
listCommits(options?: ListCommitsOptions): Promise<ListCommitsResponse>;
|
|
@@ -79,14 +80,6 @@ export interface GetFileOptions extends GitStorageInvocationOptions {
|
|
|
79
80
|
ref?: string;
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
export interface GetFileResponse {
|
|
83
|
-
path: string;
|
|
84
|
-
ref: string;
|
|
85
|
-
content: string;
|
|
86
|
-
size: number;
|
|
87
|
-
is_binary: boolean;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
83
|
export interface RepullOptions extends GitStorageInvocationOptions {
|
|
91
84
|
ref?: string;
|
|
92
85
|
}
|