@keetanetwork/anchor 0.0.52 → 0.0.58
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/lib/asset.d.ts +18 -4
- package/lib/asset.d.ts.map +1 -1
- package/lib/asset.js +18 -0
- package/lib/asset.js.map +1 -1
- package/lib/chaining-graph.cli.d.ts +2 -0
- package/lib/chaining-graph.cli.d.ts.map +1 -0
- package/lib/chaining-graph.cli.js +257 -0
- package/lib/chaining-graph.cli.js.map +1 -0
- package/lib/chaining.d.ts +247 -0
- package/lib/chaining.d.ts.map +1 -0
- package/lib/chaining.js +1187 -0
- package/lib/chaining.js.map +1 -0
- package/lib/metadata.types.d.ts +28 -0
- package/lib/metadata.types.d.ts.map +1 -0
- package/lib/metadata.types.generated.d.ts +3 -0
- package/lib/metadata.types.generated.d.ts.map +1 -0
- package/lib/metadata.types.generated.js +15 -0
- package/lib/metadata.types.generated.js.map +1 -0
- package/lib/metadata.types.js +50 -0
- package/lib/metadata.types.js.map +1 -0
- package/lib/resolver.d.ts +15 -19
- package/lib/resolver.d.ts.map +1 -1
- package/lib/resolver.js +1101 -469
- package/lib/resolver.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/services/asset-movement/client.d.ts +12 -5
- package/services/asset-movement/client.d.ts.map +1 -1
- package/services/asset-movement/client.js +190 -9
- package/services/asset-movement/client.js.map +1 -1
- package/services/asset-movement/common.d.ts +119 -60
- package/services/asset-movement/common.d.ts.map +1 -1
- package/services/asset-movement/common.generated.d.ts +48 -0
- package/services/asset-movement/common.generated.d.ts.map +1 -0
- package/services/asset-movement/common.generated.js +37425 -0
- package/services/asset-movement/common.generated.js.map +1 -0
- package/services/asset-movement/common.js +22 -35368
- package/services/asset-movement/common.js.map +1 -1
- package/services/asset-movement/lib/location.d.ts +10 -1
- package/services/asset-movement/lib/location.d.ts.map +1 -1
- package/services/asset-movement/lib/location.generated.d.ts +2 -1
- package/services/asset-movement/lib/location.generated.d.ts.map +1 -1
- package/services/asset-movement/lib/location.generated.js +23 -0
- package/services/asset-movement/lib/location.generated.js.map +1 -1
- package/services/asset-movement/lib/location.js +3 -0
- package/services/asset-movement/lib/location.js.map +1 -1
- package/services/asset-movement/server.d.ts +17 -6
- package/services/asset-movement/server.d.ts.map +1 -1
- package/services/asset-movement/server.js +47 -2
- package/services/asset-movement/server.js.map +1 -1
- package/services/fx/client.d.ts +3 -2
- package/services/fx/client.d.ts.map +1 -1
- package/services/fx/client.js +8 -3
- package/services/fx/client.js.map +1 -1
- package/services/fx/server.d.ts +2 -1
- package/services/fx/server.d.ts.map +1 -1
- package/services/fx/server.js +3 -0
- package/services/fx/server.js.map +1 -1
- package/services/storage/clients/contacts.generated.js +142 -90
- package/services/storage/clients/contacts.generated.js.map +1 -1
- package/services/storage/common.d.ts +61 -16
- package/services/storage/common.d.ts.map +1 -1
- package/services/storage/common.js.map +1 -1
- package/services/storage/server.d.ts.map +1 -1
- package/services/storage/server.js +35 -22
- package/services/storage/server.js.map +1 -1
- package/services/storage/test-utils.d.ts +7 -2
- package/services/storage/test-utils.d.ts.map +1 -1
- package/services/storage/test-utils.js +22 -4
- package/services/storage/test-utils.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../../src/services/storage/test-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tPathPolicy,\n\tFullStorageBackend,\n\tStorageObjectMetadata,\n\tStoragePutMetadata,\n\tStorageGetResult,\n\tSearchCriteria,\n\tSearchPagination,\n\tSearchResults,\n\tQuotaStatus,\n\tQuotaLimits,\n\tUploadReservation\n} from './common.js';\nimport type { KeetaStorageAnchorProvider } from './client.js';\nimport { KeetaNet } from '../../client/index.js';\nimport { createNodeAndClient, setResolverInfo } from '../../lib/utils/tests/node.js';\nimport { KeetaNetStorageAnchorHTTPServer } from './server.js';\nimport { Errors } from './common.js';\nimport { Buffer } from '../../lib/utils/buffer.js';\nimport KeetaAnchorResolver from '../../lib/resolver.js';\nimport KeetaStorageAnchorClient from './client.js';\n\n// #region Test Path Policy\n\n/**\n * Parsed path for the test path policy: /user/<pubkey>/<relativePath>\n */\nexport type TestParsedPath = {\n\tpath: string;\n\towner: string;\n\trelativePath: string;\n};\n\n/**\n * Test path policy implementing the /user/<pubkey>/<path> pattern.\n * Owner-based access control: only the owner can access their namespace.\n */\nexport class TestPathPolicy implements PathPolicy<TestParsedPath> {\n\t// Matches /user/<owner> or /user/<owner>/ or /user/<owner>/<path>\n\treadonly #pattern = /^\\/user\\/([^/]+)(\\/(.*))?$/;\n\n\tparse(path: string): TestParsedPath | null {\n\t\tconst match = path.match(this.#pattern);\n\t\tif (!match?.[1]) {\n\t\t\treturn(null);\n\t\t}\n\n\t\treturn({ path, owner: match[1], relativePath: match[3] ?? '' });\n\t}\n\n\tvalidate(path: string): TestParsedPath {\n\t\tconst parsed = this.parse(path);\n\t\tif (!parsed) {\n\t\t\tthrow(new Errors.InvalidPath('Path must match /user/<pubkey>/<path>'));\n\t\t}\n\n\t\t// Reject empty segments in original path\n\t\tif (path.includes('//')) {\n\t\t\tthrow(new Errors.InvalidPath('Path contains empty segments'));\n\t\t}\n\n\t\t// Reject path traversal attempts\n\t\tconst segments = parsed.relativePath.split('/');\n\t\tfor (const seg of segments) {\n\t\t\tif (seg === '..' || seg === '.') {\n\t\t\t\tthrow(new Errors.InvalidPath('Path contains relative segments'));\n\t\t\t}\n\t\t}\n\n\t\treturn(parsed);\n\t}\n\n\tisValid(path: string): boolean {\n\t\treturn(this.parse(path) !== null);\n\t}\n\n\tcheckAccess(\n\t\taccount: InstanceType<typeof KeetaNet.lib.Account>,\n\t\tparsed: TestParsedPath,\n\t\t_ignoreOperation: 'get' | 'put' | 'delete' | 'search' | 'metadata'\n\t): boolean {\n\t\t// Owner-based access: account must match the path owner\n\t\treturn(parsed.owner === account.publicKeyString.get());\n\t}\n\n\tgetAuthorizedSigner(parsed: TestParsedPath): InstanceType<typeof KeetaNet.lib.Account> | null {\n\t\treturn(KeetaNet.lib.Account.fromPublicKeyString(parsed.owner).assertAccount());\n\t}\n\n\tvalidateMetadata(parsed: TestParsedPath, metadata: StoragePutMetadata): void {\n\t\t// Require public visibility for paths under public/\n\t\tif (parsed.relativePath.startsWith('public/') && metadata.visibility !== 'public') {\n\t\t\tthrow(new Errors.InvalidMetadata('Objects under /public/ must have public visibility'));\n\t\t}\n\t}\n\n\t/**\n\t * Helper to construct a path for a given owner and relative path.\n\t */\n\tmakePath(owner: string, relativePath: string): string {\n\t\treturn(`/user/${owner}/${relativePath}`);\n\t}\n\n\t/**\n\t * Helper to get the namespace prefix for an owner.\n\t */\n\tgetNamespacePrefix(owner: string): string {\n\t\treturn(`/user/${owner}/`);\n\t}\n}\n\n/**\n * Shared instance of TestPathPolicy for use in tests.\n */\nexport const testPathPolicy: TestPathPolicy = new TestPathPolicy();\n\n/**\n * Create test metadata with sensible defaults.\n */\nexport function testMetadata(\n\towner: string,\n\toverrides?: Partial<StoragePutMetadata>\n): StoragePutMetadata {\n\treturn({\n\t\towner,\n\t\ttags: [],\n\t\tvisibility: 'private',\n\t\t...overrides\n\t});\n}\n\n// #endregion\n\n// #region Types\n\ntype StorageEntry = {\n\tdata: Buffer;\n\tmetadata: StorageObjectMetadata;\n};\n\ntype QuotaConfig = {\n\tmaxObjectsPerUser: number;\n\tmaxStoragePerUser: number;\n};\n\n// #endregion\n\n// #region Shared Storage Operations\n\nfunction putToStorage(\n\tstorage: Map<string, StorageEntry>,\n\tpath: string,\n\tdata: Buffer,\n\tmetadata: StoragePutMetadata\n): StorageObjectMetadata {\n\tconst now = new Date().toISOString();\n\tconst existing = storage.get(path);\n\tconst objectMetadata: StorageObjectMetadata = {\n\t\tpath,\n\t\towner: metadata.owner,\n\t\ttags: metadata.tags,\n\t\tvisibility: metadata.visibility,\n\t\tsize: data.length,\n\t\tcreatedAt: existing?.metadata.createdAt ?? now,\n\t\t...(existing ? { updatedAt: now } : {})\n\t};\n\n\tstorage.set(path, { data, metadata: objectMetadata });\n\treturn(objectMetadata);\n}\n\nfunction getFromStorage(\n\tstorage: Map<string, StorageEntry>,\n\tpath: string\n): StorageGetResult | null {\n\tconst entry = storage.get(path);\n\tif (!entry) {\n\t\treturn(null);\n\t}\n\n\treturn({\n\t\tdata: Buffer.from(entry.data),\n\t\tmetadata: { ...entry.metadata }\n\t});\n}\n\nfunction searchStorage(\n\tstorage: Map<string, StorageEntry>,\n\tcriteria: SearchCriteria,\n\tpagination: SearchPagination\n): SearchResults {\n\tconst results: StorageObjectMetadata[] = [];\n\tconst limit = pagination.limit ?? 100;\n\tconst startAfter = pagination.cursor;\n\tlet foundCursor = !startAfter;\n\n\tfor (const [path, entry] of storage.entries()) {\n\t\tif (!foundCursor) {\n\t\t\tif (path === startAfter) {\n\t\t\t\tfoundCursor = true;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst metadata = entry.metadata;\n\n\t\tif (criteria.pathPrefix) {\n\t\t\tconst prefix = criteria.pathPrefix.endsWith('/')\n\t\t\t\t? criteria.pathPrefix\n\t\t\t\t: criteria.pathPrefix + '/';\n\t\t\tif (!path.startsWith(prefix) && path !== criteria.pathPrefix) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!criteria.recursive) {\n\t\t\t\tconst remainder = path.slice(prefix.length);\n\t\t\t\tif (remainder.includes('/')) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (criteria.owner && metadata.owner !== criteria.owner) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (criteria.tags && criteria.tags.length > 0) {\n\t\t\tconst hasMatchingTag = criteria.tags.some(function(tag) {\n\t\t\t\treturn(metadata.tags.includes(tag));\n\t\t\t});\n\t\t\tif (!hasMatchingTag) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (criteria.name) {\n\t\t\tconst filename = path.split('/').pop();\n\t\t\tif (!filename?.includes(criteria.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (criteria.visibility && metadata.visibility !== criteria.visibility) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tresults.push(metadata);\n\n\t\tif (results.length >= limit) {\n\t\t\treturn({ results, nextCursor: path });\n\t\t}\n\t}\n\n\treturn({ results });\n}\n\nfunction computeQuotaStatus(\n\tstorage: Map<string, StorageEntry>,\n\towner: string,\n\tquotaConfig: QuotaConfig\n): QuotaStatus {\n\tlet objectCount = 0;\n\tlet totalSize = 0;\n\tfor (const entry of storage.values()) {\n\t\tif (entry.metadata.owner === owner) {\n\t\t\tobjectCount++;\n\n\t\t\ttotalSize += entry.metadata.size;\n\t\t}\n\t}\n\n\treturn({\n\t\tobjectCount,\n\t\ttotalSize,\n\t\tremainingObjects: Math.max(0, quotaConfig.maxObjectsPerUser - objectCount),\n\t\tremainingSize: Math.max(0, quotaConfig.maxStoragePerUser - totalSize)\n\t});\n}\n\n// #endregion\n\n// #region Memory Storage Backend\n\n/**\n * In-memory storage backend with full capabilities: CRUD, search, and quota management.\n * Intended for testing and development purposes.\n */\nexport class MemoryStorageBackend implements FullStorageBackend {\n\tprivate storage = new Map<string, StorageEntry>();\n\tprivate reservations = new Map<string, UploadReservation>();\n\treadonly #reservationsByPath = new Map<string, string>(); // \"owner:path\" -> reservationId\n\tprivate reservationCounter = 0;\n\treadonly #quotaLimitsPerUser = new Map<string, QuotaLimits>();\n\n\tprivate readonly quotaConfig: QuotaConfig = {\n\t\tmaxObjectsPerUser: 1000,\n\t\tmaxStoragePerUser: 100 * 1024 * 1024 // 100MB\n\t};\n\n\t/**\n\t * Prune expired reservations to keep quota accounting accurate.\n\t */\n\t#pruneExpiredReservations(): void {\n\t\tconst now = Date.now();\n\t\tfor (const [id, reservation] of this.reservations) {\n\t\t\tif (new Date(reservation.expiresAt).getTime() <= now) {\n\t\t\t\tthis.reservations.delete(id);\n\t\t\t\tthis.#reservationsByPath.delete(`${reservation.owner}:${reservation.path}`);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync put(path: string, data: Buffer, metadata: StoragePutMetadata): Promise<StorageObjectMetadata> {\n\t\treturn(putToStorage(this.storage, path, data, metadata));\n\t}\n\n\tasync get(path: string): Promise<StorageGetResult | null> {\n\t\treturn(getFromStorage(this.storage, path));\n\t}\n\n\tasync delete(path: string): Promise<boolean> {\n\t\treturn(this.storage.delete(path));\n\t}\n\n\tasync updateMetadata(path: string, metadata: Omit<StoragePutMetadata, 'owner'>): Promise<StorageObjectMetadata | null> {\n\t\tconst entry = this.storage.get(path);\n\t\tif (!entry) {\n\t\t\treturn(null);\n\t\t}\n\n\t\tconst now = new Date().toISOString();\n\t\tconst updated: StorageObjectMetadata = {\n\t\t\t...entry.metadata,\n\t\t\ttags: metadata.tags,\n\t\t\tvisibility: metadata.visibility,\n\t\t\tupdatedAt: now\n\t\t};\n\n\t\tthis.storage.set(path, { data: entry.data, metadata: updated });\n\t\treturn(updated);\n\t}\n\n\tasync search(criteria: SearchCriteria, pagination: SearchPagination): Promise<SearchResults> {\n\t\treturn(searchStorage(this.storage, criteria, pagination));\n\t}\n\n\tasync getQuotaStatus(owner: string): Promise<QuotaStatus> {\n\t\t// Prune expired reservations first\n\t\tthis.#pruneExpiredReservations();\n\n\t\t// Get base quota from actual storage\n\t\tconst baseQuota = computeQuotaStatus(this.storage, owner, this.quotaConfig);\n\n\t\t// Add pending reservations for this owner\n\t\tlet reservedObjects = 0;\n\t\tlet reservedSize = 0;\n\t\tfor (const reservation of this.reservations.values()) {\n\t\t\tif (reservation.owner === owner) {\n\t\t\t\t// Only count as new object if path doesn't exist\n\t\t\t\tif (!this.storage.has(reservation.path)) {\n\t\t\t\t\treservedObjects++;\n\t\t\t\t}\n\n\t\t\t\treservedSize += reservation.size;\n\t\t\t}\n\t\t}\n\n\t\tconst objectCount = baseQuota.objectCount + reservedObjects;\n\t\tconst totalSize = baseQuota.totalSize + reservedSize;\n\t\tconst remainingObjects = Math.max(0, (baseQuota.remainingObjects ?? 0) - reservedObjects);\n\t\tconst remainingSize = Math.max(0, (baseQuota.remainingSize ?? 0) - reservedSize);\n\t\treturn({\n\t\t\tobjectCount,\n\t\t\ttotalSize,\n\t\t\tremainingObjects,\n\t\t\tremainingSize\n\t\t});\n\t}\n\n\tasync getQuotaLimits(owner: string): Promise<QuotaLimits | null> {\n\t\treturn(this.#quotaLimitsPerUser.get(owner) ?? null);\n\t}\n\n\tsetQuotaLimits(owner: string, limits: QuotaLimits): void {\n\t\tthis.#quotaLimitsPerUser.set(owner, limits);\n\t}\n\n\tasync reserveUpload(owner: string, path: string, size: number, options?: {\n\t\tttlMs?: number;\n\t\tquotaLimits?: { maxObjectsPerUser: number; maxStoragePerUser: number };\n\t}): Promise<UploadReservation> {\n\t\t// Validate size parameter\n\t\tif (size < 0) {\n\t\t\tthrow(new Errors.InvariantViolation('Reservation size cannot be negative'));\n\t\t}\n\n\t\t// Prune expired reservations first\n\t\tthis.#pruneExpiredReservations();\n\n\t\t// Default TTL: 5 minutes\n\t\tconst DEFAULT_RESERVATION_TTL_MS = 5 * 60 * 1000;\n\t\tconst ttl = options?.ttlMs ?? DEFAULT_RESERVATION_TTL_MS;\n\n\t\t// Use provided quota limits or fall back to backend defaults\n\t\tconst limits = options?.quotaLimits ?? this.quotaConfig;\n\n\t\t// Check if this would exceed quota\n\t\tconst quotaStatus = await this.getQuotaStatus(owner);\n\t\tconst isNewObject = !this.storage.has(path);\n\t\tconst existingSize = this.storage.get(path)?.data.length ?? 0;\n\t\tconst sizeDelta = size - existingSize;\n\n\t\t// Calculate remaining based on provided limits\n\t\tconst remainingObjects = limits.maxObjectsPerUser - quotaStatus.objectCount;\n\t\tconst remainingSize = limits.maxStoragePerUser - quotaStatus.totalSize;\n\n\t\tif (isNewObject && remainingObjects <= 0) {\n\t\t\tthrow(new Errors.QuotaExceeded({\n\t\t\t\tquotaType: 'maxObjectsPerUser',\n\t\t\t\tlimit: limits.maxObjectsPerUser,\n\t\t\t\tcurrent: quotaStatus.objectCount\n\t\t\t}));\n\t\t}\n\n\t\tif (sizeDelta > 0 && remainingSize < sizeDelta) {\n\t\t\tthrow(new Errors.QuotaExceeded({\n\t\t\t\tquotaType: 'maxStoragePerUser',\n\t\t\t\tlimit: limits.maxStoragePerUser,\n\t\t\t\tcurrent: quotaStatus.totalSize + sizeDelta\n\t\t\t}));\n\t\t}\n\n\t\t// Check for existing reservation for this (owner, path)\n\t\t// If a reservation already exists, we calculate the additional quota needed\n\t\t// by comparing the new sizeDelta with the existing reservation's reserved size.\n\t\tconst pathKey = `${owner}:${path}`;\n\t\tconst existingId = this.#reservationsByPath.get(pathKey);\n\t\tif (existingId) {\n\t\t\tconst existing = this.reservations.get(existingId);\n\t\t\tif (existing) {\n\t\t\t\tconst clampedSizeDelta = Math.max(0, sizeDelta);\n\t\t\t\tconst additionalSize = clampedSizeDelta - existing.size;\n\n\t\t\t\t// Re-check quota if size is increasing beyond current reservation\n\t\t\t\tif (additionalSize > 0 && remainingSize < additionalSize) {\n\t\t\t\t\tthrow(new Errors.QuotaExceeded({\n\t\t\t\t\t\tquotaType: 'maxStoragePerUser',\n\t\t\t\t\t\tlimit: limits.maxStoragePerUser,\n\t\t\t\t\t\tcurrent: quotaStatus.totalSize + additionalSize\n\t\t\t\t\t}));\n\t\t\t\t}\n\n\t\t\t\t// Update to max size, extend expiry\n\t\t\t\texisting.size = Math.max(existing.size, clampedSizeDelta);\n\t\t\t\texisting.expiresAt = new Date(Date.now() + ttl).toISOString();\n\t\t\t\treturn(existing);\n\t\t\t}\n\t\t}\n\n\t\tconst now = new Date();\n\t\tconst reservation: UploadReservation = {\n\t\t\tid: `res_${++this.reservationCounter}`,\n\t\t\towner,\n\t\t\tpath,\n\t\t\tsize: Math.max(0, sizeDelta),\n\t\t\tcreatedAt: now.toISOString(),\n\t\t\texpiresAt: new Date(now.getTime() + ttl).toISOString()\n\t\t};\n\n\t\tthis.reservations.set(reservation.id, reservation);\n\t\tthis.#reservationsByPath.set(pathKey, reservation.id);\n\t\treturn(reservation);\n\t}\n\n\tasync commitUpload(reservationId: string): Promise<void> {\n\t\t// Simply remove the reservation - the actual storage was already updated via put()\n\t\tconst reservation = this.reservations.get(reservationId);\n\t\tif (reservation) {\n\t\t\tthis.#reservationsByPath.delete(`${reservation.owner}:${reservation.path}`);\n\t\t}\n\n\t\tthis.reservations.delete(reservationId);\n\t}\n\n\tasync releaseUpload(reservationId: string): Promise<void> {\n\t\t// Remove the reservation, freeing the reserved quota\n\t\tconst reservation = this.reservations.get(reservationId);\n\t\tif (reservation) {\n\t\t\tthis.#reservationsByPath.delete(`${reservation.owner}:${reservation.path}`);\n\t\t}\n\n\t\tthis.reservations.delete(reservationId);\n\t}\n\n\tclear(): void {\n\t\tthis.storage.clear();\n\t\tthis.reservations.clear();\n\t\tthis.#reservationsByPath.clear();\n\t}\n\n\tget size(): number {\n\t\treturn(this.storage.size);\n\t}\n}\n\n// #endregion\n\n// #region Shared Test Harness\n\nexport type Account = InstanceType<typeof KeetaNet.lib.Account>;\n\nexport function randomSeed(): string | ArrayBuffer {\n\treturn(KeetaNet.lib.Account.generateRandomSeed());\n}\n\nexport interface StorageProviderTestContext {\n\tprovider: KeetaStorageAnchorProvider;\n\taccount: Account;\n\tstorageClient: KeetaStorageAnchorClient;\n}\n\n/**\n * Shared test harness that stands up a storage server, resolves a provider,\n * and passes the provider context to the test function.\n */\nexport async function withStorageProvider(\n\tseed: string | ArrayBuffer,\n\ttestFunction: (ctx: StorageProviderTestContext) => Promise<void>\n): Promise<void> {\n\tconst account = KeetaNet.lib.Account.fromSeed(seed, 0);\n\tconst anchorAccount = KeetaNet.lib.Account.fromSeed(seed, 50);\n\n\tawait using nodeAndClient = await createNodeAndClient(account);\n\n\tconst userClient = nodeAndClient.userClient;\n\tnodeAndClient.fees.disable();\n\n\tconst backend = new MemoryStorageBackend();\n\n\tawait using server = new KeetaNetStorageAnchorHTTPServer({\n\t\tbackend,\n\t\tanchorAccount,\n\t\tpathPolicies: [testPathPolicy]\n\t});\n\n\tawait server.start();\n\n\tconst rootAccount = KeetaNet.lib.Account.fromSeed(seed, 100);\n\tconst serviceMetadata = await server.serviceMetadata();\n\n\tawait setResolverInfo(rootAccount, userClient, {\n\t\tversion: 1,\n\t\tcurrencyMap: {},\n\t\tservices: {\n\t\t\tstorage: {\n\t\t\t\t'test-provider': serviceMetadata\n\t\t\t}\n\t\t}\n\t});\n\n\tconst resolver = new KeetaAnchorResolver({\n\t\troot: rootAccount,\n\t\tclient: userClient,\n\t\ttrustedCAs: []\n\t});\n\n\tconst storageClient = new KeetaStorageAnchorClient(userClient, { resolver });\n\tconst maybeProvider = await storageClient.getProviderByID('test-provider');\n\tif (!maybeProvider) {\n\t\tthrow(new Error('Provider not found'));\n\t}\n\n\tawait testFunction({ provider: maybeProvider, account, storageClient });\n}\n\n// #endregion\n"]}
|
|
1
|
+
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../../src/services/storage/test-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tPathPolicy,\n\tPathPolicyContext,\n\tFullStorageBackend,\n\tStorageObjectMetadata,\n\tStoragePutMetadata,\n\tStorageGetResult,\n\tSearchCriteria,\n\tSearchPagination,\n\tSearchResults,\n\tQuotaStatus,\n\tQuotaLimits,\n\tUploadReservation\n} from './common.js';\nimport type { KeetaStorageAnchorProvider } from './client.js';\nimport { KeetaNet } from '../../client/index.js';\nimport { createNodeAndClient, setResolverInfo } from '../../lib/utils/tests/node.js';\nimport { KeetaNetStorageAnchorHTTPServer } from './server.js';\nimport { Errors } from './common.js';\nimport { Buffer } from '../../lib/utils/buffer.js';\nimport KeetaAnchorResolver from '../../lib/resolver.js';\nimport KeetaStorageAnchorClient from './client.js';\n\n// #region Test Path Policy\n\n/**\n * Parsed path for the test path policy: /user/<pubkey>/<relativePath>\n */\nexport type TestParsedPath = {\n\tpath: string;\n\towner: string;\n\trelativePath: string;\n};\n\n/**\n * Test path policy implementing the /user/<pubkey>/<path> pattern.\n * Owner-based access control: only the owner can access their namespace.\n */\nexport class TestPathPolicy implements PathPolicy<TestParsedPath> {\n\t// Matches /user/<owner> or /user/<owner>/ or /user/<owner>/<path>\n\treadonly #pattern = /^\\/user\\/([^/]+)(\\/(.*))?$/;\n\n\tparse(path: string): TestParsedPath | null {\n\t\tconst match = path.match(this.#pattern);\n\t\tif (!match?.[1]) {\n\t\t\treturn(null);\n\t\t}\n\n\t\treturn({ path, owner: match[1], relativePath: match[3] ?? '' });\n\t}\n\n\tvalidate(path: string): TestParsedPath {\n\t\tconst parsed = this.parse(path);\n\t\tif (!parsed) {\n\t\t\tthrow(new Errors.InvalidPath('Path must match /user/<pubkey>/<path>'));\n\t\t}\n\n\t\t// Reject empty segments in original path\n\t\tif (path.includes('//')) {\n\t\t\tthrow(new Errors.InvalidPath('Path contains empty segments'));\n\t\t}\n\n\t\t// Reject path traversal attempts\n\t\tconst segments = parsed.relativePath.split('/');\n\t\tfor (const seg of segments) {\n\t\t\tif (seg === '..' || seg === '.') {\n\t\t\t\tthrow(new Errors.InvalidPath('Path contains relative segments'));\n\t\t\t}\n\t\t}\n\n\t\treturn(parsed);\n\t}\n\n\tisValid(path: string): boolean {\n\t\treturn(this.parse(path) !== null);\n\t}\n\n\tcheckAccess(\n\t\taccount: InstanceType<typeof KeetaNet.lib.Account>,\n\t\tparsed: TestParsedPath,\n\t\t_ignoreOperation: 'get' | 'put' | 'delete' | 'search' | 'metadata'\n\t): boolean {\n\t\t// Owner-based access: account must match the path owner\n\t\treturn(parsed.owner === account.publicKeyString.get());\n\t}\n\n\tgetAuthorizedSigner(parsed: TestParsedPath): InstanceType<typeof KeetaNet.lib.Account> | null {\n\t\treturn(KeetaNet.lib.Account.fromPublicKeyString(parsed.owner).assertAccount());\n\t}\n\n\tgetOwner(path: string): string {\n\t\treturn(this.validate(path).owner);\n\t}\n\n\tvalidateContext(parsed: TestParsedPath, context: PathPolicyContext): void {\n\t\tif (context.operation === 'put' || context.operation === 'updateMetadata') {\n\t\t\tif (parsed.relativePath.startsWith('public/') && context.metadata.visibility !== 'public') {\n\t\t\t\tthrow(new Errors.InvalidMetadata('Objects under /public/ must have public visibility'));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper to construct a path for a given owner and relative path.\n\t */\n\tmakePath(owner: string, relativePath: string): string {\n\t\treturn(`/user/${owner}/${relativePath}`);\n\t}\n\n\t/**\n\t * Helper to get the namespace prefix for an owner.\n\t */\n\tgetNamespacePrefix(owner: string): string {\n\t\treturn(`/user/${owner}/`);\n\t}\n}\n\n/**\n * Shared instance of TestPathPolicy for use in tests.\n */\nexport const testPathPolicy: TestPathPolicy = new TestPathPolicy();\n\n/**\n * Create test metadata with sensible defaults.\n */\nexport function testMetadata(\n\towner: string,\n\toverrides?: Partial<StoragePutMetadata>\n): StoragePutMetadata {\n\treturn({\n\t\towner,\n\t\ttags: [],\n\t\tvisibility: 'private',\n\t\t...overrides\n\t});\n}\n\n/**\n * Create test object metadata with sensible defaults.\n */\nexport function testObjectMetadata(\n\tpath: string,\n\towner: string,\n\toverrides?: Partial<StorageObjectMetadata>\n): StorageObjectMetadata {\n\treturn({\n\t\tpath,\n\t\towner,\n\t\ttags: [],\n\t\tvisibility: 'private',\n\t\tsize: 0,\n\t\tcreatedAt: new Date().toISOString(),\n\t\t...overrides\n\t});\n}\n\n// #endregion\n\n// #region Types\n\ntype StorageEntry = {\n\tdata: Buffer;\n\tmetadata: StorageObjectMetadata;\n};\n\ntype QuotaConfig = {\n\tmaxObjectsPerUser: number;\n\tmaxStoragePerUser: number;\n};\n\n// #endregion\n\n// #region Shared Storage Operations\n\nfunction putToStorage(\n\tstorage: Map<string, StorageEntry>,\n\tpath: string,\n\tdata: Buffer,\n\tmetadata: StoragePutMetadata\n): StorageObjectMetadata {\n\tconst now = new Date().toISOString();\n\tconst existing = storage.get(path);\n\tconst objectMetadata: StorageObjectMetadata = {\n\t\tpath,\n\t\towner: metadata.owner,\n\t\ttags: metadata.tags,\n\t\tvisibility: metadata.visibility,\n\t\tsize: data.length,\n\t\tcreatedAt: existing?.metadata.createdAt ?? now,\n\t\t...(existing ? { updatedAt: now } : {})\n\t};\n\n\tstorage.set(path, { data, metadata: objectMetadata });\n\treturn(objectMetadata);\n}\n\nfunction getFromStorage(\n\tstorage: Map<string, StorageEntry>,\n\tpath: string\n): StorageGetResult | null {\n\tconst entry = storage.get(path);\n\tif (!entry) {\n\t\treturn(null);\n\t}\n\n\treturn({\n\t\tdata: Buffer.from(entry.data),\n\t\tmetadata: { ...entry.metadata }\n\t});\n}\n\nfunction searchStorage(\n\tstorage: Map<string, StorageEntry>,\n\tcriteria: SearchCriteria,\n\tpagination: SearchPagination\n): SearchResults {\n\tconst results: StorageObjectMetadata[] = [];\n\tconst limit = pagination.limit ?? 100;\n\tconst startAfter = pagination.cursor;\n\tlet foundCursor = !startAfter;\n\n\tfor (const [path, entry] of storage.entries()) {\n\t\tif (!foundCursor) {\n\t\t\tif (path === startAfter) {\n\t\t\t\tfoundCursor = true;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst metadata = entry.metadata;\n\n\t\tif (criteria.pathPrefix) {\n\t\t\tconst prefix = criteria.pathPrefix.endsWith('/')\n\t\t\t\t? criteria.pathPrefix\n\t\t\t\t: criteria.pathPrefix + '/';\n\t\t\tif (!path.startsWith(prefix) && path !== criteria.pathPrefix) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!criteria.recursive) {\n\t\t\t\tconst remainder = path.slice(prefix.length);\n\t\t\t\tif (remainder.includes('/')) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (criteria.owner && metadata.owner !== criteria.owner) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (criteria.tags && criteria.tags.length > 0) {\n\t\t\tconst hasMatchingTag = criteria.tags.some(function(tag) {\n\t\t\t\treturn(metadata.tags.includes(tag));\n\t\t\t});\n\t\t\tif (!hasMatchingTag) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (criteria.name) {\n\t\t\tconst filename = path.split('/').pop();\n\t\t\tif (!filename?.includes(criteria.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (criteria.visibility && metadata.visibility !== criteria.visibility) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tresults.push(metadata);\n\n\t\tif (results.length >= limit) {\n\t\t\treturn({ results, nextCursor: path });\n\t\t}\n\t}\n\n\treturn({ results });\n}\n\nfunction computeQuotaStatus(\n\tstorage: Map<string, StorageEntry>,\n\towner: string,\n\tquotaConfig: QuotaConfig\n): QuotaStatus {\n\tlet objectCount = 0;\n\tlet totalSize = 0;\n\tfor (const entry of storage.values()) {\n\t\tif (entry.metadata.owner === owner) {\n\t\t\tobjectCount++;\n\n\t\t\ttotalSize += entry.metadata.size;\n\t\t}\n\t}\n\n\treturn({\n\t\tobjectCount,\n\t\ttotalSize,\n\t\tremainingObjects: Math.max(0, quotaConfig.maxObjectsPerUser - objectCount),\n\t\tremainingSize: Math.max(0, quotaConfig.maxStoragePerUser - totalSize)\n\t});\n}\n\n// #endregion\n\n// #region Memory Storage Backend\n\n/**\n * In-memory storage backend with full capabilities: CRUD, search, and quota management.\n * Intended for testing and development purposes.\n */\nexport class MemoryStorageBackend implements FullStorageBackend {\n\tprivate storage = new Map<string, StorageEntry>();\n\tprivate reservations = new Map<string, UploadReservation>();\n\treadonly #reservationsByPath = new Map<string, string>(); // \"owner:path\" -> reservationId\n\tprivate reservationCounter = 0;\n\treadonly #quotaLimitsPerUser = new Map<string, QuotaLimits>();\n\n\tprivate readonly quotaConfig: QuotaConfig = {\n\t\tmaxObjectsPerUser: 1000,\n\t\tmaxStoragePerUser: 100 * 1024 * 1024 // 100MB\n\t};\n\n\t/**\n\t * Prune expired reservations to keep quota accounting accurate.\n\t */\n\t#pruneExpiredReservations(): void {\n\t\tconst now = Date.now();\n\t\tfor (const [id, reservation] of this.reservations) {\n\t\t\tif (new Date(reservation.expiresAt).getTime() <= now) {\n\t\t\t\tthis.reservations.delete(id);\n\t\t\t\tthis.#reservationsByPath.delete(`${reservation.owner}:${reservation.path}`);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync put(path: string, data: Buffer, metadata: StoragePutMetadata): Promise<StorageObjectMetadata> {\n\t\treturn(putToStorage(this.storage, path, data, metadata));\n\t}\n\n\tasync get(path: string): Promise<StorageGetResult | null> {\n\t\treturn(getFromStorage(this.storage, path));\n\t}\n\n\tasync delete(path: string): Promise<boolean> {\n\t\treturn(this.storage.delete(path));\n\t}\n\n\tasync updateMetadata(path: string, metadata: Omit<StoragePutMetadata, 'owner'>): Promise<StorageObjectMetadata | null> {\n\t\tconst entry = this.storage.get(path);\n\t\tif (!entry) {\n\t\t\treturn(null);\n\t\t}\n\n\t\tconst now = new Date().toISOString();\n\t\tconst updated: StorageObjectMetadata = {\n\t\t\t...entry.metadata,\n\t\t\ttags: metadata.tags,\n\t\t\tvisibility: metadata.visibility,\n\t\t\tupdatedAt: now\n\t\t};\n\n\t\tthis.storage.set(path, { data: entry.data, metadata: updated });\n\t\treturn(updated);\n\t}\n\n\tasync search(criteria: SearchCriteria, pagination: SearchPagination): Promise<SearchResults> {\n\t\treturn(searchStorage(this.storage, criteria, pagination));\n\t}\n\n\tasync getQuotaStatus(owner: string): Promise<QuotaStatus> {\n\t\t// Prune expired reservations first\n\t\tthis.#pruneExpiredReservations();\n\n\t\t// Get base quota from actual storage\n\t\tconst baseQuota = computeQuotaStatus(this.storage, owner, this.quotaConfig);\n\n\t\t// Add pending reservations for this owner\n\t\tlet reservedObjects = 0;\n\t\tlet reservedSize = 0;\n\t\tfor (const reservation of this.reservations.values()) {\n\t\t\tif (reservation.owner === owner) {\n\t\t\t\t// Only count as new object if path doesn't exist\n\t\t\t\tif (!this.storage.has(reservation.path)) {\n\t\t\t\t\treservedObjects++;\n\t\t\t\t}\n\n\t\t\t\treservedSize += reservation.size;\n\t\t\t}\n\t\t}\n\n\t\tconst objectCount = baseQuota.objectCount + reservedObjects;\n\t\tconst totalSize = baseQuota.totalSize + reservedSize;\n\t\tconst remainingObjects = Math.max(0, (baseQuota.remainingObjects ?? 0) - reservedObjects);\n\t\tconst remainingSize = Math.max(0, (baseQuota.remainingSize ?? 0) - reservedSize);\n\t\treturn({\n\t\t\tobjectCount,\n\t\t\ttotalSize,\n\t\t\tremainingObjects,\n\t\t\tremainingSize\n\t\t});\n\t}\n\n\tasync getQuotaLimits(owner: string): Promise<QuotaLimits | null> {\n\t\treturn(this.#quotaLimitsPerUser.get(owner) ?? null);\n\t}\n\n\tsetQuotaLimits(owner: string, limits: QuotaLimits): void {\n\t\tthis.#quotaLimitsPerUser.set(owner, limits);\n\t}\n\n\tasync reserveUpload(owner: string, path: string, size: number, options?: {\n\t\tttlMs?: number;\n\t\tquotaLimits?: { maxObjectsPerUser: number; maxStoragePerUser: number };\n\t}): Promise<UploadReservation> {\n\t\t// Validate size parameter\n\t\tif (size < 0) {\n\t\t\tthrow(new Errors.InvariantViolation('Reservation size cannot be negative'));\n\t\t}\n\n\t\t// Prune expired reservations first\n\t\tthis.#pruneExpiredReservations();\n\n\t\t// Default TTL: 5 minutes\n\t\tconst DEFAULT_RESERVATION_TTL_MS = 5 * 60 * 1000;\n\t\tconst ttl = options?.ttlMs ?? DEFAULT_RESERVATION_TTL_MS;\n\n\t\t// Use provided quota limits or fall back to backend defaults\n\t\tconst limits = options?.quotaLimits ?? this.quotaConfig;\n\n\t\t// Check if this would exceed quota\n\t\tconst quotaStatus = await this.getQuotaStatus(owner);\n\t\tconst isNewObject = !this.storage.has(path);\n\t\tconst existingSize = this.storage.get(path)?.data.length ?? 0;\n\t\tconst sizeDelta = size - existingSize;\n\n\t\t// Calculate remaining based on provided limits\n\t\tconst remainingObjects = limits.maxObjectsPerUser - quotaStatus.objectCount;\n\t\tconst remainingSize = limits.maxStoragePerUser - quotaStatus.totalSize;\n\n\t\tif (isNewObject && remainingObjects <= 0) {\n\t\t\tthrow(new Errors.QuotaExceeded({\n\t\t\t\tquotaType: 'maxObjectsPerUser',\n\t\t\t\tlimit: limits.maxObjectsPerUser,\n\t\t\t\tcurrent: quotaStatus.objectCount\n\t\t\t}));\n\t\t}\n\n\t\tif (sizeDelta > 0 && remainingSize < sizeDelta) {\n\t\t\tthrow(new Errors.QuotaExceeded({\n\t\t\t\tquotaType: 'maxStoragePerUser',\n\t\t\t\tlimit: limits.maxStoragePerUser,\n\t\t\t\tcurrent: quotaStatus.totalSize + sizeDelta\n\t\t\t}));\n\t\t}\n\n\t\t// Check for existing reservation for this (owner, path)\n\t\t// If a reservation already exists, we calculate the additional quota needed\n\t\t// by comparing the new sizeDelta with the existing reservation's reserved size.\n\t\tconst pathKey = `${owner}:${path}`;\n\t\tconst existingId = this.#reservationsByPath.get(pathKey);\n\t\tif (existingId) {\n\t\t\tconst existing = this.reservations.get(existingId);\n\t\t\tif (existing) {\n\t\t\t\tconst clampedSizeDelta = Math.max(0, sizeDelta);\n\t\t\t\tconst additionalSize = clampedSizeDelta - existing.size;\n\n\t\t\t\t// Re-check quota if size is increasing beyond current reservation\n\t\t\t\tif (additionalSize > 0 && remainingSize < additionalSize) {\n\t\t\t\t\tthrow(new Errors.QuotaExceeded({\n\t\t\t\t\t\tquotaType: 'maxStoragePerUser',\n\t\t\t\t\t\tlimit: limits.maxStoragePerUser,\n\t\t\t\t\t\tcurrent: quotaStatus.totalSize + additionalSize\n\t\t\t\t\t}));\n\t\t\t\t}\n\n\t\t\t\t// Update to max size, extend expiry\n\t\t\t\texisting.size = Math.max(existing.size, clampedSizeDelta);\n\t\t\t\texisting.expiresAt = new Date(Date.now() + ttl).toISOString();\n\t\t\t\treturn(existing);\n\t\t\t}\n\t\t}\n\n\t\tconst now = new Date();\n\t\tconst reservation: UploadReservation = {\n\t\t\tid: `res_${++this.reservationCounter}`,\n\t\t\towner,\n\t\t\tpath,\n\t\t\tsize: Math.max(0, sizeDelta),\n\t\t\tcreatedAt: now.toISOString(),\n\t\t\texpiresAt: new Date(now.getTime() + ttl).toISOString()\n\t\t};\n\n\t\tthis.reservations.set(reservation.id, reservation);\n\t\tthis.#reservationsByPath.set(pathKey, reservation.id);\n\t\treturn(reservation);\n\t}\n\n\tasync commitUpload(reservationId: string): Promise<void> {\n\t\t// Simply remove the reservation - the actual storage was already updated via put()\n\t\tconst reservation = this.reservations.get(reservationId);\n\t\tif (reservation) {\n\t\t\tthis.#reservationsByPath.delete(`${reservation.owner}:${reservation.path}`);\n\t\t}\n\n\t\tthis.reservations.delete(reservationId);\n\t}\n\n\tasync releaseUpload(reservationId: string): Promise<void> {\n\t\t// Remove the reservation, freeing the reserved quota\n\t\tconst reservation = this.reservations.get(reservationId);\n\t\tif (reservation) {\n\t\t\tthis.#reservationsByPath.delete(`${reservation.owner}:${reservation.path}`);\n\t\t}\n\n\t\tthis.reservations.delete(reservationId);\n\t}\n\n\tclear(): void {\n\t\tthis.storage.clear();\n\t\tthis.reservations.clear();\n\t\tthis.#reservationsByPath.clear();\n\t}\n\n\tget size(): number {\n\t\treturn(this.storage.size);\n\t}\n}\n\n// #endregion\n\n// #region Shared Test Harness\n\nexport type Account = InstanceType<typeof KeetaNet.lib.Account>;\n\nexport function randomSeed(): string | ArrayBuffer {\n\treturn(KeetaNet.lib.Account.generateRandomSeed());\n}\n\nexport interface StorageProviderTestContext {\n\tprovider: KeetaStorageAnchorProvider;\n\taccount: Account;\n\tstorageClient: KeetaStorageAnchorClient;\n}\n\n/**\n * Shared test harness that stands up a storage server, resolves a provider,\n * and passes the provider context to the test function.\n */\nexport async function withStorageProvider(\n\tseed: string | ArrayBuffer,\n\ttestFunction: (ctx: StorageProviderTestContext) => Promise<void>\n): Promise<void> {\n\tconst account = KeetaNet.lib.Account.fromSeed(seed, 0);\n\tconst anchorAccount = KeetaNet.lib.Account.fromSeed(seed, 50);\n\n\tawait using nodeAndClient = await createNodeAndClient(account);\n\n\tconst userClient = nodeAndClient.userClient;\n\tnodeAndClient.fees.disable();\n\n\tconst backend = new MemoryStorageBackend();\n\n\tawait using server = new KeetaNetStorageAnchorHTTPServer({\n\t\tbackend,\n\t\tanchorAccount,\n\t\tpathPolicies: [testPathPolicy]\n\t});\n\n\tawait server.start();\n\n\tconst rootAccount = KeetaNet.lib.Account.fromSeed(seed, 100);\n\tconst serviceMetadata = await server.serviceMetadata();\n\n\tawait setResolverInfo(rootAccount, userClient, {\n\t\tversion: 1,\n\t\tcurrencyMap: {},\n\t\tservices: {\n\t\t\tstorage: {\n\t\t\t\t'test-provider': serviceMetadata\n\t\t\t}\n\t\t}\n\t});\n\n\tconst resolver = new KeetaAnchorResolver({\n\t\troot: rootAccount,\n\t\tclient: userClient,\n\t\ttrustedCAs: []\n\t});\n\n\tconst storageClient = new KeetaStorageAnchorClient(userClient, { resolver });\n\tconst maybeProvider = await storageClient.getProviderByID('test-provider');\n\tif (!maybeProvider) {\n\t\tthrow(new Error('Provider not found'));\n\t}\n\n\tawait testFunction({ provider: maybeProvider, account, storageClient });\n}\n\n// #endregion\n"]}
|