@omnistreamai/data-adapter-webdav 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/webdav-adapter.ts +5 -7
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/webdav-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;AAYA;AACe,cADF,aAAA,YAAyB,aACvB,CAAA;EAQO,SAAA,IAAA,GARP,WAAA,CAAA,MAAA;EAqHV,SAAA,IAAA,GAAA,eAAA;EA4BiB,QAAA,OAAA;EAEZ;;;EAiBe,UAAA,CAAA,OAAA,EA5JH,aA4JG,CAAA,EAAA,IAAA;EAGP;;;EAEb,QAAA,UAAA;EAwBA;;;EAeA,QAAA,QAAA;EAmBqB;;;EAIG,QAAA,OAAA;EAAhB;;;EA0H6B,SAAA,CAAA,SAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,MAAA,EAAA,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA5OrC,OA4OqC,CAAA,IAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/webdav-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;AAYA;AACe,cADF,aAAA,YAAyB,aACvB,CAAA;EAQO,SAAA,IAAA,GARP,WAAA,CAAA,MAAA;EAqHV,SAAA,IAAA,GAAA,eAAA;EA4BiB,QAAA,OAAA;EAEZ;;;EAiBe,UAAA,CAAA,OAAA,EA5JH,aA4JG,CAAA,EAAA,IAAA;EAGP;;;EAEb,QAAA,UAAA;EAwBA;;;EAeA,QAAA,QAAA;EAmBqB;;;EAIG,QAAA,OAAA;EAAhB;;;EA0H6B,SAAA,CAAA,SAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,MAAA,EAAA,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA5OrC,OA4OqC,CAAA,IAAA,CAAA;EAiDhB;;;gBAjQJ,kDAEZ,oBAEL,QAAQ;;;;mBAeY,8DAGf,QAAQ,qBAEb,QAAQ;;;;0DAwBR;;;;oBAWqB,0EAIrB,QAAQ;;;;oBAmBa,sDAEb,aAAa,sBAErB,QAAQ,gBAAgB;;;;;;;;;;;;4BA8GK;;;;gCAYQ;;;;oBAiDhB"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/webdav-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;AAYA;AACe,cADF,aAAA,YAAyB,aACvB,CAAA;EAQO,SAAA,IAAA,GARP,WAAA,CAAA,MAAA;EAqHV,SAAA,IAAA,GAAA,eAAA;EA4BiB,QAAA,OAAA;EAEZ;;;EAiBe,UAAA,CAAA,OAAA,EA5JH,aA4JG,CAAA,EAAA,IAAA;EAGP;;;EAEb,QAAA,UAAA;EAwBA;;;EAeA,QAAA,QAAA;EAmBqB;;;EAIG,QAAA,OAAA;EAAhB;;;EA0H6B,SAAA,CAAA,SAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,MAAA,EAAA,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA5OrC,OA4OqC,CAAA,IAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/webdav-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;AAYA;AACe,cADF,aAAA,YAAyB,aACvB,CAAA;EAQO,SAAA,IAAA,GARP,WAAA,CAAA,MAAA;EAqHV,SAAA,IAAA,GAAA,eAAA;EA4BiB,QAAA,OAAA;EAEZ;;;EAiBe,UAAA,CAAA,OAAA,EA5JH,aA4JG,CAAA,EAAA,IAAA;EAGP;;;EAEb,QAAA,UAAA;EAwBA;;;EAeA,QAAA,QAAA;EAmBqB;;;EAIG,QAAA,OAAA;EAAhB;;;EA0H6B,SAAA,CAAA,SAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,MAAA,EAAA,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA5OrC,OA4OqC,CAAA,IAAA,CAAA;EAiDhB;;;gBAjQJ,kDAEZ,oBAEL,QAAQ;;;;mBAeY,8DAGf,QAAQ,qBAEb,QAAQ;;;;0DAwBR;;;;oBAWqB,0EAIrB,QAAQ;;;;oBAmBa,sDAEb,aAAa,sBAErB,QAAQ,gBAAgB;;;;;;;;;;;;4BA8GK;;;;gCAYQ;;;;oBAiDhB"}
|
package/dist/index.js
CHANGED
|
@@ -135,7 +135,7 @@ var WebDAVAdapter = class {
|
|
|
135
135
|
const files = await this.listDirectory(storeName);
|
|
136
136
|
const allData = [];
|
|
137
137
|
for (const file of files) try {
|
|
138
|
-
const data = await this.request(this.buildUrl(file), { method: "GET" });
|
|
138
|
+
const data = await this.request(this.buildUrl(storeName, file), { method: "GET" });
|
|
139
139
|
if (data) allData.push(data);
|
|
140
140
|
} catch {}
|
|
141
141
|
let filteredData = allData;
|
|
@@ -216,10 +216,10 @@ var WebDAVAdapter = class {
|
|
|
216
216
|
const fullPath = match[1] || "";
|
|
217
217
|
let relativePath = "";
|
|
218
218
|
try {
|
|
219
|
-
relativePath = new URL(fullPath).pathname
|
|
220
|
-
} catch {
|
|
221
|
-
|
|
222
|
-
|
|
219
|
+
relativePath = new URL(fullPath).pathname;
|
|
220
|
+
} catch {}
|
|
221
|
+
const pathRegex = /* @__PURE__ */ new RegExp(`^/*${path}`);
|
|
222
|
+
relativePath = fullPath.replace(basePath, "").replace(pathRegex, "").replace(/^\//, "");
|
|
223
223
|
if (relativePath && relativePath !== path.replace(/^\//, "")) files.push(relativePath);
|
|
224
224
|
}
|
|
225
225
|
return files;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["AdapterType","headers: Record<string, string>","AuthType","allData: T[]","files: string[]"],"sources":["../src/webdav-adapter.ts"],"sourcesContent":["import {\n AdapterType,\n type RemoteAdapter,\n type QueryOptions,\n type PaginatedResult,\n type ServiceConfig,\n AuthType,\n} from \"@omnistreamai/data-core\";\n\n/**\n * WebDAV adapter implementation\n */\nexport class WebDAVAdapter implements RemoteAdapter {\n readonly type = AdapterType.Remote;\n readonly name = \"WebDAVAdapter\";\n\n private service: ServiceConfig | null = null;\n\n /**\n * Set service configuration\n */\n setService(service: ServiceConfig): void {\n this.service = service;\n }\n\n /**\n * Get request headers\n */\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (!this.service?.authentication) {\n return headers;\n }\n\n const { authentication } = this.service;\n\n switch (authentication.authType) {\n case AuthType.Token:\n if (authentication.token) {\n headers[\"Authorization\"] =\n `${authentication.token.token_type} ${authentication.token.access_token}`;\n }\n break;\n case AuthType.Bearer:\n if (authentication.bearer) {\n headers[\"Authorization\"] = `Bearer ${authentication.bearer}`;\n }\n break;\n case AuthType.Basic:\n if (authentication.username && authentication.password) {\n const credentials = btoa(\n `${authentication.username}:${authentication.password}`,\n );\n headers[\"Authorization\"] = `Basic ${credentials}`;\n }\n break;\n }\n\n return headers;\n }\n\n /**\n * Build URL\n */\n private buildUrl(storeName: string, id?: string): string {\n if (!this.service) {\n throw new Error(\"Service not configured. Call setService() first.\");\n }\n\n const baseUrl = this.service.endpoint.replace(/\\/$/, \"\");\n const storePath = `/${storeName}`;\n\n if (id) {\n return `${baseUrl}${storePath}/${id}`;\n }\n\n return `${baseUrl}${storePath}`;\n }\n\n /**\n * Send request\n */\n private async request<T>(\n url: string,\n options: RequestInit = {},\n {\n allowNotFound,\n }: {\n allowNotFound?: boolean;\n } = {},\n ): Promise<T | null> {\n const response = await fetch(url, {\n ...options,\n headers: {\n ...this.getHeaders(),\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n if (allowNotFound && response.status == 404) {\n return null;\n }\n throw new Error(\n `HTTP error! status: ${response.status}, message: ${response.statusText}`,\n );\n }\n\n const text = await response.text();\n if (!text) {\n return null;\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return null;\n }\n }\n\n /**\n * Initialize store\n */\n async initStore(\n storeName: string,\n _indexes: string[] = [],\n _idKey: string = \"id\",\n ): Promise<void> {\n const path = storeName.replace(/^\\/+|\\/+$/g, \"\");\n const parts = path.split(\"/\");\n\n let currentPath = \"\";\n for (const part of parts) {\n currentPath = currentPath ? `${currentPath}/${part}` : part;\n\n try {\n await this.listDirectory(currentPath);\n } catch {\n const url = this.buildUrl(currentPath);\n\n const response = await fetch(url, {\n method: \"MKCOL\",\n headers: this.getHeaders(),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create store: ${response.statusText}`);\n }\n }\n }\n }\n\n /**\n * Add data\n */\n async add<T extends Record<string, unknown>>(\n storeName: string,\n data: T,\n idKey: string = \"id\",\n ): Promise<T> {\n const id = String(data[idKey]);\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(url, {\n method: \"PUT\",\n body: JSON.stringify(data),\n });\n\n return result ?? data;\n }\n\n /**\n * Update data\n */\n async update<T extends Record<string, unknown>>(\n storeName: string,\n id: string,\n data: Partial<T>,\n idKey: string = \"id\",\n ): Promise<T> {\n const existing = await this.getData<T>(storeName, id, idKey);\n if (!existing) {\n throw new Error(\"Not found id:\" + id);\n }\n\n const updated = { ...existing, ...data };\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(url, {\n method: \"PUT\",\n body: JSON.stringify(updated),\n });\n\n return result ?? updated;\n }\n\n /**\n * Delete data\n */\n async delete(\n storeName: string,\n id: string,\n _idKey: string = \"id\",\n ): Promise<void> {\n const url = this.buildUrl(storeName, id);\n\n await this.request(url, {\n method: \"DELETE\",\n });\n }\n\n /**\n * Get data by ID\n */\n async getData<T extends Record<string, unknown>>(\n storeName: string,\n id: string,\n _idKey: string = \"id\",\n ): Promise<T | null> {\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(\n url,\n {\n method: \"GET\",\n },\n {\n allowNotFound: true,\n },\n );\n\n return result;\n }\n\n /**\n * Get list data (with pagination support)\n */\n async getList<T extends Record<string, unknown>>(\n storeName: string,\n options: QueryOptions<T> = {},\n _idKey: string = \"id\",\n ): Promise<PaginatedResult<T>> {\n const files = await this.listDirectory(storeName);\n\n const allData: T[] = [];\n for (const file of files) {\n try {\n const data = await this.request<T>(this.buildUrl(file), {\n method: \"GET\",\n });\n if (data) {\n allData.push(data);\n }\n } catch {}\n }\n\n let filteredData = allData;\n\n if (options.where) {\n filteredData = allData.filter((item) => {\n for (const key in options.where) {\n const itemValue = item[key];\n const whereValue = options.where![key];\n if (itemValue !== whereValue) {\n return false;\n }\n }\n return true;\n });\n }\n\n // Sorting\n if (options.sortBy) {\n filteredData = this.sortEntries(\n filteredData,\n String(options.sortBy),\n options.sortOrder,\n );\n }\n\n const totalCount = filteredData.length;\n const page = options.page ?? 1;\n const limit = options.limit ?? totalCount;\n\n const startIndex = (page - 1) * limit;\n const endIndex = startIndex + limit;\n const paginatedData = filteredData.slice(startIndex, endIndex);\n\n return {\n data: paginatedData,\n totalCount,\n page,\n limit,\n };\n }\n\n /**\n * Sort entries by specified field\n * @param entries Array of entries to sort\n * @param key Sorting field name\n * @param sortOrder Sort order: 'asc' or 'desc' (default: 'asc')\n * @returns Sorted array of entries\n */\n private sortEntries<T extends Record<string, unknown>>(\n entries: T[],\n key: string,\n sortOrder: \"asc\" | \"desc\" = \"asc\",\n ): T[] {\n return [...entries].sort((a, b) => {\n const aValue = a[key];\n const bValue = b[key];\n\n // Handle undefined or null values\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return 1; // null/undefined at the end\n if (bValue == null) return -1; // null/undefined at the end\n\n let comparison = 0;\n\n // Number type sorting\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n }\n // String type sorting\n else if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n comparison = aValue.localeCompare(bValue);\n }\n // Date type sorting (if string format date)\n else if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n const aDate = new Date(aValue);\n const bDate = new Date(bValue);\n if (!isNaN(aDate.getTime()) && !isNaN(bDate.getTime())) {\n comparison = aDate.getTime() - bDate.getTime();\n } else {\n // Convert other types to string for comparison\n comparison = String(aValue).localeCompare(String(bValue));\n }\n }\n // Convert other types to string for comparison\n else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n // Apply sort order\n return sortOrder === \"desc\" ? -comparison : comparison;\n });\n }\n\n /**\n * Clear store\n */\n async clear(storeName: string): Promise<void> {\n const list = await this.getList(storeName);\n\n for (const item of list.data) {\n const id = String((item as Record<string, unknown>)[\"id\"]);\n await this.delete(storeName, id);\n }\n }\n\n /**\n * List directory contents\n */\n async listDirectory(path: string = \"\"): Promise<string[]> {\n if (!this.service) {\n throw new Error(\"Service not configured. Call setService() first.\");\n }\n\n const baseUrl = this.service.endpoint.replace(/\\/$/, \"\");\n const url = path ? `${baseUrl}/${path.replace(/^\\//, \"\")}` : baseUrl;\n\n const response = await fetch(url, {\n method: \"PROPFIND\",\n headers: {\n ...this.getHeaders(),\n Depth: \"1\",\n },\n });\n\n if (!response.ok) {\n throw new Error(`Failed to list directory: ${response.statusText}`);\n }\n\n const text = await response.text();\n\n const hrefRegex = /<d:href[^>]*>([^<]+)<\\/d:href>/gi;\n const files: string[] = [];\n let match;\n\n const baseUrlObj = new URL(baseUrl);\n const basePath = baseUrlObj.pathname;\n\n while ((match = hrefRegex.exec(text)) !== null) {\n const fullPath = match[1] || \"\";\n let relativePath = \"\";\n try {\n const hrefUrl = new URL(fullPath);\n relativePath = hrefUrl.pathname\n .replace(basePath, \"\")\n .replace(/^\\//, \"\");\n } catch {\n relativePath = fullPath.replace(basePath, \"\").replace(/^\\//, \"\");\n }\n if (relativePath && relativePath !== path.replace(/^\\//, \"\")) {\n files.push(relativePath);\n }\n }\n\n return files;\n }\n\n /**\n * Test connection\n */\n async testConnection(): Promise<boolean> {\n try {\n await this.listDirectory(\"\");\n return true;\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["AdapterType","headers: Record<string, string>","AuthType","allData: T[]","files: string[]"],"sources":["../src/webdav-adapter.ts"],"sourcesContent":["import {\n AdapterType,\n type RemoteAdapter,\n type QueryOptions,\n type PaginatedResult,\n type ServiceConfig,\n AuthType,\n} from \"@omnistreamai/data-core\";\n\n/**\n * WebDAV adapter implementation\n */\nexport class WebDAVAdapter implements RemoteAdapter {\n readonly type = AdapterType.Remote;\n readonly name = \"WebDAVAdapter\";\n\n private service: ServiceConfig | null = null;\n\n /**\n * Set service configuration\n */\n setService(service: ServiceConfig): void {\n this.service = service;\n }\n\n /**\n * Get request headers\n */\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (!this.service?.authentication) {\n return headers;\n }\n\n const { authentication } = this.service;\n\n switch (authentication.authType) {\n case AuthType.Token:\n if (authentication.token) {\n headers[\"Authorization\"] =\n `${authentication.token.token_type} ${authentication.token.access_token}`;\n }\n break;\n case AuthType.Bearer:\n if (authentication.bearer) {\n headers[\"Authorization\"] = `Bearer ${authentication.bearer}`;\n }\n break;\n case AuthType.Basic:\n if (authentication.username && authentication.password) {\n const credentials = btoa(\n `${authentication.username}:${authentication.password}`,\n );\n headers[\"Authorization\"] = `Basic ${credentials}`;\n }\n break;\n }\n\n return headers;\n }\n\n /**\n * Build URL\n */\n private buildUrl(storeName: string, id?: string): string {\n if (!this.service) {\n throw new Error(\"Service not configured. Call setService() first.\");\n }\n\n const baseUrl = this.service.endpoint.replace(/\\/$/, \"\");\n const storePath = `/${storeName}`;\n\n if (id) {\n return `${baseUrl}${storePath}/${id}`;\n }\n\n return `${baseUrl}${storePath}`;\n }\n\n /**\n * Send request\n */\n private async request<T>(\n url: string,\n options: RequestInit = {},\n {\n allowNotFound,\n }: {\n allowNotFound?: boolean;\n } = {},\n ): Promise<T | null> {\n const response = await fetch(url, {\n ...options,\n headers: {\n ...this.getHeaders(),\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n if (allowNotFound && response.status == 404) {\n return null;\n }\n throw new Error(\n `HTTP error! status: ${response.status}, message: ${response.statusText}`,\n );\n }\n\n const text = await response.text();\n if (!text) {\n return null;\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return null;\n }\n }\n\n /**\n * Initialize store\n */\n async initStore(\n storeName: string,\n _indexes: string[] = [],\n _idKey: string = \"id\",\n ): Promise<void> {\n const path = storeName.replace(/^\\/+|\\/+$/g, \"\");\n const parts = path.split(\"/\");\n\n let currentPath = \"\";\n for (const part of parts) {\n currentPath = currentPath ? `${currentPath}/${part}` : part;\n\n try {\n await this.listDirectory(currentPath);\n } catch {\n const url = this.buildUrl(currentPath);\n\n const response = await fetch(url, {\n method: \"MKCOL\",\n headers: this.getHeaders(),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create store: ${response.statusText}`);\n }\n }\n }\n }\n\n /**\n * Add data\n */\n async add<T extends Record<string, unknown>>(\n storeName: string,\n data: T,\n idKey: string = \"id\",\n ): Promise<T> {\n const id = String(data[idKey]);\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(url, {\n method: \"PUT\",\n body: JSON.stringify(data),\n });\n\n return result ?? data;\n }\n\n /**\n * Update data\n */\n async update<T extends Record<string, unknown>>(\n storeName: string,\n id: string,\n data: Partial<T>,\n idKey: string = \"id\",\n ): Promise<T> {\n const existing = await this.getData<T>(storeName, id, idKey);\n if (!existing) {\n throw new Error(\"Not found id:\" + id);\n }\n\n const updated = { ...existing, ...data };\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(url, {\n method: \"PUT\",\n body: JSON.stringify(updated),\n });\n\n return result ?? updated;\n }\n\n /**\n * Delete data\n */\n async delete(\n storeName: string,\n id: string,\n _idKey: string = \"id\",\n ): Promise<void> {\n const url = this.buildUrl(storeName, id);\n\n await this.request(url, {\n method: \"DELETE\",\n });\n }\n\n /**\n * Get data by ID\n */\n async getData<T extends Record<string, unknown>>(\n storeName: string,\n id: string,\n _idKey: string = \"id\",\n ): Promise<T | null> {\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(\n url,\n {\n method: \"GET\",\n },\n {\n allowNotFound: true,\n },\n );\n\n return result;\n }\n\n /**\n * Get list data (with pagination support)\n */\n async getList<T extends Record<string, unknown>>(\n storeName: string,\n options: QueryOptions<T> = {},\n _idKey: string = \"id\",\n ): Promise<PaginatedResult<T>> {\n const files = await this.listDirectory(storeName);\n\n const allData: T[] = [];\n for (const file of files) {\n try {\n const data = await this.request<T>(this.buildUrl(storeName, file), {\n method: \"GET\",\n });\n if (data) {\n allData.push(data);\n }\n } catch {}\n }\n\n let filteredData = allData;\n\n if (options.where) {\n filteredData = allData.filter((item) => {\n for (const key in options.where) {\n const itemValue = item[key];\n const whereValue = options.where![key];\n if (itemValue !== whereValue) {\n return false;\n }\n }\n return true;\n });\n }\n\n // Sorting\n if (options.sortBy) {\n filteredData = this.sortEntries(\n filteredData,\n String(options.sortBy),\n options.sortOrder,\n );\n }\n\n const totalCount = filteredData.length;\n const page = options.page ?? 1;\n const limit = options.limit ?? totalCount;\n\n const startIndex = (page - 1) * limit;\n const endIndex = startIndex + limit;\n const paginatedData = filteredData.slice(startIndex, endIndex);\n\n return {\n data: paginatedData,\n totalCount,\n page,\n limit,\n };\n }\n\n /**\n * Sort entries by specified field\n * @param entries Array of entries to sort\n * @param key Sorting field name\n * @param sortOrder Sort order: 'asc' or 'desc' (default: 'asc')\n * @returns Sorted array of entries\n */\n private sortEntries<T extends Record<string, unknown>>(\n entries: T[],\n key: string,\n sortOrder: \"asc\" | \"desc\" = \"asc\",\n ): T[] {\n return [...entries].sort((a, b) => {\n const aValue = a[key];\n const bValue = b[key];\n\n // Handle undefined or null values\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return 1; // null/undefined at the end\n if (bValue == null) return -1; // null/undefined at the end\n\n let comparison = 0;\n\n // Number type sorting\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n }\n // String type sorting\n else if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n comparison = aValue.localeCompare(bValue);\n }\n // Date type sorting (if string format date)\n else if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n const aDate = new Date(aValue);\n const bDate = new Date(bValue);\n if (!isNaN(aDate.getTime()) && !isNaN(bDate.getTime())) {\n comparison = aDate.getTime() - bDate.getTime();\n } else {\n // Convert other types to string for comparison\n comparison = String(aValue).localeCompare(String(bValue));\n }\n }\n // Convert other types to string for comparison\n else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n // Apply sort order\n return sortOrder === \"desc\" ? -comparison : comparison;\n });\n }\n\n /**\n * Clear store\n */\n async clear(storeName: string): Promise<void> {\n const list = await this.getList(storeName);\n\n for (const item of list.data) {\n const id = String((item as Record<string, unknown>)[\"id\"]);\n await this.delete(storeName, id);\n }\n }\n\n /**\n * List directory contents\n */\n async listDirectory(path: string = \"\"): Promise<string[]> {\n if (!this.service) {\n throw new Error(\"Service not configured. Call setService() first.\");\n }\n\n const baseUrl = this.service.endpoint.replace(/\\/$/, \"\");\n const url = path ? `${baseUrl}/${path.replace(/^\\//, \"\")}` : baseUrl;\n\n const response = await fetch(url, {\n method: \"PROPFIND\",\n headers: {\n ...this.getHeaders(),\n Depth: \"1\",\n },\n });\n\n if (!response.ok) {\n throw new Error(`Failed to list directory: ${response.statusText}`);\n }\n\n const text = await response.text();\n\n const hrefRegex = /<d:href[^>]*>([^<]+)<\\/d:href>/gi;\n const files: string[] = [];\n let match;\n\n const baseUrlObj = new URL(baseUrl);\n const basePath = baseUrlObj.pathname;\n\n while ((match = hrefRegex.exec(text)) !== null) {\n const fullPath = match[1] || \"\";\n let relativePath = \"\";\n try {\n const hrefUrl = new URL(fullPath);\n relativePath = hrefUrl.pathname;\n } catch {}\n const pathRegex = new RegExp(`^/*${path}`)\n relativePath = fullPath.replace(basePath, \"\").replace(pathRegex, '').replace(/^\\//, \"\");\n if (relativePath && relativePath !== path.replace(/^\\//, \"\")) {\n files.push(relativePath);\n }\n }\n\n return files;\n }\n\n /**\n * Test connection\n */\n async testConnection(): Promise<boolean> {\n try {\n await this.listDirectory(\"\");\n return true;\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -135,7 +135,7 @@ var WebDAVAdapter = class {
|
|
|
135
135
|
const files = await this.listDirectory(storeName);
|
|
136
136
|
const allData = [];
|
|
137
137
|
for (const file of files) try {
|
|
138
|
-
const data = await this.request(this.buildUrl(file), { method: "GET" });
|
|
138
|
+
const data = await this.request(this.buildUrl(storeName, file), { method: "GET" });
|
|
139
139
|
if (data) allData.push(data);
|
|
140
140
|
} catch {}
|
|
141
141
|
let filteredData = allData;
|
|
@@ -216,10 +216,10 @@ var WebDAVAdapter = class {
|
|
|
216
216
|
const fullPath = match[1] || "";
|
|
217
217
|
let relativePath = "";
|
|
218
218
|
try {
|
|
219
|
-
relativePath = new URL(fullPath).pathname
|
|
220
|
-
} catch {
|
|
221
|
-
|
|
222
|
-
|
|
219
|
+
relativePath = new URL(fullPath).pathname;
|
|
220
|
+
} catch {}
|
|
221
|
+
const pathRegex = /* @__PURE__ */ new RegExp(`^/*${path}`);
|
|
222
|
+
relativePath = fullPath.replace(basePath, "").replace(pathRegex, "").replace(/^\//, "");
|
|
223
223
|
if (relativePath && relativePath !== path.replace(/^\//, "")) files.push(relativePath);
|
|
224
224
|
}
|
|
225
225
|
return files;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["headers: Record<string, string>","allData: T[]","files: string[]"],"sources":["../src/webdav-adapter.ts"],"sourcesContent":["import {\n AdapterType,\n type RemoteAdapter,\n type QueryOptions,\n type PaginatedResult,\n type ServiceConfig,\n AuthType,\n} from \"@omnistreamai/data-core\";\n\n/**\n * WebDAV adapter implementation\n */\nexport class WebDAVAdapter implements RemoteAdapter {\n readonly type = AdapterType.Remote;\n readonly name = \"WebDAVAdapter\";\n\n private service: ServiceConfig | null = null;\n\n /**\n * Set service configuration\n */\n setService(service: ServiceConfig): void {\n this.service = service;\n }\n\n /**\n * Get request headers\n */\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (!this.service?.authentication) {\n return headers;\n }\n\n const { authentication } = this.service;\n\n switch (authentication.authType) {\n case AuthType.Token:\n if (authentication.token) {\n headers[\"Authorization\"] =\n `${authentication.token.token_type} ${authentication.token.access_token}`;\n }\n break;\n case AuthType.Bearer:\n if (authentication.bearer) {\n headers[\"Authorization\"] = `Bearer ${authentication.bearer}`;\n }\n break;\n case AuthType.Basic:\n if (authentication.username && authentication.password) {\n const credentials = btoa(\n `${authentication.username}:${authentication.password}`,\n );\n headers[\"Authorization\"] = `Basic ${credentials}`;\n }\n break;\n }\n\n return headers;\n }\n\n /**\n * Build URL\n */\n private buildUrl(storeName: string, id?: string): string {\n if (!this.service) {\n throw new Error(\"Service not configured. Call setService() first.\");\n }\n\n const baseUrl = this.service.endpoint.replace(/\\/$/, \"\");\n const storePath = `/${storeName}`;\n\n if (id) {\n return `${baseUrl}${storePath}/${id}`;\n }\n\n return `${baseUrl}${storePath}`;\n }\n\n /**\n * Send request\n */\n private async request<T>(\n url: string,\n options: RequestInit = {},\n {\n allowNotFound,\n }: {\n allowNotFound?: boolean;\n } = {},\n ): Promise<T | null> {\n const response = await fetch(url, {\n ...options,\n headers: {\n ...this.getHeaders(),\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n if (allowNotFound && response.status == 404) {\n return null;\n }\n throw new Error(\n `HTTP error! status: ${response.status}, message: ${response.statusText}`,\n );\n }\n\n const text = await response.text();\n if (!text) {\n return null;\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return null;\n }\n }\n\n /**\n * Initialize store\n */\n async initStore(\n storeName: string,\n _indexes: string[] = [],\n _idKey: string = \"id\",\n ): Promise<void> {\n const path = storeName.replace(/^\\/+|\\/+$/g, \"\");\n const parts = path.split(\"/\");\n\n let currentPath = \"\";\n for (const part of parts) {\n currentPath = currentPath ? `${currentPath}/${part}` : part;\n\n try {\n await this.listDirectory(currentPath);\n } catch {\n const url = this.buildUrl(currentPath);\n\n const response = await fetch(url, {\n method: \"MKCOL\",\n headers: this.getHeaders(),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create store: ${response.statusText}`);\n }\n }\n }\n }\n\n /**\n * Add data\n */\n async add<T extends Record<string, unknown>>(\n storeName: string,\n data: T,\n idKey: string = \"id\",\n ): Promise<T> {\n const id = String(data[idKey]);\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(url, {\n method: \"PUT\",\n body: JSON.stringify(data),\n });\n\n return result ?? data;\n }\n\n /**\n * Update data\n */\n async update<T extends Record<string, unknown>>(\n storeName: string,\n id: string,\n data: Partial<T>,\n idKey: string = \"id\",\n ): Promise<T> {\n const existing = await this.getData<T>(storeName, id, idKey);\n if (!existing) {\n throw new Error(\"Not found id:\" + id);\n }\n\n const updated = { ...existing, ...data };\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(url, {\n method: \"PUT\",\n body: JSON.stringify(updated),\n });\n\n return result ?? updated;\n }\n\n /**\n * Delete data\n */\n async delete(\n storeName: string,\n id: string,\n _idKey: string = \"id\",\n ): Promise<void> {\n const url = this.buildUrl(storeName, id);\n\n await this.request(url, {\n method: \"DELETE\",\n });\n }\n\n /**\n * Get data by ID\n */\n async getData<T extends Record<string, unknown>>(\n storeName: string,\n id: string,\n _idKey: string = \"id\",\n ): Promise<T | null> {\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(\n url,\n {\n method: \"GET\",\n },\n {\n allowNotFound: true,\n },\n );\n\n return result;\n }\n\n /**\n * Get list data (with pagination support)\n */\n async getList<T extends Record<string, unknown>>(\n storeName: string,\n options: QueryOptions<T> = {},\n _idKey: string = \"id\",\n ): Promise<PaginatedResult<T>> {\n const files = await this.listDirectory(storeName);\n\n const allData: T[] = [];\n for (const file of files) {\n try {\n const data = await this.request<T>(this.buildUrl(file), {\n method: \"GET\",\n });\n if (data) {\n allData.push(data);\n }\n } catch {}\n }\n\n let filteredData = allData;\n\n if (options.where) {\n filteredData = allData.filter((item) => {\n for (const key in options.where) {\n const itemValue = item[key];\n const whereValue = options.where![key];\n if (itemValue !== whereValue) {\n return false;\n }\n }\n return true;\n });\n }\n\n // Sorting\n if (options.sortBy) {\n filteredData = this.sortEntries(\n filteredData,\n String(options.sortBy),\n options.sortOrder,\n );\n }\n\n const totalCount = filteredData.length;\n const page = options.page ?? 1;\n const limit = options.limit ?? totalCount;\n\n const startIndex = (page - 1) * limit;\n const endIndex = startIndex + limit;\n const paginatedData = filteredData.slice(startIndex, endIndex);\n\n return {\n data: paginatedData,\n totalCount,\n page,\n limit,\n };\n }\n\n /**\n * Sort entries by specified field\n * @param entries Array of entries to sort\n * @param key Sorting field name\n * @param sortOrder Sort order: 'asc' or 'desc' (default: 'asc')\n * @returns Sorted array of entries\n */\n private sortEntries<T extends Record<string, unknown>>(\n entries: T[],\n key: string,\n sortOrder: \"asc\" | \"desc\" = \"asc\",\n ): T[] {\n return [...entries].sort((a, b) => {\n const aValue = a[key];\n const bValue = b[key];\n\n // Handle undefined or null values\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return 1; // null/undefined at the end\n if (bValue == null) return -1; // null/undefined at the end\n\n let comparison = 0;\n\n // Number type sorting\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n }\n // String type sorting\n else if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n comparison = aValue.localeCompare(bValue);\n }\n // Date type sorting (if string format date)\n else if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n const aDate = new Date(aValue);\n const bDate = new Date(bValue);\n if (!isNaN(aDate.getTime()) && !isNaN(bDate.getTime())) {\n comparison = aDate.getTime() - bDate.getTime();\n } else {\n // Convert other types to string for comparison\n comparison = String(aValue).localeCompare(String(bValue));\n }\n }\n // Convert other types to string for comparison\n else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n // Apply sort order\n return sortOrder === \"desc\" ? -comparison : comparison;\n });\n }\n\n /**\n * Clear store\n */\n async clear(storeName: string): Promise<void> {\n const list = await this.getList(storeName);\n\n for (const item of list.data) {\n const id = String((item as Record<string, unknown>)[\"id\"]);\n await this.delete(storeName, id);\n }\n }\n\n /**\n * List directory contents\n */\n async listDirectory(path: string = \"\"): Promise<string[]> {\n if (!this.service) {\n throw new Error(\"Service not configured. Call setService() first.\");\n }\n\n const baseUrl = this.service.endpoint.replace(/\\/$/, \"\");\n const url = path ? `${baseUrl}/${path.replace(/^\\//, \"\")}` : baseUrl;\n\n const response = await fetch(url, {\n method: \"PROPFIND\",\n headers: {\n ...this.getHeaders(),\n Depth: \"1\",\n },\n });\n\n if (!response.ok) {\n throw new Error(`Failed to list directory: ${response.statusText}`);\n }\n\n const text = await response.text();\n\n const hrefRegex = /<d:href[^>]*>([^<]+)<\\/d:href>/gi;\n const files: string[] = [];\n let match;\n\n const baseUrlObj = new URL(baseUrl);\n const basePath = baseUrlObj.pathname;\n\n while ((match = hrefRegex.exec(text)) !== null) {\n const fullPath = match[1] || \"\";\n let relativePath = \"\";\n try {\n const hrefUrl = new URL(fullPath);\n relativePath = hrefUrl.pathname\n .replace(basePath, \"\")\n .replace(/^\\//, \"\");\n } catch {\n relativePath = fullPath.replace(basePath, \"\").replace(/^\\//, \"\");\n }\n if (relativePath && relativePath !== path.replace(/^\\//, \"\")) {\n files.push(relativePath);\n }\n }\n\n return files;\n }\n\n /**\n * Test connection\n */\n async testConnection(): Promise<boolean> {\n try {\n await this.listDirectory(\"\");\n return true;\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["headers: Record<string, string>","allData: T[]","files: string[]"],"sources":["../src/webdav-adapter.ts"],"sourcesContent":["import {\n AdapterType,\n type RemoteAdapter,\n type QueryOptions,\n type PaginatedResult,\n type ServiceConfig,\n AuthType,\n} from \"@omnistreamai/data-core\";\n\n/**\n * WebDAV adapter implementation\n */\nexport class WebDAVAdapter implements RemoteAdapter {\n readonly type = AdapterType.Remote;\n readonly name = \"WebDAVAdapter\";\n\n private service: ServiceConfig | null = null;\n\n /**\n * Set service configuration\n */\n setService(service: ServiceConfig): void {\n this.service = service;\n }\n\n /**\n * Get request headers\n */\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (!this.service?.authentication) {\n return headers;\n }\n\n const { authentication } = this.service;\n\n switch (authentication.authType) {\n case AuthType.Token:\n if (authentication.token) {\n headers[\"Authorization\"] =\n `${authentication.token.token_type} ${authentication.token.access_token}`;\n }\n break;\n case AuthType.Bearer:\n if (authentication.bearer) {\n headers[\"Authorization\"] = `Bearer ${authentication.bearer}`;\n }\n break;\n case AuthType.Basic:\n if (authentication.username && authentication.password) {\n const credentials = btoa(\n `${authentication.username}:${authentication.password}`,\n );\n headers[\"Authorization\"] = `Basic ${credentials}`;\n }\n break;\n }\n\n return headers;\n }\n\n /**\n * Build URL\n */\n private buildUrl(storeName: string, id?: string): string {\n if (!this.service) {\n throw new Error(\"Service not configured. Call setService() first.\");\n }\n\n const baseUrl = this.service.endpoint.replace(/\\/$/, \"\");\n const storePath = `/${storeName}`;\n\n if (id) {\n return `${baseUrl}${storePath}/${id}`;\n }\n\n return `${baseUrl}${storePath}`;\n }\n\n /**\n * Send request\n */\n private async request<T>(\n url: string,\n options: RequestInit = {},\n {\n allowNotFound,\n }: {\n allowNotFound?: boolean;\n } = {},\n ): Promise<T | null> {\n const response = await fetch(url, {\n ...options,\n headers: {\n ...this.getHeaders(),\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n if (allowNotFound && response.status == 404) {\n return null;\n }\n throw new Error(\n `HTTP error! status: ${response.status}, message: ${response.statusText}`,\n );\n }\n\n const text = await response.text();\n if (!text) {\n return null;\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return null;\n }\n }\n\n /**\n * Initialize store\n */\n async initStore(\n storeName: string,\n _indexes: string[] = [],\n _idKey: string = \"id\",\n ): Promise<void> {\n const path = storeName.replace(/^\\/+|\\/+$/g, \"\");\n const parts = path.split(\"/\");\n\n let currentPath = \"\";\n for (const part of parts) {\n currentPath = currentPath ? `${currentPath}/${part}` : part;\n\n try {\n await this.listDirectory(currentPath);\n } catch {\n const url = this.buildUrl(currentPath);\n\n const response = await fetch(url, {\n method: \"MKCOL\",\n headers: this.getHeaders(),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create store: ${response.statusText}`);\n }\n }\n }\n }\n\n /**\n * Add data\n */\n async add<T extends Record<string, unknown>>(\n storeName: string,\n data: T,\n idKey: string = \"id\",\n ): Promise<T> {\n const id = String(data[idKey]);\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(url, {\n method: \"PUT\",\n body: JSON.stringify(data),\n });\n\n return result ?? data;\n }\n\n /**\n * Update data\n */\n async update<T extends Record<string, unknown>>(\n storeName: string,\n id: string,\n data: Partial<T>,\n idKey: string = \"id\",\n ): Promise<T> {\n const existing = await this.getData<T>(storeName, id, idKey);\n if (!existing) {\n throw new Error(\"Not found id:\" + id);\n }\n\n const updated = { ...existing, ...data };\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(url, {\n method: \"PUT\",\n body: JSON.stringify(updated),\n });\n\n return result ?? updated;\n }\n\n /**\n * Delete data\n */\n async delete(\n storeName: string,\n id: string,\n _idKey: string = \"id\",\n ): Promise<void> {\n const url = this.buildUrl(storeName, id);\n\n await this.request(url, {\n method: \"DELETE\",\n });\n }\n\n /**\n * Get data by ID\n */\n async getData<T extends Record<string, unknown>>(\n storeName: string,\n id: string,\n _idKey: string = \"id\",\n ): Promise<T | null> {\n const url = this.buildUrl(storeName, id);\n\n const result = await this.request<T>(\n url,\n {\n method: \"GET\",\n },\n {\n allowNotFound: true,\n },\n );\n\n return result;\n }\n\n /**\n * Get list data (with pagination support)\n */\n async getList<T extends Record<string, unknown>>(\n storeName: string,\n options: QueryOptions<T> = {},\n _idKey: string = \"id\",\n ): Promise<PaginatedResult<T>> {\n const files = await this.listDirectory(storeName);\n\n const allData: T[] = [];\n for (const file of files) {\n try {\n const data = await this.request<T>(this.buildUrl(storeName, file), {\n method: \"GET\",\n });\n if (data) {\n allData.push(data);\n }\n } catch {}\n }\n\n let filteredData = allData;\n\n if (options.where) {\n filteredData = allData.filter((item) => {\n for (const key in options.where) {\n const itemValue = item[key];\n const whereValue = options.where![key];\n if (itemValue !== whereValue) {\n return false;\n }\n }\n return true;\n });\n }\n\n // Sorting\n if (options.sortBy) {\n filteredData = this.sortEntries(\n filteredData,\n String(options.sortBy),\n options.sortOrder,\n );\n }\n\n const totalCount = filteredData.length;\n const page = options.page ?? 1;\n const limit = options.limit ?? totalCount;\n\n const startIndex = (page - 1) * limit;\n const endIndex = startIndex + limit;\n const paginatedData = filteredData.slice(startIndex, endIndex);\n\n return {\n data: paginatedData,\n totalCount,\n page,\n limit,\n };\n }\n\n /**\n * Sort entries by specified field\n * @param entries Array of entries to sort\n * @param key Sorting field name\n * @param sortOrder Sort order: 'asc' or 'desc' (default: 'asc')\n * @returns Sorted array of entries\n */\n private sortEntries<T extends Record<string, unknown>>(\n entries: T[],\n key: string,\n sortOrder: \"asc\" | \"desc\" = \"asc\",\n ): T[] {\n return [...entries].sort((a, b) => {\n const aValue = a[key];\n const bValue = b[key];\n\n // Handle undefined or null values\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return 1; // null/undefined at the end\n if (bValue == null) return -1; // null/undefined at the end\n\n let comparison = 0;\n\n // Number type sorting\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n }\n // String type sorting\n else if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n comparison = aValue.localeCompare(bValue);\n }\n // Date type sorting (if string format date)\n else if (typeof aValue === \"string\" && typeof bValue === \"string\") {\n const aDate = new Date(aValue);\n const bDate = new Date(bValue);\n if (!isNaN(aDate.getTime()) && !isNaN(bDate.getTime())) {\n comparison = aDate.getTime() - bDate.getTime();\n } else {\n // Convert other types to string for comparison\n comparison = String(aValue).localeCompare(String(bValue));\n }\n }\n // Convert other types to string for comparison\n else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n // Apply sort order\n return sortOrder === \"desc\" ? -comparison : comparison;\n });\n }\n\n /**\n * Clear store\n */\n async clear(storeName: string): Promise<void> {\n const list = await this.getList(storeName);\n\n for (const item of list.data) {\n const id = String((item as Record<string, unknown>)[\"id\"]);\n await this.delete(storeName, id);\n }\n }\n\n /**\n * List directory contents\n */\n async listDirectory(path: string = \"\"): Promise<string[]> {\n if (!this.service) {\n throw new Error(\"Service not configured. Call setService() first.\");\n }\n\n const baseUrl = this.service.endpoint.replace(/\\/$/, \"\");\n const url = path ? `${baseUrl}/${path.replace(/^\\//, \"\")}` : baseUrl;\n\n const response = await fetch(url, {\n method: \"PROPFIND\",\n headers: {\n ...this.getHeaders(),\n Depth: \"1\",\n },\n });\n\n if (!response.ok) {\n throw new Error(`Failed to list directory: ${response.statusText}`);\n }\n\n const text = await response.text();\n\n const hrefRegex = /<d:href[^>]*>([^<]+)<\\/d:href>/gi;\n const files: string[] = [];\n let match;\n\n const baseUrlObj = new URL(baseUrl);\n const basePath = baseUrlObj.pathname;\n\n while ((match = hrefRegex.exec(text)) !== null) {\n const fullPath = match[1] || \"\";\n let relativePath = \"\";\n try {\n const hrefUrl = new URL(fullPath);\n relativePath = hrefUrl.pathname;\n } catch {}\n const pathRegex = new RegExp(`^/*${path}`)\n relativePath = fullPath.replace(basePath, \"\").replace(pathRegex, '').replace(/^\\//, \"\");\n if (relativePath && relativePath !== path.replace(/^\\//, \"\")) {\n files.push(relativePath);\n }\n }\n\n return files;\n }\n\n /**\n * Test connection\n */\n async testConnection(): Promise<boolean> {\n try {\n await this.listDirectory(\"\");\n return true;\n } catch {\n return false;\n }\n }\n}\n"],"mappings":";;;;;;AAYA,IAAa,gBAAb,MAAoD;CAClD,AAAS,OAAO,YAAY;CAC5B,AAAS,OAAO;CAEhB,AAAQ,UAAgC;;;;CAKxC,WAAW,SAA8B;AACvC,OAAK,UAAU;;;;;CAMjB,AAAQ,aAAqC;EAC3C,MAAMA,UAAkC,EACtC,gBAAgB,oBACjB;AAED,MAAI,CAAC,KAAK,SAAS,eACjB,QAAO;EAGT,MAAM,EAAE,mBAAmB,KAAK;AAEhC,UAAQ,eAAe,UAAvB;GACE,KAAK,SAAS;AACZ,QAAI,eAAe,MACjB,SAAQ,mBACN,GAAG,eAAe,MAAM,WAAW,GAAG,eAAe,MAAM;AAE/D;GACF,KAAK,SAAS;AACZ,QAAI,eAAe,OACjB,SAAQ,mBAAmB,UAAU,eAAe;AAEtD;GACF,KAAK,SAAS;AACZ,QAAI,eAAe,YAAY,eAAe,SAI5C,SAAQ,mBAAmB,SAHP,KAClB,GAAG,eAAe,SAAS,GAAG,eAAe,WAC9C;AAGH;;AAGJ,SAAO;;;;;CAMT,AAAQ,SAAS,WAAmB,IAAqB;AACvD,MAAI,CAAC,KAAK,QACR,OAAM,IAAI,MAAM,mDAAmD;EAGrE,MAAM,UAAU,KAAK,QAAQ,SAAS,QAAQ,OAAO,GAAG;EACxD,MAAM,YAAY,IAAI;AAEtB,MAAI,GACF,QAAO,GAAG,UAAU,UAAU,GAAG;AAGnC,SAAO,GAAG,UAAU;;;;;CAMtB,MAAc,QACZ,KACA,UAAuB,EAAE,EACzB,EACE,kBAGE,EAAE,EACa;EACnB,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,GAAG;GACH,SAAS;IACP,GAAG,KAAK,YAAY;IACpB,GAAG,QAAQ;IACZ;GACF,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;AAChB,OAAI,iBAAiB,SAAS,UAAU,IACtC,QAAO;AAET,SAAM,IAAI,MACR,uBAAuB,SAAS,OAAO,aAAa,SAAS,aAC9D;;EAGH,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,MAAI,CAAC,KACH,QAAO;AAGT,MAAI;AACF,UAAO,KAAK,MAAM,KAAK;UACjB;AACN,UAAO;;;;;;CAOX,MAAM,UACJ,WACA,WAAqB,EAAE,EACvB,SAAiB,MACF;EAEf,MAAM,QADO,UAAU,QAAQ,cAAc,GAAG,CAC7B,MAAM,IAAI;EAE7B,IAAI,cAAc;AAClB,OAAK,MAAM,QAAQ,OAAO;AACxB,iBAAc,cAAc,GAAG,YAAY,GAAG,SAAS;AAEvD,OAAI;AACF,UAAM,KAAK,cAAc,YAAY;WAC/B;IACN,MAAM,MAAM,KAAK,SAAS,YAAY;IAEtC,MAAM,WAAW,MAAM,MAAM,KAAK;KAChC,QAAQ;KACR,SAAS,KAAK,YAAY;KAC3B,CAAC;AAEF,QAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,2BAA2B,SAAS,aAAa;;;;;;;CASzE,MAAM,IACJ,WACA,MACA,QAAgB,MACJ;EACZ,MAAM,KAAK,OAAO,KAAK,OAAO;EAC9B,MAAM,MAAM,KAAK,SAAS,WAAW,GAAG;AAOxC,SALe,MAAM,KAAK,QAAW,KAAK;GACxC,QAAQ;GACR,MAAM,KAAK,UAAU,KAAK;GAC3B,CAAC,IAEe;;;;;CAMnB,MAAM,OACJ,WACA,IACA,MACA,QAAgB,MACJ;EACZ,MAAM,WAAW,MAAM,KAAK,QAAW,WAAW,IAAI,MAAM;AAC5D,MAAI,CAAC,SACH,OAAM,IAAI,MAAM,kBAAkB,GAAG;EAGvC,MAAM,UAAU;GAAE,GAAG;GAAU,GAAG;GAAM;EACxC,MAAM,MAAM,KAAK,SAAS,WAAW,GAAG;AAOxC,SALe,MAAM,KAAK,QAAW,KAAK;GACxC,QAAQ;GACR,MAAM,KAAK,UAAU,QAAQ;GAC9B,CAAC,IAEe;;;;;CAMnB,MAAM,OACJ,WACA,IACA,SAAiB,MACF;EACf,MAAM,MAAM,KAAK,SAAS,WAAW,GAAG;AAExC,QAAM,KAAK,QAAQ,KAAK,EACtB,QAAQ,UACT,CAAC;;;;;CAMJ,MAAM,QACJ,WACA,IACA,SAAiB,MACE;EACnB,MAAM,MAAM,KAAK,SAAS,WAAW,GAAG;AAYxC,SAVe,MAAM,KAAK,QACxB,KACA,EACE,QAAQ,OACT,EACD,EACE,eAAe,MAChB,CACF;;;;;CAQH,MAAM,QACJ,WACA,UAA2B,EAAE,EAC7B,SAAiB,MACY;EAC7B,MAAM,QAAQ,MAAM,KAAK,cAAc,UAAU;EAEjD,MAAMC,UAAe,EAAE;AACvB,OAAK,MAAM,QAAQ,MACjB,KAAI;GACF,MAAM,OAAO,MAAM,KAAK,QAAW,KAAK,SAAS,WAAW,KAAK,EAAE,EACjE,QAAQ,OACT,CAAC;AACF,OAAI,KACF,SAAQ,KAAK,KAAK;UAEd;EAGV,IAAI,eAAe;AAEnB,MAAI,QAAQ,MACV,gBAAe,QAAQ,QAAQ,SAAS;AACtC,QAAK,MAAM,OAAO,QAAQ,MAGxB,KAFkB,KAAK,SACJ,QAAQ,MAAO,KAEhC,QAAO;AAGX,UAAO;IACP;AAIJ,MAAI,QAAQ,OACV,gBAAe,KAAK,YAClB,cACA,OAAO,QAAQ,OAAO,EACtB,QAAQ,UACT;EAGH,MAAM,aAAa,aAAa;EAChC,MAAM,OAAO,QAAQ,QAAQ;EAC7B,MAAM,QAAQ,QAAQ,SAAS;EAE/B,MAAM,cAAc,OAAO,KAAK;EAChC,MAAM,WAAW,aAAa;AAG9B,SAAO;GACL,MAHoB,aAAa,MAAM,YAAY,SAAS;GAI5D;GACA;GACA;GACD;;;;;;;;;CAUH,AAAQ,YACN,SACA,KACA,YAA4B,OACvB;AACL,SAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,MAAM;GACjC,MAAM,SAAS,EAAE;GACjB,MAAM,SAAS,EAAE;AAGjB,OAAI,UAAU,QAAQ,UAAU,KAAM,QAAO;AAC7C,OAAI,UAAU,KAAM,QAAO;AAC3B,OAAI,UAAU,KAAM,QAAO;GAE3B,IAAI,aAAa;AAGjB,OAAI,OAAO,WAAW,YAAY,OAAO,WAAW,SAClD,cAAa,SAAS;YAGf,OAAO,WAAW,YAAY,OAAO,WAAW,SACvD,cAAa,OAAO,cAAc,OAAO;YAGlC,OAAO,WAAW,YAAY,OAAO,WAAW,UAAU;IACjE,MAAM,QAAQ,IAAI,KAAK,OAAO;IAC9B,MAAM,QAAQ,IAAI,KAAK,OAAO;AAC9B,QAAI,CAAC,MAAM,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,MAAM,SAAS,CAAC,CACpD,cAAa,MAAM,SAAS,GAAG,MAAM,SAAS;QAG9C,cAAa,OAAO,OAAO,CAAC,cAAc,OAAO,OAAO,CAAC;SAK3D,cAAa,OAAO,OAAO,CAAC,cAAc,OAAO,OAAO,CAAC;AAI3D,UAAO,cAAc,SAAS,CAAC,aAAa;IAC5C;;;;;CAMJ,MAAM,MAAM,WAAkC;EAC5C,MAAM,OAAO,MAAM,KAAK,QAAQ,UAAU;AAE1C,OAAK,MAAM,QAAQ,KAAK,MAAM;GAC5B,MAAM,KAAK,OAAQ,KAAiC,MAAM;AAC1D,SAAM,KAAK,OAAO,WAAW,GAAG;;;;;;CAOpC,MAAM,cAAc,OAAe,IAAuB;AACxD,MAAI,CAAC,KAAK,QACR,OAAM,IAAI,MAAM,mDAAmD;EAGrE,MAAM,UAAU,KAAK,QAAQ,SAAS,QAAQ,OAAO,GAAG;EACxD,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,KAAK,QAAQ,OAAO,GAAG,KAAK;EAE7D,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,QAAQ;GACR,SAAS;IACP,GAAG,KAAK,YAAY;IACpB,OAAO;IACR;GACF,CAAC;AAEF,MAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,6BAA6B,SAAS,aAAa;EAGrE,MAAM,OAAO,MAAM,SAAS,MAAM;EAElC,MAAM,YAAY;EAClB,MAAMC,QAAkB,EAAE;EAC1B,IAAI;EAGJ,MAAM,WADa,IAAI,IAAI,QAAQ,CACP;AAE5B,UAAQ,QAAQ,UAAU,KAAK,KAAK,MAAM,MAAM;GAC9C,MAAM,WAAW,MAAM,MAAM;GAC7B,IAAI,eAAe;AACnB,OAAI;AAEF,mBADgB,IAAI,IAAI,SAAS,CACV;WACjB;GACR,MAAM,4BAAY,IAAI,OAAO,MAAM,OAAO;AAC1C,kBAAe,SAAS,QAAQ,UAAU,GAAG,CAAC,QAAQ,WAAW,GAAG,CAAC,QAAQ,OAAO,GAAG;AACvF,OAAI,gBAAgB,iBAAiB,KAAK,QAAQ,OAAO,GAAG,CAC1D,OAAM,KAAK,aAAa;;AAI5B,SAAO;;;;;CAMT,MAAM,iBAAmC;AACvC,MAAI;AACF,SAAM,KAAK,cAAc,GAAG;AAC5B,UAAO;UACD;AACN,UAAO"}
|
package/package.json
CHANGED
package/src/webdav-adapter.ts
CHANGED
|
@@ -248,7 +248,7 @@ export class WebDAVAdapter implements RemoteAdapter {
|
|
|
248
248
|
const allData: T[] = [];
|
|
249
249
|
for (const file of files) {
|
|
250
250
|
try {
|
|
251
|
-
const data = await this.request<T>(this.buildUrl(file), {
|
|
251
|
+
const data = await this.request<T>(this.buildUrl(storeName, file), {
|
|
252
252
|
method: "GET",
|
|
253
253
|
});
|
|
254
254
|
if (data) {
|
|
@@ -398,12 +398,10 @@ export class WebDAVAdapter implements RemoteAdapter {
|
|
|
398
398
|
let relativePath = "";
|
|
399
399
|
try {
|
|
400
400
|
const hrefUrl = new URL(fullPath);
|
|
401
|
-
relativePath = hrefUrl.pathname
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
relativePath = fullPath.replace(basePath, "").replace(/^\//, "");
|
|
406
|
-
}
|
|
401
|
+
relativePath = hrefUrl.pathname;
|
|
402
|
+
} catch {}
|
|
403
|
+
const pathRegex = new RegExp(`^/*${path}`)
|
|
404
|
+
relativePath = fullPath.replace(basePath, "").replace(pathRegex, '').replace(/^\//, "");
|
|
407
405
|
if (relativePath && relativePath !== path.replace(/^\//, "")) {
|
|
408
406
|
files.push(relativePath);
|
|
409
407
|
}
|