From 2f42de15bc55ffcf7c3d45fc350f9c50813dd711 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Fri, 23 Jan 2026 15:33:12 +0100 Subject: [PATCH 01/14] chore: update node-appwrite SDK from v2.2.3 to v21.1.0 This is the first step in migrating the extension to support the latest Appwrite SDK and API (compatible with Appwrite 1.8.x). Breaking changes to address in subsequent commits: - Database API now requires databaseId parameter - Storage API now requires bucketId parameter - Functions: Tags renamed to Deployments - Health: method names updated - Permission system updated with helper classes Co-Authored-By: Claude Opus 4.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 13b816a..5019e78 100644 --- a/package.json +++ b/package.json @@ -770,7 +770,7 @@ "cronstrue": "^1.113.0", "dayjs": "^1.10.4", "fs-extra": "^9.1.0", - "node-appwrite": "^2.2.3", + "node-appwrite": "^21.1.0", "tar": "^6.1.0" } } From dbce216813698bf74ac1ec131c69fd1b08677b5a Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Fri, 23 Jan 2026 15:35:17 +0100 Subject: [PATCH 02/14] refactor: update type definitions for SDK v21 Major type definition changes: - Add Database entity type (databaseId now required) - Add Bucket entity type (bucketId now required) - Rename Tag to Deployment throughout - Add new health check types (PubSub, Storage, etc.) - Add helper types (Permission, Role, Query, ID) - Update User type with new fields (mfa, targets, labels) - Update Function type (runtime replaces env, deployment replaces tag) - Update Execution type with new request/response fields - Deprecate old types with @deprecated annotations - Add DatabasesClient (replaces DatabaseClient) Co-Authored-By: Claude Opus 4.5 --- src/appwrite.d.ts | 976 +++++++++++++++++++++++++++++++--------------- 1 file changed, 653 insertions(+), 323 deletions(-) diff --git a/src/appwrite.d.ts b/src/appwrite.d.ts index dda0ed0..33864b6 100644 --- a/src/appwrite.d.ts +++ b/src/appwrite.d.ts @@ -1,454 +1,784 @@ import { ReadStream } from 'fs'; -import { Stream } from 'node:stream'; + +// ============================================================================ +// Common Types +// ============================================================================ export type Token = { - /** - * Token ID. - */ $id: string; - /** - * User ID. - */ + $createdAt: string; + $updatedAt: string; userId: string; - /** - * Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload. - */ secret: string; - /** - * Token expiration date in Unix timestamp. - */ - expire: number; + expire: string; + phrase: string; +}; + +export type Error = { + message: string; + code: number; + type: string; + version: string; }; +type ClientInfo = { + osCode: string; + osName: string; + osVersion: string; + clientType: string; + clientCode: string; + clientName: string; + clientVersion: string; + clientEngine: string; + clientEngineVersion: string; + deviceName: string; + deviceBrand: string; + deviceModel: string; + countryCode: string; + countryName: string; +}; + +// ============================================================================ +// User Types +// ============================================================================ + export type User = { - /** - * User ID. - */ $id: string; - /** - * User name. - */ + $createdAt: string; + $updatedAt: string; name: string; - /** - * User registration date in Unix timestamp. - */ - registration: number; - /** - * User status. 0 for Unactivated, 1 for active and 2 is blocked. - * @deprecated according to developers - */ - status: number; - /** - * User email address. - */ + password?: string; + hash?: string; + hashOptions?: Record; + registration: string; + status: boolean; + labels: string[]; + passwordUpdate: string; email: string; - /** - * Email verification status. - */ + phone: string; emailVerification: boolean; - /** - * User preferences as a key-value object - */ + phoneVerification: boolean; + mfa: boolean; prefs: Record; + targets: Target[]; + accessedAt: string; }; -export type UsersList = { - /** - * Total sum of items in the list. - */ - sum: number; - /** - * List of users. - */ - users: User[]; +export type Target = { + $id: string; + $createdAt: string; + $updatedAt: string; + name: string; + userId: string; + providerId?: string; + providerType: string; + identifier: string; }; -export type Error = { - /** - * Error message. - */ - message: string; - - /** - * Error code. - */ - code: string; - - /** - * Server version number. - */ - version: string; +export type UsersList = { + total: number; + users: User[]; }; export type Session = { - /** - * Session ID. - */ $id: string; - /** - * User ID. - */ + $createdAt: string; + $updatedAt: string; userId: string; - /** - * Session expiration date in Unix timestamp. - */ - expire: number; - /** - * IP in use when the session was created. - */ + expire: string; + provider: string; + providerUid: string; + providerAccessToken: string; + providerAccessTokenExpiry: string; + providerRefreshToken: string; ip: string; - /** - * Returns true if this the current user session. - */ + osCode: string; + osName: string; + osVersion: string; + clientType: string; + clientCode: string; + clientName: string; + clientVersion: string; + clientEngine: string; + clientEngineVersion: string; + deviceName: string; + deviceBrand: string; + deviceModel: string; + countryCode: string; + countryName: string; current: boolean; -} & ClientInfo; + factors: string[]; + secret: string; + mfaUpdatedAt: string; +}; + +export type SessionList = { + total: number; + sessions: Session[]; +}; export type Log = { - /** - * Event name. - */ event: string; - /** - * IP session in use when the session was created. - */ + userId: string; + userEmail: string; + userName: string; + mode: string; ip: string; - /** - * Log creation time in Unix timestamp. - */ - time: number; -} & ClientInfo; - -type ClientInfo = { - /** - * Operating system code name. View list of possible values: - * https://github.com/appwrite/appwrite/blob/master/docs/lists/os.json - */ + time: string; osCode: string; - /** - * Operating system name. - */ osName: string; - /** - * Operating system version. - */ osVersion: string; - /** - * Client type. - */ clientType: string; - /** - * Client code name. View list of possible values: - * https://github.com/appwrite/appwrite/blob/master/docs/lists/clients.json - */ clientCode: string; - /** - * Client name. - */ clientName: string; - /** - * Client version. - */ clientVersion: string; - /** - * Client engine name. - */ clientEngine: string; - /** - * Client engine version. - */ clientEngineVersion: string; - /** - * Device name. - */ deviceName: string; - /** - * Device brand name. - */ deviceBrand: string; - /** - * Device model name. - */ deviceModel: string; - /** - * Country two-character ISO 3166-1 alpha code. - */ countryCode: string; - /** - * Country name. - */ countryName: string; }; +export type LogsList = { + total: number; + logs: Log[]; +}; + +// ============================================================================ +// Team Types +// ============================================================================ + export type Team = { - /** - * Team ID. - */ $id: string; - /** - * Team name. - */ + $createdAt: string; + $updatedAt: string; name: string; - /** - * Team creation date in Unix timestamp. - */ - dateCreated: number; - /** - * Total sum of team members. - */ - sum: number; -}; - -type Membership = { - /** - * Membership ID. - */ - $id: string; + total: number; + prefs: Record; +}; - /** - * User ID. - */ +export type Membership = { + $id: string; + $createdAt: string; + $updatedAt: string; userId: string; - - /** - * Team ID. - */ + userName: string; + userEmail: string; teamId: string; - - /** - * User name. - */ - name: string; - - /** - * User email address. - */ - email: string; - - /** - * Date, the user has been invited to join the team in Unix timestamp. - */ - invited: number; - - /** - * Date, the user has accepted the invitation to join the team in Unix timestamp. - */ - joined: number; - - /** - * User confirmation status, true if the user has joined the team or false otherwise. - */ + teamName: string; + invited: string; + joined: string; confirm: boolean; - - /** - * User list of roles - */ + mfa: boolean; roles: string[]; }; -export type FilesList = { - sum: number; - files: File[]; -}; +// ============================================================================ +// Database Types +// ============================================================================ -export type File = { +export type Database = { $id: string; - $permissions: Permissions; name: string; - dateCreated: number; - signature: string; - mimeType: string; - sizeOriginal: number; + $createdAt: string; + $updatedAt: string; + enabled: boolean; +}; + +export type DatabasesList = { + total: number; + databases: Database[]; }; export type Collection = { $id: string; - $permissions: Permissions; + $createdAt: string; + $updatedAt: string; + $permissions: string[]; + databaseId: string; name: string; - dateCreated: number; - dateUpdated: number; - rules: Rule[]; + enabled: boolean; + documentSecurity: boolean; + attributes: Attribute[]; + indexes: Index[]; }; export type CreatedCollection = Partial & Pick; export type CollectionsList = { - sum: number; + total: number; collections: Collection[]; }; -export type CreatedRule = Omit; +export type Attribute = { + key: string; + type: string; + status: string; + error: string; + required: boolean; + array: boolean; + size?: number; + default?: unknown; + min?: number; + max?: number; + format?: string; + elements?: string[]; +}; + +export type AttributesList = { + total: number; + attributes: Attribute[]; +}; + +export type Index = { + key: string; + type: string; + status: string; + error: string; + attributes: string[]; + orders?: string[]; +}; + +export type IndexesList = { + total: number; + indexes: Index[]; +}; + +export type Document = { + $id: string; + $collectionId: string; + $databaseId: string; + $createdAt: string; + $updatedAt: string; + $permissions: string[]; + [key: string]: unknown; +}; +export type DocumentsList = { + total: number; + documents: Document[]; +}; + +/** @deprecated Use Attribute instead */ export type Rule = { $id: string; $collection: string; type: string; key: string; label: string; - default?: any; + default?: unknown; required: boolean; array: boolean; list?: string[]; }; +/** @deprecated Use Attribute instead */ +export type CreatedRule = Omit; + +/** @deprecated Use string[] permissions instead */ export type Permissions = { read: string[]; write: string[]; -} +}; -export type Client = { - // Your API Endpoint - setEndpoint: (endpoint: string) => Client; - // Your project ID - setProject: (projectId: string) => Client; - // Your secret API key - setKey: (key: string) => Client; - setSelfSigned: (value: boolean) => void; +// ============================================================================ +// Storage Types +// ============================================================================ + +export type Bucket = { + $id: string; + $createdAt: string; + $updatedAt: string; + $permissions: string[]; + fileSecurity: boolean; + name: string; + enabled: boolean; + maximumFileSize: number; + allowedFileExtensions: string[]; + compression: string; + encryption: boolean; + antivirus: boolean; }; -export type UsersClient = { - delete: (id: string) => Promise; - deleteSessions: (id: string) => Promise; - create: (email: string, password: string, name?: string) => Promise; - getLogs: (id: string) => Promise; + +export type BucketsList = { + total: number; + buckets: Bucket[]; }; -export type DatabaseClient = { - listCollections: () => Promise; - listDocuments: (collectionId: string) => Promise; - updateCollection: (collectionId: string, name: string, read: string[], write: string[], rules?: (Rule | CreatedRule)[]) => Promise; - deleteCollection: (collectionId: string) => Promise; - getCollection: (collectionId: string) => Promise; - deleteDocument: (collectionId: string, documentId: string) => Promise; - createCollection: (name: string, read: string[], write: string[], rules: Rule[]) => Promise; +export type File = { + $id: string; + $createdAt: string; + $updatedAt: string; + $permissions: string[]; + bucketId: string; + name: string; + signature: string; + mimeType: string; + sizeOriginal: number; + chunksTotal: number; + chunksUploaded: number; }; -export type DocumentsList = { - sum: number; - documents: any[]; +export type FilesList = { + total: number; + files: File[]; }; -type GetHealth = () => any; +// ============================================================================ +// Health Types +// ============================================================================ -export type HealthClient = { - get: GetHealth; - getDB: GetHealth; - getCache: GetHealth; - getTime: GetHealth; - getQueueWebhooks: GetHealth; - getQueueTasks: GetHealth; - getQueueLogs: GetHealth; - getQueueUsage: GetHealth; - getQueueCertificates: GetHealth; - getQueueFunctions: GetHealth; - getStorageLocal: GetHealth; - getAntiVirus: GetHealth; +export type HealthStatus = { + name: string; + ping: number; + status: string; +}; + +export type HealthTime = { + remoteTime: number; + localTime: number; + diff: number; +}; + +export type HealthQueue = { + size: number; +}; + +export type HealthAntivirus = { + version: string; + status: string; +}; + +export type HealthCertificate = { + name: string; + subjectSN: string; + issuerOrganisation: string; + validFrom: string; + validTo: string; + signatureTypeSN: string; }; export type AppwriteHealth = { - HTTP: any; - DB: any; - Cache: any; - Time: any; - QueueWebhooks: any; - QueueTasks: any; - QueueLogs: any; - QueueUsage: any; - QueueCertificates: any; - QueueFunctions: any; - StorageLocal: any; - AntiVirus: any; + HTTP: HealthStatus; + DB: HealthStatus; + Cache: HealthStatus; + PubSub: HealthStatus; + Time: HealthTime; + Storage: HealthStatus; + StorageLocal: HealthStatus; + Antivirus: HealthAntivirus; + QueueWebhooks: HealthQueue; + QueueLogs: HealthQueue; + QueueUsage: HealthQueue; + QueueCertificates: HealthQueue; + QueueFunctions: HealthQueue; + QueueBuilds: HealthQueue; + QueueMails: HealthQueue; + QueueMessaging: HealthQueue; + QueueMigrations: HealthQueue; + QueueDeletes: HealthQueue; }; -export type StorageClient = { - createFile: (file: any, read?: string[], write?: string[]) => Promise; - listFiles: () => Promise; - getFile: (fileId: string) => Promise; +// ============================================================================ +// Functions Types +// ============================================================================ + +export type Variable = { + $id: string; + $createdAt: string; + $updatedAt: string; + key: string; + value: string; + resourceType: string; + resourceId: string; }; -type Vars = Record; +export type VariableList = { + total: number; + variables: Variable[]; +}; export type Function = { - '$id': string; - '$permissions': Permissions; - name: string; - dateCreated: number; - dateUpdated: number; - status: string; - env: string; - tag: string; - vars: Vars; - events: string[]; - schedule: string; - scheduleNext: number; - schedulePrevious: number; - timeout: number; -} + $id: string; + $createdAt: string; + $updatedAt: string; + execute: string[]; + name: string; + enabled: boolean; + live: boolean; + logging: boolean; + runtime: string; + deployment: string; + scopes: string[]; + vars: Variable[]; + events: string[]; + schedule: string; + timeout: number; + entrypoint: string; + commands: string; + version: string; + installationId: string; + providerRepositoryId: string; + providerBranch: string; + providerRootDirectory: string; + providerSilentMode: boolean; +}; export type FunctionsList = { - sum: number; + total: number; functions: Function[]; -} +}; -export type Tag = { - '$id': string; - functionId: string; - dateCreated: number; - command: string; - size: string; +export type Deployment = { + $id: string; + $createdAt: string; + $updatedAt: string; + type: string; + resourceId: string; + resourceType: string; + entrypoint: string; + size: number; + buildId: string; + activate: boolean; + status: string; + buildLogs: string; + buildTime: number; + providerRepositoryName: string; + providerRepositoryOwner: string; + providerRepositoryUrl: string; + providerBranch: string; + providerCommitHash: string; + providerCommitAuthorUrl: string; + providerCommitAuthor: string; + providerCommitMessage: string; + providerCommitUrl: string; + providerBranchUrl: string; }; -export type TagList = { - sum: number; - tags: Tag[]; -} +export type DeploymentList = { + total: number; + deployments: Deployment[]; +}; -export type ExecutionStatus = "waiting" | "processing" | "completed" | "failed"; +/** @deprecated Use Deployment instead */ +export type Tag = Deployment; + +/** @deprecated Use DeploymentList instead */ +export type TagList = DeploymentList; + +export type ExecutionStatus = "waiting" | "processing" | "completed" | "failed" | "scheduled"; export type Execution = { - '$id': string; - functionId: string; - dateCreated: number; - trigger: string; - status: ExecutionStatus; - exitCode: number; - stdout: string; - stderr: string; - time: number; + $id: string; + $createdAt: string; + $updatedAt: string; + $permissions: string[]; + functionId: string; + trigger: string; + status: ExecutionStatus; + requestMethod: string; + requestPath: string; + requestHeaders: Header[]; + responseStatusCode: number; + responseBody: string; + responseHeaders: Header[]; + logs: string; + errors: string; + duration: number; + scheduledAt?: string; +}; + +export type Header = { + name: string; + value: string; }; export type ExecutionList = { - sum: number; + total: number; executions: Execution[]; }; -export type Search = { - search?: string; - limit?: number; - offset?: number; - orderType?: 'ASC' | 'DESC'; +// ============================================================================ +// Client Types +// ============================================================================ + +export type Client = { + setEndpoint: (endpoint: string) => Client; + setProject: (projectId: string) => Client; + setKey: (key: string) => Client; + setSelfSigned: (value?: boolean) => Client; + setJWT: (jwt: string) => Client; + setLocale: (locale: string) => Client; + setSession: (session: string) => Client; + setForwardedUserAgent: (userAgent: string) => Client; +}; + +// ============================================================================ +// Service Client Types +// ============================================================================ + +export type UsersClient = { + // User CRUD + create: (userId: string, email?: string, phone?: string, password?: string, name?: string) => Promise; + get: (userId: string) => Promise; + list: (queries?: string[], search?: string) => Promise; + delete: (userId: string) => Promise; + + // User updates + updateEmail: (userId: string, email: string) => Promise; + updateName: (userId: string, name: string) => Promise; + updatePassword: (userId: string, password: string) => Promise; + updatePhone: (userId: string, number: string) => Promise; + updateStatus: (userId: string, status: boolean) => Promise; + updateLabels: (userId: string, labels: string[]) => Promise; + updateEmailVerification: (userId: string, emailVerification: boolean) => Promise; + updatePhoneVerification: (userId: string, phoneVerification: boolean) => Promise; + updateMfa: (userId: string, mfa: boolean) => Promise; + + // Preferences + getPrefs: (userId: string) => Promise>; + updatePrefs: (userId: string, prefs: Record) => Promise>; + + // Sessions + listSessions: (userId: string) => Promise; + deleteSessions: (userId: string) => Promise; + deleteSession: (userId: string, sessionId: string) => Promise; + createSession: (userId: string) => Promise; + + // Logs + getLogs: (userId: string, queries?: string[]) => Promise; + + // Targets + listTargets: (userId: string, queries?: string[]) => Promise<{ total: number; targets: Target[] }>; +}; + +export type DatabasesClient = { + // Database CRUD + create: (databaseId: string, name: string, enabled?: boolean) => Promise; + get: (databaseId: string) => Promise; + list: (queries?: string[], search?: string) => Promise; + update: (databaseId: string, name: string, enabled?: boolean) => Promise; + delete: (databaseId: string) => Promise; + + // Collection CRUD + createCollection: (databaseId: string, collectionId: string, name: string, permissions?: string[], documentSecurity?: boolean, enabled?: boolean) => Promise; + getCollection: (databaseId: string, collectionId: string) => Promise; + listCollections: (databaseId: string, queries?: string[], search?: string) => Promise; + updateCollection: (databaseId: string, collectionId: string, name: string, permissions?: string[], documentSecurity?: boolean, enabled?: boolean) => Promise; + deleteCollection: (databaseId: string, collectionId: string) => Promise; + + // Document CRUD + createDocument: (databaseId: string, collectionId: string, documentId: string, data: Record, permissions?: string[]) => Promise; + getDocument: (databaseId: string, collectionId: string, documentId: string, queries?: string[]) => Promise; + listDocuments: (databaseId: string, collectionId: string, queries?: string[]) => Promise; + updateDocument: (databaseId: string, collectionId: string, documentId: string, data?: Record, permissions?: string[]) => Promise; + deleteDocument: (databaseId: string, collectionId: string, documentId: string) => Promise; + + // Attributes + createStringAttribute: (databaseId: string, collectionId: string, key: string, size: number, required: boolean, xdefault?: string, array?: boolean, encrypt?: boolean) => Promise; + createIntegerAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, min?: number, max?: number, xdefault?: number, array?: boolean) => Promise; + createFloatAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, min?: number, max?: number, xdefault?: number, array?: boolean) => Promise; + createBooleanAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: boolean, array?: boolean) => Promise; + createEmailAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: string, array?: boolean) => Promise; + createUrlAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: string, array?: boolean) => Promise; + createIpAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: string, array?: boolean) => Promise; + createDatetimeAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: string, array?: boolean) => Promise; + createEnumAttribute: (databaseId: string, collectionId: string, key: string, elements: string[], required: boolean, xdefault?: string, array?: boolean) => Promise; + createRelationshipAttribute: (databaseId: string, collectionId: string, relatedCollectionId: string, type: string, twoWay?: boolean, key?: string, twoWayKey?: string, onDelete?: string) => Promise; + getAttribute: (databaseId: string, collectionId: string, key: string) => Promise; + listAttributes: (databaseId: string, collectionId: string, queries?: string[]) => Promise; + updateStringAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: string) => Promise; + updateIntegerAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, min?: number, max?: number, xdefault?: number) => Promise; + updateFloatAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, min?: number, max?: number, xdefault?: number) => Promise; + updateBooleanAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: boolean) => Promise; + updateEmailAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: string) => Promise; + updateUrlAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: string) => Promise; + updateIpAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: string) => Promise; + updateDatetimeAttribute: (databaseId: string, collectionId: string, key: string, required: boolean, xdefault?: string) => Promise; + updateEnumAttribute: (databaseId: string, collectionId: string, key: string, elements: string[], required: boolean, xdefault?: string) => Promise; + updateRelationshipAttribute: (databaseId: string, collectionId: string, key: string, onDelete?: string) => Promise; + deleteAttribute: (databaseId: string, collectionId: string, key: string) => Promise; + + // Indexes + createIndex: (databaseId: string, collectionId: string, key: string, type: string, attributes: string[], orders?: string[]) => Promise; + getIndex: (databaseId: string, collectionId: string, key: string) => Promise; + listIndexes: (databaseId: string, collectionId: string, queries?: string[]) => Promise; + deleteIndex: (databaseId: string, collectionId: string, key: string) => Promise; +}; + +/** @deprecated Use DatabasesClient instead */ +export type DatabaseClient = { + listCollections: () => Promise; + listDocuments: (collectionId: string) => Promise; + updateCollection: (collectionId: string, name: string, read: string[], write: string[], rules?: (Rule | CreatedRule)[]) => Promise; + deleteCollection: (collectionId: string) => Promise; + getCollection: (collectionId: string) => Promise; + deleteDocument: (collectionId: string, documentId: string) => Promise; + createCollection: (name: string, read: string[], write: string[], rules: Rule[]) => Promise; +}; + +type GetHealth = () => Promise; +type GetHealthQueue = (threshold?: number) => Promise; + +export type HealthClient = { + get: GetHealth; + getDB: GetHealth; + getCache: GetHealth; + getPubSub: GetHealth; + getTime: () => Promise; + getStorage: GetHealth; + getStorageLocal: GetHealth; + getAntivirus: () => Promise; + getCertificate: (domain?: string) => Promise; + + // Queue health checks + getQueueBuilds: GetHealthQueue; + getQueueCertificates: GetHealthQueue; + getQueueDatabases: (name?: string, threshold?: number) => Promise; + getQueueDeletes: GetHealthQueue; + getQueueFunctions: GetHealthQueue; + getQueueLogs: GetHealthQueue; + getQueueMails: GetHealthQueue; + getQueueMessaging: GetHealthQueue; + getQueueMigrations: GetHealthQueue; + getQueueUsage: GetHealthQueue; + getQueueUsageDump: GetHealthQueue; + getQueueWebhooks: GetHealthQueue; + getFailedJobs: (name: string, threshold?: number) => Promise; +}; + +export type StorageClient = { + // Bucket CRUD + createBucket: (bucketId: string, name: string, permissions?: string[], fileSecurity?: boolean, enabled?: boolean, maximumFileSize?: number, allowedFileExtensions?: string[], compression?: string, encryption?: boolean, antivirus?: boolean) => Promise; + getBucket: (bucketId: string) => Promise; + listBuckets: (queries?: string[], search?: string) => Promise; + updateBucket: (bucketId: string, name: string, permissions?: string[], fileSecurity?: boolean, enabled?: boolean, maximumFileSize?: number, allowedFileExtensions?: string[], compression?: string, encryption?: boolean, antivirus?: boolean) => Promise; + deleteBucket: (bucketId: string) => Promise; + + // File CRUD + createFile: (bucketId: string, fileId: string, file: File | ReadStream | Buffer, permissions?: string[]) => Promise; + getFile: (bucketId: string, fileId: string) => Promise; + listFiles: (bucketId: string, queries?: string[], search?: string) => Promise; + updateFile: (bucketId: string, fileId: string, name?: string, permissions?: string[]) => Promise; + deleteFile: (bucketId: string, fileId: string) => Promise; + + // File operations + getFileDownload: (bucketId: string, fileId: string) => Promise; + getFilePreview: (bucketId: string, fileId: string, width?: number, height?: number, gravity?: string, quality?: number, borderWidth?: number, borderColor?: string, borderRadius?: number, opacity?: number, rotation?: number, background?: string, output?: string) => Promise; + getFileView: (bucketId: string, fileId: string) => Promise; }; export type FunctionsClient = { - create: (name: string, execute: string[], env: string, vars?: Vars, events?: string[], schedule?: string, timeout?: number) => Promise; - list: (search?: string, offset?: number, limit?: number, orderType?: 'ASC' | 'DESC') => Promise; - get: (functionId: string) => Promise; - update: (functionId: string, name: string, execute: string[], vars?: Vars, events?: string[], schedule?: string, timeout?: number) => Promise; - updateTag: (functionId: string, tagId: string) => Promise; - delete: (functionId: string) => Promise; - createTag: (id: string, command: string, code: ReadStream) => Promise; - listTags: (id: string, search?: string, limit?: number, offset?: number, orderType?: 'ASC' | 'DESC') => Promise; - getTag: (functionId: string, tagId: string) => Promise; - deleteTag: (functionId: string, tagId: string) => Promise; - createExecution: (functionId: string, data?: string) => Promise; - listExecutions: (functionId: string, search?: string, limit?: number, offset?: number, orderType?: 'ASC' | 'DESC') => Promise; - getExecution: (functionId: string, executionId: string) => Promise; -} + // Function CRUD + create: (functionId: string, name: string, runtime: string, execute?: string[], events?: string[], schedule?: string, timeout?: number, enabled?: boolean, logging?: boolean, entrypoint?: string, commands?: string, scopes?: string[], installationId?: string, providerRepositoryId?: string, providerBranch?: string, providerSilentMode?: boolean, providerRootDirectory?: string, templateRepository?: string, templateOwner?: string, templateRootDirectory?: string, templateVersion?: string) => Promise; + get: (functionId: string) => Promise; + list: (queries?: string[], search?: string) => Promise; + update: (functionId: string, name: string, runtime?: string, execute?: string[], events?: string[], schedule?: string, timeout?: number, enabled?: boolean, logging?: boolean, entrypoint?: string, commands?: string, scopes?: string[], installationId?: string, providerRepositoryId?: string, providerBranch?: string, providerSilentMode?: boolean, providerRootDirectory?: string) => Promise; + delete: (functionId: string) => Promise; + + // Deployment operations (replaces Tags) + createDeployment: (functionId: string, code: ReadStream | Buffer, activate: boolean, entrypoint?: string, commands?: string) => Promise; + getDeployment: (functionId: string, deploymentId: string) => Promise; + listDeployments: (functionId: string, queries?: string[], search?: string) => Promise; + updateDeployment: (functionId: string, deploymentId: string) => Promise; + deleteDeployment: (functionId: string, deploymentId: string) => Promise; + getDeploymentDownload: (functionId: string, deploymentId: string) => Promise; + + // Execution operations + createExecution: (functionId: string, body?: string, async?: boolean, path?: string, method?: string, headers?: Record, scheduledAt?: string) => Promise; + getExecution: (functionId: string, executionId: string) => Promise; + listExecutions: (functionId: string, queries?: string[]) => Promise; + deleteExecution: (functionId: string, executionId: string) => Promise; + + // Variable operations + createVariable: (functionId: string, key: string, value: string) => Promise; + getVariable: (functionId: string, variableId: string) => Promise; + listVariables: (functionId: string) => Promise; + updateVariable: (functionId: string, variableId: string, key: string, value?: string) => Promise; + deleteVariable: (functionId: string, variableId: string) => Promise; + + /** @deprecated Use createDeployment instead */ + createTag: (id: string, command: string, code: ReadStream) => Promise; + /** @deprecated Use listDeployments instead */ + listTags: (id: string, search?: string, limit?: number, offset?: number, orderType?: 'ASC' | 'DESC') => Promise; + /** @deprecated Use getDeployment instead */ + getTag: (functionId: string, tagId: string) => Promise; + /** @deprecated Use deleteDeployment instead */ + deleteTag: (functionId: string, tagId: string) => Promise; + /** @deprecated Use updateDeployment instead */ + updateTag: (functionId: string, tagId: string) => Promise; +}; + +// ============================================================================ +// SDK Type with Helper Classes +// ============================================================================ + +export type PermissionHelper = { + read: (role: string) => string; + write: (role: string) => string; + create: (role: string) => string; + update: (role: string) => string; + delete: (role: string) => string; +}; + +export type RoleHelper = { + any: () => string; + user: (id: string, status?: string) => string; + users: (status?: string) => string; + guests: () => string; + team: (id: string, role?: string) => string; + member: (id: string) => string; + label: (name: string) => string; +}; + +export type QueryHelper = { + equal: (attribute: string, value: unknown) => string; + notEqual: (attribute: string, value: unknown) => string; + lessThan: (attribute: string, value: unknown) => string; + lessThanEqual: (attribute: string, value: unknown) => string; + greaterThan: (attribute: string, value: unknown) => string; + greaterThanEqual: (attribute: string, value: unknown) => string; + search: (attribute: string, value: string) => string; + orderAsc: (attribute: string) => string; + orderDesc: (attribute: string) => string; + cursorAfter: (documentId: string) => string; + cursorBefore: (documentId: string) => string; + limit: (limit: number) => string; + offset: (offset: number) => string; + contains: (attribute: string, value: unknown) => string; + or: (queries: string[]) => string; + and: (queries: string[]) => string; + select: (attributes: string[]) => string; + between: (attribute: string, start: unknown, end: unknown) => string; + startsWith: (attribute: string, value: string) => string; + endsWith: (attribute: string, value: string) => string; + isNull: (attribute: string) => string; + isNotNull: (attribute: string) => string; +}; + +export type IDHelper = { + unique: () => string; + custom: (id: string) => string; +}; export type SDK = { Client: new () => Client; + // Service classes Users: new (client: Client) => UsersClient; Health: new (client: Client) => HealthClient; - Database: new (client: Client) => DatabaseClient; + Databases: new (client: Client) => DatabasesClient; Storage: new (client: Client) => StorageClient; Functions: new (client: Client) => FunctionsClient; + + // Helper classes + Permission: PermissionHelper; + Role: RoleHelper; + Query: QueryHelper; + ID: IDHelper; + + /** @deprecated Use Databases instead */ + Database: new (client: Client) => DatabaseClient; }; From de63cac609981cc394407cad2439bc0575900a98 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Fri, 23 Jan 2026 15:42:03 +0100 Subject: [PATCH 03/14] refactor: update constants for SDK v21 - Export SDK helper classes (Permission, Role, Query, ID) - Update system events to new format: - databases.*.collections.* (with databaseId) - buckets.*.files.* (with bucketId) - functions.*.deployments.* (replaces tags) - Add messaging events (providers, topics, messages) - Update function runtimes list to current versions: - Node.js 18-22, Python 3.9-3.12, PHP 8.0-8.3 - Ruby 3.1-3.3, Dart 2.17-3.3, Deno 1.35-2.0 - Bun 1.0, .NET 6-8, Java 8-21 - Swift 5.8-5.9, Kotlin 1.8-1.9, C++ 17/20, Go 1.22-1.23 Co-Authored-By: Claude Opus 4.5 --- src/constants.ts | 335 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 234 insertions(+), 101 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 40276cc..90cc1a0 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,197 +1,330 @@ -import type { SDK } from "./appwrite"; +import type { SDK, PermissionHelper, RoleHelper, QueryHelper, IDHelper } from "./appwrite"; // eslint-disable-next-line @typescript-eslint/no-var-requires -export const AppwriteSDK: SDK = require("node-appwrite") as SDK; +const sdk = require("node-appwrite"); +export const AppwriteSDK: SDK = sdk as SDK; + +// Export helper classes from SDK +export const Permission: PermissionHelper = sdk.Permission; +export const Role: RoleHelper = sdk.Role; +export const Query: QueryHelper = sdk.Query; +export const ID: IDHelper = sdk.ID; + +// System events for Appwrite v1.8.x / SDK v21 +// See: https://appwrite.io/docs/advanced/platform/events export const appwriteSystemEvents = [ + // Users events { - name: "account.create", - description: "This event triggers when the account is created.", + name: "users.*.create", + description: "Triggered when a user is created.", }, { - name: "account.update.email", - description: "This event triggers when the account email address is updated.", + name: "users.*.update", + description: "Triggered when a user is updated.", }, { - name: "account.update.name", - description: "This event triggers when the account name is updated.", + name: "users.*.update.email", + description: "Triggered when a user email is updated.", }, { - name: "account.update.password", - description: "This event triggers when the account password is updated.", + name: "users.*.update.name", + description: "Triggered when a user name is updated.", }, { - name: "account.update.prefs", - description: "This event triggers when the account preferences are updated.", + name: "users.*.update.password", + description: "Triggered when a user password is updated.", }, { - name: "account.recovery.create", - description: "This event triggers when the account recovery token is created.", + name: "users.*.update.status", + description: "Triggered when a user status is updated.", }, { - name: "account.recovery.update", - description: "This event triggers when the account recovery token is validated.", + name: "users.*.update.prefs", + description: "Triggered when user preferences are updated.", }, { - name: "account.verification.create", - description: "This event triggers when the account verification token is created.", + name: "users.*.delete", + description: "Triggered when a user is deleted.", }, { - name: "account.verification.update", - description: "This event triggers when the account verification token is validated.", + name: "users.*.sessions.*.create", + description: "Triggered when a user session is created.", }, { - name: "account.delete", - description: "This event triggers when the account is deleted.", + name: "users.*.sessions.*.delete", + description: "Triggered when a user session is deleted.", }, { - name: "account.sessions.create", - description: "This event triggers when the account session is created.", + name: "users.*.recovery.*.create", + description: "Triggered when a user recovery token is created.", }, { - name: "account.delete", - description: "This event triggers when the account is deleted.", + name: "users.*.recovery.*.update", + description: "Triggered when a user recovery token is validated.", }, { - name: "account.sessions.create", - description: "This event triggers when the account session is created.", + name: "users.*.verification.*.create", + description: "Triggered when a user verification token is created.", }, { - name: "account.sessions.delete", - description: "This event triggers when the account session is deleted.", + name: "users.*.verification.*.update", + description: "Triggered when a user verification token is validated.", }, + + // Databases events (new format with databaseId) { - name: "database.collections.create", - description: "This event triggers when a database collection is created.", + name: "databases.*.create", + description: "Triggered when a database is created.", }, { - name: "database.collections.update", - description: "This event triggers when a database collection is updated.", + name: "databases.*.update", + description: "Triggered when a database is updated.", }, { - name: "database.collections.delete", - description: "This event triggers when a database collection is deleted.", + name: "databases.*.delete", + description: "Triggered when a database is deleted.", }, { - name: "database.documents.create", - description: "This event triggers when a database document is created.", + name: "databases.*.collections.*.create", + description: "Triggered when a collection is created.", }, { - name: "database.documents.update", - description: "This event triggers when a database document is updated.", + name: "databases.*.collections.*.update", + description: "Triggered when a collection is updated.", }, { - name: "database.documents.delete", - description: "This event triggers when a database document is deleted.", + name: "databases.*.collections.*.delete", + description: "Triggered when a collection is deleted.", }, { - name: "functions.create", - description: "This event triggers when a function is created.", + name: "databases.*.collections.*.documents.*.create", + description: "Triggered when a document is created.", }, { - name: "functions.update", - description: "This event triggers when a function is updated.", + name: "databases.*.collections.*.documents.*.update", + description: "Triggered when a document is updated.", }, { - name: "functions.delete", - description: "This event triggers when a function is deleted.", + name: "databases.*.collections.*.documents.*.delete", + description: "Triggered when a document is deleted.", }, { - name: "functions.tags.create", - description: "This event triggers when a function tag is created.", + name: "databases.*.collections.*.attributes.*.create", + description: "Triggered when an attribute is created.", }, { - name: "functions.tags.update", - description: "This event triggers when a function tag is updated.", + name: "databases.*.collections.*.attributes.*.delete", + description: "Triggered when an attribute is deleted.", }, { - name: "functions.tags.delete", - description: "This event triggers when a function tag is deleted.", + name: "databases.*.collections.*.indexes.*.create", + description: "Triggered when an index is created.", }, { - name: "functions.executions.create", - description: "This event triggers when a function execution is created.", + name: "databases.*.collections.*.indexes.*.delete", + description: "Triggered when an index is deleted.", }, + + // Storage events (with bucketId) { - name: "functions.executions.update", - description: "This event triggers when a function execution is updated.", + name: "buckets.*.create", + description: "Triggered when a storage bucket is created.", }, { - name: "storage.files.create", - description: "This event triggers when a storage file is created.", + name: "buckets.*.update", + description: "Triggered when a storage bucket is updated.", }, { - name: "storage.files.update", - description: "This event triggers when a storage file is updated.", + name: "buckets.*.delete", + description: "Triggered when a storage bucket is deleted.", }, { - name: "storage.files.delete", - description: "This event triggers when a storage file is deleted.", + name: "buckets.*.files.*.create", + description: "Triggered when a file is created.", }, { - name: "users.create", - description: "This event triggers when a user is created from the users API.", + name: "buckets.*.files.*.update", + description: "Triggered when a file is updated.", }, { - name: "users.update.prefs", - description: "This event triggers when a user preference is updated from the users API.", + name: "buckets.*.files.*.delete", + description: "Triggered when a file is deleted.", + }, + + // Functions events (with deployments instead of tags) + { + name: "functions.*.create", + description: "Triggered when a function is created.", }, { - name: "users.update.status", - description: "This event triggers when a user status is updated from the users API.", + name: "functions.*.update", + description: "Triggered when a function is updated.", }, { - name: "users.delete", - description: "This event triggers when a user is deleted from users API.", + name: "functions.*.delete", + description: "Triggered when a function is deleted.", }, { - name: "users.sessions.delete", - description: "This event triggers when a user session is deleted from users API.", + name: "functions.*.deployments.*.create", + description: "Triggered when a function deployment is created.", }, { - name: "teams.create", - description: "This event triggers when a team is created.", + name: "functions.*.deployments.*.update", + description: "Triggered when a function deployment is updated.", }, { - name: "teams.update", - description: "This event triggers when a team is updated.", + name: "functions.*.deployments.*.delete", + description: "Triggered when a function deployment is deleted.", }, { - name: "teams.delete", - description: "This event triggers when a team is deleted.", + name: "functions.*.executions.*.create", + description: "Triggered when a function execution is created.", }, { - name: "teams.memberships.create", - description: "This event triggers when a team memberships is created.", + name: "functions.*.executions.*.update", + description: "Triggered when a function execution is updated.", }, { - name: "teams.memberships.update", - description: "This event triggers when a team membership is updated.", + name: "functions.*.executions.*.delete", + description: "Triggered when a function execution is deleted.", + }, + + // Teams events + { + name: "teams.*.create", + description: "Triggered when a team is created.", + }, + { + name: "teams.*.update", + description: "Triggered when a team is updated.", + }, + { + name: "teams.*.delete", + description: "Triggered when a team is deleted.", + }, + { + name: "teams.*.memberships.*.create", + description: "Triggered when a team membership is created.", + }, + { + name: "teams.*.memberships.*.update", + description: "Triggered when a team membership is updated.", + }, + { + name: "teams.*.memberships.*.update.status", + description: "Triggered when a team membership status is updated.", + }, + { + name: "teams.*.memberships.*.delete", + description: "Triggered when a team membership is deleted.", + }, + + // Messaging events + { + name: "providers.*.create", + description: "Triggered when a messaging provider is created.", }, { - name: "teams.memberships.update.status", - description: "This event triggers when a team memberships status is updated.", + name: "providers.*.update", + description: "Triggered when a messaging provider is updated.", }, { - name: "teams.memberships.delete", - description: "This event triggers when a team memberships is deleted.", + name: "providers.*.delete", + description: "Triggered when a messaging provider is deleted.", + }, + { + name: "topics.*.create", + description: "Triggered when a messaging topic is created.", + }, + { + name: "topics.*.update", + description: "Triggered when a messaging topic is updated.", + }, + { + name: "topics.*.delete", + description: "Triggered when a messaging topic is deleted.", + }, + { + name: "messages.*.create", + description: "Triggered when a message is created.", + }, + { + name: "messages.*.update", + description: "Triggered when a message is updated.", + }, + { + name: "messages.*.delete", + description: "Triggered when a message is deleted.", }, ]; +// Function runtimes for Appwrite v1.8.x / SDK v21 +// See: https://appwrite.io/docs/products/functions/runtimes export const appwriteFunctionRuntimes = [ - "dotnet-3.1", - "dotnet-5.0", - "dart-2.10", - "dart-2.12", - "deno-1.5", - "deno-1.6", - "deno-1.8", - "python-3.8", + // Node.js + "node-18.0", + "node-20.0", + "node-21.0", + "node-22.0", + + // Python "python-3.9", - "ruby-2.7", - "ruby-3.0", - "php-7.4", + "python-3.10", + "python-3.11", + "python-3.12", + + // PHP "php-8.0", - "node-14.5", - "node-15.5", + "php-8.1", + "php-8.2", + "php-8.3", + + // Ruby + "ruby-3.1", + "ruby-3.2", + "ruby-3.3", + + // Dart + "dart-2.17", + "dart-2.18", + "dart-3.0", + "dart-3.1", + "dart-3.3", + + // Deno + "deno-1.35", + "deno-1.40", + "deno-2.0", + + // Bun + "bun-1.0", + + // .NET + "dotnet-6.0", + "dotnet-7.0", + "dotnet-8.0", + + // Java + "java-8.0", + "java-11.0", + "java-17.0", + "java-18.0", + "java-21.0", + + // Swift + "swift-5.8", + "swift-5.9", + + // Kotlin + "kotlin-1.8", + "kotlin-1.9", + + // C++ + "cpp-17", + "cpp-20", + + // Go + "go-1.22", + "go-1.23", ]; From 968a56ac430fa6356a1433277f999d0ba9332560 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Fri, 23 Jan 2026 15:42:34 +0100 Subject: [PATCH 04/14] feat: add databaseId and bucketId to project configuration SDK v21 requires databaseId for all database operations and bucketId for all storage operations. These optional fields allow users to configure default IDs per project. Co-Authored-By: Claude Opus 4.5 --- src/settings.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/settings.ts b/src/settings.ts index 72a7474..7792327 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -8,6 +8,10 @@ export type AppwriteProjectConfiguration = { projectId: string; selfSigned: boolean; secret: string; + /** Default database ID for database operations (required for SDK v21+) */ + databaseId?: string; + /** Default storage bucket ID for file operations (required for SDK v21+) */ + bucketId?: string; }; export async function getDefaultProject(): Promise { From 693e50ddea2e5d4df214500b7e6b8179fc5a7a21 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Fri, 23 Jan 2026 15:43:28 +0100 Subject: [PATCH 05/14] refactor: update client initialization for SDK v21 - Extend clientConfig to include databaseId and bucketId - Pass default databaseId to Database service - Pass default bucketId to Storage service - Fix setSelfSigned to be called conditionally Co-Authored-By: Claude Opus 4.5 --- src/client.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/client.ts b/src/client.ts index 5fe9c13..d082220 100644 --- a/src/client.ts +++ b/src/client.ts @@ -8,23 +8,33 @@ import { AppwriteSDK } from "./constants"; import { AppwriteProjectConfiguration } from "./settings"; export let client: Client; -export let clientConfig: { endpoint: string; projectId: string; secret: string }; +export let clientConfig: { + endpoint: string; + projectId: string; + secret: string; + databaseId?: string; + bucketId?: string; +}; export let usersClient: Users | undefined; export let healthClient: Health | undefined; export let databaseClient: Database | undefined; export let storageClient: Storage | undefined; export let functionsClient: Functions | undefined; - -function initAppwriteClient({ endpoint, projectId, secret, selfSigned }: AppwriteProjectConfiguration) { +function initAppwriteClient({ endpoint, projectId, secret, selfSigned, databaseId, bucketId }: AppwriteProjectConfiguration) { client = new AppwriteSDK.Client(); - clientConfig = { endpoint, projectId, secret }; - client.setEndpoint(endpoint).setProject(projectId).setKey(secret).setSelfSigned(selfSigned); + clientConfig = { endpoint, projectId, secret, databaseId, bucketId }; + + client.setEndpoint(endpoint).setProject(projectId).setKey(secret); + + if (selfSigned) { + client.setSelfSigned(true); + } usersClient = new Users(client); healthClient = new Health(client); - databaseClient = new Database(client); - storageClient = new Storage(client); + databaseClient = new Database(client, databaseId); + storageClient = new Storage(client, bucketId); functionsClient = new Functions(client); return client; From 976d14c58ef18e6a3d804b2aa0443503de24b23a Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Fri, 23 Jan 2026 15:49:39 +0100 Subject: [PATCH 06/14] refactor: Update all service modules for SDK v21 - Database.ts: Add databaseId parameter to all methods, use Databases (plural), add attribute operations (replaces rules), add permission conversion helpers - Functions.ts: Rename Tags to Deployments, add variable management, new method signatures with runtime/scopes/entrypoint/commands - Storage.ts: Add bucketId parameter to all methods, add bucket operations - Health.ts: Add new health checks (PubSub, Storage, QueueBuilds, QueueMails, QueueMessaging, QueueMigrations, QueueDeletes), update method names - Users.ts: Update create signature (userId first), add new user management methods Co-Authored-By: Claude Opus 4.5 --- src/appwrite/Database.ts | 298 ++++++++++++++++++++++++++++++++++---- src/appwrite/Functions.ts | 236 ++++++++++++++++++++++++++---- src/appwrite/Health.ts | 153 ++++++++++++++++--- src/appwrite/Storage.ts | 136 ++++++++++++++++- src/appwrite/Users.ts | 60 +++++++- 5 files changed, 790 insertions(+), 93 deletions(-) diff --git a/src/appwrite/Database.ts b/src/appwrite/Database.ts index 7d5be16..2895372 100644 --- a/src/appwrite/Database.ts +++ b/src/appwrite/Database.ts @@ -1,61 +1,297 @@ -import { Client, Collection, CreatedCollection, CreatedRule, DatabaseClient, Rule } from "../appwrite"; -import { AppwriteSDK } from '../constants'; +import { Client, Collection, CreatedCollection, DatabasesClient, Database as DatabaseEntity, DatabasesList, DocumentsList, Attribute, AttributesList } from "../appwrite"; +import { AppwriteSDK, ID, Permission, Role } from '../constants'; import AppwriteCall from "../utils/AppwriteCall"; export class Database { - private readonly database: DatabaseClient; + private readonly databases: DatabasesClient; + private defaultDatabaseId: string | undefined; - constructor(client: Client) { - this.database = new AppwriteSDK.Database(client); + constructor(client: Client, defaultDatabaseId?: string) { + this.databases = new AppwriteSDK.Databases(client); + this.defaultDatabaseId = defaultDatabaseId; } - public async getCollection(collectionId: string): Promise { - return await AppwriteCall(this.database.getCollection(collectionId)); + /** + * Get the database ID, using default if not provided + */ + private getDatabaseId(databaseId?: string): string { + const id = databaseId || this.defaultDatabaseId; + if (!id) { + throw new Error('Database ID is required. Please configure a default database ID in your project settings.'); + } + return id; } - public async deleteDocument(collectionId: string, documentId: string): Promise { - await AppwriteCall(this.database.deleteDocument(collectionId, documentId)); + /** + * Set the default database ID + */ + public setDefaultDatabaseId(databaseId: string): void { + this.defaultDatabaseId = databaseId; } - public async deleteCollection(collectionId: string): Promise { - await AppwriteCall(this.database.deleteCollection(collectionId)); + /** + * Get the current default database ID + */ + public getDefaultDatabaseId(): string | undefined { + return this.defaultDatabaseId; } - public async createCollection(collection: CreatedCollection): Promise { - await AppwriteCall( - this.database.createCollection( + // ========================================================================= + // Database operations + // ========================================================================= + + public async listDatabases(): Promise { + return await AppwriteCall(this.databases.list()); + } + + public async getDatabase(databaseId: string): Promise { + return await AppwriteCall(this.databases.get(databaseId)); + } + + public async createDatabase(name: string, databaseId?: string): Promise { + const id = databaseId || ID.unique(); + return await AppwriteCall(this.databases.create(id, name, true)); + } + + public async deleteDatabase(databaseId: string): Promise { + await AppwriteCall(this.databases.delete(databaseId)); + } + + // ========================================================================= + // Collection operations + // ========================================================================= + + public async getCollection(collectionId: string, databaseId?: string): Promise { + const dbId = this.getDatabaseId(databaseId); + return await AppwriteCall(this.databases.getCollection(dbId, collectionId)); + } + + public async listCollections(databaseId?: string): Promise { + const dbId = this.getDatabaseId(databaseId); + const result = await AppwriteCall<{ total: number; collections: Collection[] }>( + this.databases.listCollections(dbId) + ); + return result?.collections; + } + + public async createCollection(collection: CreatedCollection, databaseId?: string): Promise { + const dbId = this.getDatabaseId(databaseId); + const collectionId = ID.unique(); + + // Convert old permission format to new format if needed + const permissions = this.convertPermissions( + collection.$permissions ?? [] + ); + + return await AppwriteCall( + this.databases.createCollection( + dbId, + collectionId, collection.name, - collection.$permissions?.read ?? [], - collection.$permissions?.write ?? [], - collection.rules ?? [] + permissions, + true, // documentSecurity + true // enabled ) ); } - public async updatePermissions(collection: Collection, read: string[], write: string[]): Promise { - await AppwriteCall(this.database.updateCollection(collection.$id, collection.name, read, write, collection.rules)); + public async deleteCollection(collectionId: string, databaseId?: string): Promise { + const dbId = this.getDatabaseId(databaseId); + await AppwriteCall(this.databases.deleteCollection(dbId, collectionId)); } - public async createRule(collection: Collection, newRule: CreatedRule): Promise { - await AppwriteCall( - this.database.updateCollection(collection.$id, collection.name, collection.$permissions.read, collection.$permissions.write, [ - ...collection.rules, - newRule, - ]) + public async updateCollection( + collectionId: string, + name: string, + permissions?: string[], + databaseId?: string + ): Promise { + const dbId = this.getDatabaseId(databaseId); + return await AppwriteCall( + this.databases.updateCollection(dbId, collectionId, name, permissions) ); } - public async removeRule(collection: Collection, ruleToRemove: Rule): Promise { - const rules = collection.rules.filter((rule) => rule.$id !== ruleToRemove.$id); + // ========================================================================= + // Document operations + // ========================================================================= + + public async listDocuments(collectionId: string, databaseId?: string): Promise { + const dbId = this.getDatabaseId(databaseId); + return await AppwriteCall(this.databases.listDocuments(dbId, collectionId)); + } + + public async deleteDocument(collectionId: string, documentId: string, databaseId?: string): Promise { + const dbId = this.getDatabaseId(databaseId); + await AppwriteCall(this.databases.deleteDocument(dbId, collectionId, documentId)); + } + + // ========================================================================= + // Permission operations + // ========================================================================= + + public async updatePermissions( + collection: Collection, + read: string[], + write: string[], + databaseId?: string + ): Promise { + const dbId = this.getDatabaseId(databaseId); + const permissions = this.convertLegacyPermissions(read, write); await AppwriteCall( - this.database.updateCollection( + this.databases.updateCollection( + dbId, collection.$id, collection.name, - collection.$permissions.read, - collection.$permissions.write, - rules + permissions ) ); } + + // ========================================================================= + // Attribute operations (replaces rules) + // ========================================================================= + + public async listAttributes(collectionId: string, databaseId?: string): Promise { + const dbId = this.getDatabaseId(databaseId); + return await AppwriteCall(this.databases.listAttributes(dbId, collectionId)); + } + + public async createStringAttribute( + collectionId: string, + key: string, + size: number, + required: boolean, + defaultValue?: string, + array?: boolean, + databaseId?: string + ): Promise { + const dbId = this.getDatabaseId(databaseId); + return await AppwriteCall( + this.databases.createStringAttribute(dbId, collectionId, key, size, required, defaultValue, array) + ); + } + + public async createIntegerAttribute( + collectionId: string, + key: string, + required: boolean, + min?: number, + max?: number, + defaultValue?: number, + array?: boolean, + databaseId?: string + ): Promise { + const dbId = this.getDatabaseId(databaseId); + return await AppwriteCall( + this.databases.createIntegerAttribute(dbId, collectionId, key, required, min, max, defaultValue, array) + ); + } + + public async createBooleanAttribute( + collectionId: string, + key: string, + required: boolean, + defaultValue?: boolean, + array?: boolean, + databaseId?: string + ): Promise { + const dbId = this.getDatabaseId(databaseId); + return await AppwriteCall( + this.databases.createBooleanAttribute(dbId, collectionId, key, required, defaultValue, array) + ); + } + + public async createEmailAttribute( + collectionId: string, + key: string, + required: boolean, + defaultValue?: string, + array?: boolean, + databaseId?: string + ): Promise { + const dbId = this.getDatabaseId(databaseId); + return await AppwriteCall( + this.databases.createEmailAttribute(dbId, collectionId, key, required, defaultValue, array) + ); + } + + public async createUrlAttribute( + collectionId: string, + key: string, + required: boolean, + defaultValue?: string, + array?: boolean, + databaseId?: string + ): Promise { + const dbId = this.getDatabaseId(databaseId); + return await AppwriteCall( + this.databases.createUrlAttribute(dbId, collectionId, key, required, defaultValue, array) + ); + } + + public async deleteAttribute(collectionId: string, key: string, databaseId?: string): Promise { + const dbId = this.getDatabaseId(databaseId); + await AppwriteCall(this.databases.deleteAttribute(dbId, collectionId, key)); + } + + // ========================================================================= + // Helper methods + // ========================================================================= + + /** + * Convert new permission array format + */ + private convertPermissions(permissions: string[]): string[] { + // If already in new format, return as-is + if (permissions.length === 0 || permissions[0].includes('(')) { + return permissions; + } + // Otherwise, assume it's role strings and convert + return permissions.map(role => Permission.read(this.normalizeRole(role))); + } + + /** + * Convert legacy read/write arrays to new permission format + */ + private convertLegacyPermissions(read: string[], write: string[]): string[] { + const permissions: string[] = []; + + read.forEach(role => { + permissions.push(Permission.read(this.normalizeRole(role))); + }); + + write.forEach(role => { + permissions.push(Permission.write(this.normalizeRole(role))); + permissions.push(Permission.create(this.normalizeRole(role))); + permissions.push(Permission.update(this.normalizeRole(role))); + permissions.push(Permission.delete(this.normalizeRole(role))); + }); + + return [...new Set(permissions)]; // Remove duplicates + } + + /** + * Normalize legacy role format to new SDK format + */ + private normalizeRole(role: string): string { + if (role === '*') { + return Role.any(); + } + if (role.startsWith('user:')) { + return Role.user(role.substring(5)); + } + if (role.startsWith('team:')) { + const parts = role.substring(5).split('/'); + return parts.length > 1 ? Role.team(parts[0], parts[1]) : Role.team(parts[0]); + } + if (role === 'guests') { + return Role.guests(); + } + if (role === 'users') { + return Role.users(); + } + return role; + } } diff --git a/src/appwrite/Functions.ts b/src/appwrite/Functions.ts index 1bd8ce9..2073e23 100644 --- a/src/appwrite/Functions.ts +++ b/src/appwrite/Functions.ts @@ -1,5 +1,5 @@ -import { Client, Execution, ExecutionList, FunctionsClient, FunctionsList, Tag, TagList, Vars } from "../appwrite"; -import { AppwriteSDK } from '../constants'; +import { Client, Execution, ExecutionList, FunctionsClient, FunctionsList, Deployment, DeploymentList, Variable, VariableList, Function as FunctionEntity } from "../appwrite"; +import { AppwriteSDK, ID, Query } from '../constants'; import AppwriteCall from '../utils/AppwriteCall'; import { ReadStream } from 'node:fs'; @@ -10,43 +10,227 @@ export class Functions { this.functions = new AppwriteSDK.Functions(client); } - public async create(name: string, execute: string[], env: string, vars?: Vars, events?: string[], schedule?: string, timeout?: number): Promise { - return await AppwriteCall(this.functions.create(name, execute, env, vars, events, schedule, timeout)); - } - public async list(search?: string, offset?: number, limit?: number, orderType?: 'ASC' | 'DESC'): Promise { - return await AppwriteCall(this.functions.list(search, offset, limit, orderType)); + // ========================================================================= + // Function CRUD operations + // ========================================================================= + + /** + * Create a new function + * @param name Function name + * @param execute Execution permissions + * @param runtime Runtime environment (e.g., 'node-18.0', 'python-3.11') + */ + public async create( + name: string, + execute: string[], + runtime: string, + events?: string[], + schedule?: string, + timeout?: number, + enabled?: boolean, + logging?: boolean, + entrypoint?: string, + commands?: string, + scopes?: string[] + ): Promise { + const functionId = ID.unique(); + return await AppwriteCall( + this.functions.create( + functionId, + name, + runtime, + execute, + events, + schedule, + timeout, + enabled, + logging, + entrypoint, + commands, + scopes + ) + ); } - public async get(functionId: string): Promise { - return await AppwriteCall(this.functions.get(functionId)); + + public async list(queries?: string[], search?: string): Promise { + return await AppwriteCall(this.functions.list(queries, search)); } - public async update(functionId: string, name: string, execute: string[], vars?: Vars, events?: string[], schedule?: string, timeout?: number): Promise { - return await AppwriteCall(this.functions.update(functionId, name, execute, vars, events, schedule, timeout)); + + public async get(functionId: string): Promise { + return await AppwriteCall(this.functions.get(functionId)); } - public async updateTag(functionId: string, tagId: string): Promise { - return await AppwriteCall(this.functions.updateTag(functionId, tagId)); + + public async update( + functionId: string, + name: string, + runtime?: string, + execute?: string[], + events?: string[], + schedule?: string, + timeout?: number, + enabled?: boolean, + logging?: boolean, + entrypoint?: string, + commands?: string, + scopes?: string[] + ): Promise { + return await AppwriteCall( + this.functions.update( + functionId, + name, + runtime, + execute, + events, + schedule, + timeout, + enabled, + logging, + entrypoint, + commands, + scopes + ) + ); } + public async delete(functionId: string): Promise { return await AppwriteCall(this.functions.delete(functionId)); } - public async createTag(functionId: string, command: string, code: ReadStream): Promise { - return await AppwriteCall(this.functions.createTag(functionId, command, code)); + + // ========================================================================= + // Deployment operations (replaces Tags) + // ========================================================================= + + /** + * Create a new deployment + */ + public async createDeployment( + functionId: string, + code: ReadStream, + activate: boolean, + entrypoint?: string, + commands?: string + ): Promise { + return await AppwriteCall( + this.functions.createDeployment(functionId, code, activate, entrypoint, commands) + ); } - public async listTags(id: string, search?: string, limit?: number, offset?: number, orderType?: 'ASC' | 'DESC'): Promise { - return await AppwriteCall(this.functions.listTags(id, search, offset, limit, orderType)); + + public async listDeployments( + functionId: string, + queries?: string[], + search?: string + ): Promise { + return await AppwriteCall( + this.functions.listDeployments(functionId, queries, search) + ); } - public async getTag(functionId: string, tagId: string): Promise { - return await AppwriteCall(this.functions.getTag(functionId, tagId)); + + public async getDeployment(functionId: string, deploymentId: string): Promise { + return await AppwriteCall(this.functions.getDeployment(functionId, deploymentId)); } - public async deleteTag(functionId: string, tagId: string): Promise { - return await AppwriteCall(this.functions.deleteTag(functionId, tagId)); + + /** + * Activate a deployment (set as active) + */ + public async updateDeployment(functionId: string, deploymentId: string): Promise { + return await AppwriteCall(this.functions.updateDeployment(functionId, deploymentId)); + } + + public async deleteDeployment(functionId: string, deploymentId: string): Promise { + return await AppwriteCall(this.functions.deleteDeployment(functionId, deploymentId)); } - public async createExecution(functionId: string, data?: string): Promise { - return await AppwriteCall(this.functions.createExecution(functionId, data)); + + // ========================================================================= + // Execution operations + // ========================================================================= + + public async createExecution( + functionId: string, + body?: string, + async?: boolean, + path?: string, + method?: string, + headers?: Record + ): Promise { + return await AppwriteCall( + this.functions.createExecution(functionId, body, async, path, method, headers) + ); } - public async listExecutions(functionId: string, search?: string, limit?: number, offset?: number, orderType?: 'ASC' | 'DESC'): Promise { - return await AppwriteCall(this.functions.listExecutions(functionId, search, limit, offset, orderType)); + + public async listExecutions(functionId: string, queries?: string[]): Promise { + return await AppwriteCall(this.functions.listExecutions(functionId, queries)); } + public async getExecution(functionId: string, executionId: string): Promise { - return await AppwriteCall(this.functions.getExecution(functionId, executionId)); + return await AppwriteCall(this.functions.getExecution(functionId, executionId)); + } + + public async deleteExecution(functionId: string, executionId: string): Promise { + return await AppwriteCall(this.functions.deleteExecution(functionId, executionId)); + } + + // ========================================================================= + // Variable operations + // ========================================================================= + + public async createVariable(functionId: string, key: string, value: string): Promise { + return await AppwriteCall(this.functions.createVariable(functionId, key, value)); + } + + public async listVariables(functionId: string): Promise { + return await AppwriteCall(this.functions.listVariables(functionId)); + } + + public async getVariable(functionId: string, variableId: string): Promise { + return await AppwriteCall(this.functions.getVariable(functionId, variableId)); + } + + public async updateVariable(functionId: string, variableId: string, key: string, value?: string): Promise { + return await AppwriteCall(this.functions.updateVariable(functionId, variableId, key, value)); + } + + public async deleteVariable(functionId: string, variableId: string): Promise { + return await AppwriteCall(this.functions.deleteVariable(functionId, variableId)); + } + + // ========================================================================= + // Deprecated methods (for backward compatibility) + // ========================================================================= + + /** @deprecated Use createDeployment instead */ + public async createTag(functionId: string, command: string, code: ReadStream): Promise { + return this.createDeployment(functionId, code, true, undefined, command); + } + + /** @deprecated Use listDeployments instead */ + public async listTags( + id: string, + search?: string, + limit?: number, + offset?: number, + orderType?: 'ASC' | 'DESC' + ): Promise { + const queries: string[] = []; + if (limit) queries.push(Query.limit(limit)); + if (offset) queries.push(Query.offset(offset)); + if (orderType === 'DESC') queries.push(Query.orderDesc('$createdAt')); + else if (orderType === 'ASC') queries.push(Query.orderAsc('$createdAt')); + + return this.listDeployments(id, queries.length > 0 ? queries : undefined, search); + } + + /** @deprecated Use getDeployment instead */ + public async getTag(functionId: string, tagId: string): Promise { + return this.getDeployment(functionId, tagId); + } + + /** @deprecated Use deleteDeployment instead */ + public async deleteTag(functionId: string, tagId: string): Promise { + return this.deleteDeployment(functionId, tagId); + } + + /** @deprecated Use updateDeployment instead */ + public async updateTag(functionId: string, tagId: string): Promise { + return this.updateDeployment(functionId, tagId); } } diff --git a/src/appwrite/Health.ts b/src/appwrite/Health.ts index 3863e2a..1e80853 100644 --- a/src/appwrite/Health.ts +++ b/src/appwrite/Health.ts @@ -1,6 +1,7 @@ import { MarkdownString } from 'vscode'; import { AppwriteHealth, Client, HealthClient } from "../appwrite"; import { AppwriteSDK } from '../constants'; + export class Health { private readonly health: HealthClient; @@ -12,36 +13,144 @@ export class Health { * @returns The health of all Appwrite services. */ public async checkup(): Promise> { - return { - HTTP: await this.health.get(), - DB: await this.health.getDB(), - Cache: await this.health.getCache(), - Time: await this.health.getTime(), - QueueWebhooks: await this.health.getQueueWebhooks(), - QueueTasks: await this.health.getQueueTasks(), - QueueLogs: await this.health.getQueueLogs(), - QueueUsage: await this.health.getQueueUsage(), - QueueCertificates: await this.health.getQueueCertificates(), - QueueFunctions: await this.health.getQueueFunctions(), - StorageLocal: await this.health.getStorageLocal(), - AntiVirus: await this.health.getAntiVirus(), - }; + const results: Partial = {}; + + // Core services + try { + results.HTTP = await this.health.get(); + } catch (e) { + results.HTTP = { name: 'HTTP', ping: 0, status: 'error' }; + } + + try { + results.DB = await this.health.getDB(); + } catch (e) { + results.DB = { name: 'DB', ping: 0, status: 'error' }; + } + + try { + results.Cache = await this.health.getCache(); + } catch (e) { + results.Cache = { name: 'Cache', ping: 0, status: 'error' }; + } + + try { + results.PubSub = await this.health.getPubSub(); + } catch (e) { + results.PubSub = { name: 'PubSub', ping: 0, status: 'error' }; + } + + try { + results.Time = await this.health.getTime(); + } catch (e) { + results.Time = { remoteTime: 0, localTime: 0, diff: 0 }; + } + + // Storage + try { + results.Storage = await this.health.getStorage(); + } catch (e) { + results.Storage = { name: 'Storage', ping: 0, status: 'error' }; + } + + try { + results.StorageLocal = await this.health.getStorageLocal(); + } catch (e) { + results.StorageLocal = { name: 'StorageLocal', ping: 0, status: 'error' }; + } + + try { + results.Antivirus = await this.health.getAntivirus(); + } catch (e) { + results.Antivirus = { version: 'unknown', status: 'error' }; + } + + // Queues + try { + results.QueueWebhooks = await this.health.getQueueWebhooks(); + } catch (e) { + results.QueueWebhooks = { size: -1 }; + } + + try { + results.QueueLogs = await this.health.getQueueLogs(); + } catch (e) { + results.QueueLogs = { size: -1 }; + } + + try { + results.QueueUsage = await this.health.getQueueUsage(); + } catch (e) { + results.QueueUsage = { size: -1 }; + } + + try { + results.QueueCertificates = await this.health.getQueueCertificates(); + } catch (e) { + results.QueueCertificates = { size: -1 }; + } + + try { + results.QueueFunctions = await this.health.getQueueFunctions(); + } catch (e) { + results.QueueFunctions = { size: -1 }; + } + + try { + results.QueueBuilds = await this.health.getQueueBuilds(); + } catch (e) { + results.QueueBuilds = { size: -1 }; + } + + try { + results.QueueMails = await this.health.getQueueMails(); + } catch (e) { + results.QueueMails = { size: -1 }; + } + + try { + results.QueueMessaging = await this.health.getQueueMessaging(); + } catch (e) { + results.QueueMessaging = { size: -1 }; + } + + try { + results.QueueMigrations = await this.health.getQueueMigrations(); + } catch (e) { + results.QueueMigrations = { size: -1 }; + } + + try { + results.QueueDeletes = await this.health.getQueueDeletes(); + } catch (e) { + results.QueueDeletes = { size: -1 }; + } + + return results; } } export const healthTooltips: Record = { HTTP: "Check the Appwrite HTTP server is up and responsive.", - DB: "Check the Appwrite in-memory cache server is up and connection is successful.", + DB: "Check the Appwrite database server is up and connection is successful.", Cache: "Check the Appwrite in-memory cache server is up and connection is successful.", - Time: - new MarkdownString("Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol (NTP)](https://en.wikipedia.org/wiki/Network_Time_Protocol) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP."), + PubSub: "Check the Appwrite pub/sub server is up and connection is successful.", + Time: new MarkdownString( + "Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol (NTP)](https://en.wikipedia.org/wiki/Network_Time_Protocol) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet." + ), + Storage: "Check the Appwrite storage device is up and connection is successful.", + StorageLocal: "Check the Appwrite local storage device is up and connection is successful.", + Antivirus: "Check the Appwrite Anti Virus server is up and connection is successful.", QueueWebhooks: "The number of webhooks that are waiting to be processed in the Appwrite internal queue server.", - QueueTasks: "The number of tasks that are waiting to be processed in the Appwrite internal queue server.", QueueLogs: "The number of logs that are waiting to be processed in the Appwrite internal queue server.", QueueUsage: "The number of usage stats that are waiting to be processed in the Appwrite internal queue server.", - QueueCertificates: - new MarkdownString("The number of certificates that are waiting to be issued against [Letsencrypt](https://letsencrypt.org/) in the Appwrite internal queue server."), + QueueCertificates: new MarkdownString( + "The number of certificates that are waiting to be issued against [Letsencrypt](https://letsencrypt.org/) in the Appwrite internal queue server." + ), QueueFunctions: "The number of functions waiting to be executed.", - StorageLocal: "Check the Appwrite local storage device is up and connection is successful.", - AntiVirus: "Check the Appwrite Anti Virus server is up and connection is successful.", + QueueBuilds: "The number of function builds waiting to be processed.", + QueueMails: "The number of emails waiting to be sent.", + QueueMessaging: "The number of messages waiting to be delivered.", + QueueMigrations: "The number of migrations waiting to be processed.", + QueueDeletes: "The number of delete operations waiting to be processed.", }; diff --git a/src/appwrite/Storage.ts b/src/appwrite/Storage.ts index a27dd4f..ba63552 100644 --- a/src/appwrite/Storage.ts +++ b/src/appwrite/Storage.ts @@ -1,20 +1,142 @@ import { ReadStream } from 'node:fs'; -import { Client, FilesList, StorageClient } from "../appwrite"; -import { AppwriteSDK } from '../constants'; +import { Client, File, FilesList, StorageClient, Bucket, BucketsList } from "../appwrite"; +import { AppwriteSDK, ID } from '../constants'; import AppwriteCall from "../utils/AppwriteCall"; export class Storage { private readonly storage: StorageClient; + private defaultBucketId: string | undefined; - constructor(client: Client) { + constructor(client: Client, defaultBucketId?: string) { this.storage = new AppwriteSDK.Storage(client); + this.defaultBucketId = defaultBucketId; } - public async listFiles(): Promise { - return await AppwriteCall(this.storage.listFiles()); + /** + * Get the bucket ID, using default if not provided + */ + private getBucketId(bucketId?: string): string { + const id = bucketId || this.defaultBucketId; + if (!id) { + throw new Error('Bucket ID is required. Please configure a default bucket ID in your project settings.'); + } + return id; } - public async createFile(file: ReadStream): Promise { - return await AppwriteCall(this.storage.createFile(file)); + /** + * Set the default bucket ID + */ + public setDefaultBucketId(bucketId: string): void { + this.defaultBucketId = bucketId; + } + + /** + * Get the current default bucket ID + */ + public getDefaultBucketId(): string | undefined { + return this.defaultBucketId; + } + + // ========================================================================= + // Bucket operations + // ========================================================================= + + public async listBuckets(): Promise { + return await AppwriteCall(this.storage.listBuckets()); + } + + public async getBucket(bucketId: string): Promise { + return await AppwriteCall(this.storage.getBucket(bucketId)); + } + + public async createBucket( + name: string, + bucketId?: string, + permissions?: string[], + fileSecurity?: boolean, + enabled?: boolean, + maximumFileSize?: number, + allowedFileExtensions?: string[] + ): Promise { + const id = bucketId || ID.unique(); + return await AppwriteCall( + this.storage.createBucket( + id, + name, + permissions, + fileSecurity, + enabled, + maximumFileSize, + allowedFileExtensions + ) + ); + } + + public async deleteBucket(bucketId: string): Promise { + await AppwriteCall(this.storage.deleteBucket(bucketId)); + } + + // ========================================================================= + // File operations + // ========================================================================= + + public async listFiles(bucketId?: string): Promise { + const bId = this.getBucketId(bucketId); + return await AppwriteCall(this.storage.listFiles(bId)); + } + + public async getFile(fileId: string, bucketId?: string): Promise { + const bId = this.getBucketId(bucketId); + return await AppwriteCall(this.storage.getFile(bId, fileId)); + } + + public async createFile( + file: ReadStream | Buffer, + bucketId?: string, + fileId?: string, + permissions?: string[] + ): Promise { + const bId = this.getBucketId(bucketId); + const fId = fileId || ID.unique(); + return await AppwriteCall(this.storage.createFile(bId, fId, file, permissions)); + } + + public async updateFile( + fileId: string, + name?: string, + permissions?: string[], + bucketId?: string + ): Promise { + const bId = this.getBucketId(bucketId); + return await AppwriteCall(this.storage.updateFile(bId, fileId, name, permissions)); + } + + public async deleteFile(fileId: string, bucketId?: string): Promise { + const bId = this.getBucketId(bucketId); + await AppwriteCall(this.storage.deleteFile(bId, fileId)); + } + + // ========================================================================= + // File download/preview operations + // ========================================================================= + + public async getFileDownload(fileId: string, bucketId?: string): Promise { + const bId = this.getBucketId(bucketId); + return await AppwriteCall(this.storage.getFileDownload(bId, fileId)); + } + + public async getFilePreview( + fileId: string, + bucketId?: string, + width?: number, + height?: number + ): Promise { + const bId = this.getBucketId(bucketId); + return await AppwriteCall(this.storage.getFilePreview(bId, fileId, width, height)); + } + + public async getFileView(fileId: string, bucketId?: string): Promise { + const bId = this.getBucketId(bucketId); + return await AppwriteCall(this.storage.getFileView(bId, fileId)); } } diff --git a/src/appwrite/Users.ts b/src/appwrite/Users.ts index 442d01a..0dbeb53 100644 --- a/src/appwrite/Users.ts +++ b/src/appwrite/Users.ts @@ -1,6 +1,6 @@ import { window } from "vscode"; -import { Client, Log, User, UsersClient } from "../appwrite"; -import { AppwriteSDK } from "../constants"; +import { Client, Log, LogList, User, UsersList, UsersClient } from "../appwrite"; +import { AppwriteSDK, ID } from "../constants"; import AppwriteCall from "../utils/AppwriteCall"; export class Users { @@ -9,10 +9,27 @@ export class Users { constructor(client: Client) { this.users = new AppwriteSDK.Users(client); } + + /** + * Create a new user + * Note: In SDK v21, userId is the first parameter + */ public async createNewUser(context: CreateUserContext): Promise { - await AppwriteCall(this.users.create(context.email, context.password, context.name), (user) => { - window.showInformationMessage(`Created user with id: ${user.$id}`); - }); + const userId = ID.unique(); + await AppwriteCall( + this.users.create(userId, context.email, undefined, context.password, context.name), + (user) => { + window.showInformationMessage(`Created user with id: ${user.$id}`); + } + ); + } + + public async get(userId: string): Promise { + return await AppwriteCall(this.users.get(userId)); + } + + public async list(queries?: string[], search?: string): Promise { + return await AppwriteCall(this.users.list(queries, search)); } public async delete(userId: string): Promise { @@ -21,8 +38,37 @@ export class Users { }); } - public async getLogs(userId: string): Promise { - return (await AppwriteCall(this.users.getLogs(userId))) ?? []; + /** + * Get user logs + * Note: In SDK v21, getLogs returns LogList with logs array + */ + public async getLogs(userId: string, queries?: string[]): Promise { + const result = await AppwriteCall(this.users.getLogs(userId, queries)); + return result?.logs ?? []; + } + + public async updateEmail(userId: string, email: string): Promise { + return await AppwriteCall(this.users.updateEmail(userId, email)); + } + + public async updateName(userId: string, name: string): Promise { + return await AppwriteCall(this.users.updateName(userId, name)); + } + + public async updatePassword(userId: string, password: string): Promise { + return await AppwriteCall(this.users.updatePassword(userId, password)); + } + + public async updateStatus(userId: string, status: boolean): Promise { + return await AppwriteCall(this.users.updateStatus(userId, status)); + } + + public async updateEmailVerification(userId: string, emailVerification: boolean): Promise { + return await AppwriteCall(this.users.updateEmailVerification(userId, emailVerification)); + } + + public async updatePhoneVerification(userId: string, phoneVerification: boolean): Promise { + return await AppwriteCall(this.users.updatePhoneVerification(userId, phoneVerification)); } } From 3d03074dfb3426d101e7a3b583e3cc075ed2084f Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Fri, 23 Jan 2026 16:02:21 +0100 Subject: [PATCH 07/14] refactor: Update tree providers for SDK v21 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Database: - Add DatabaseTreeItem to show databases as root level items - CollectionTreeItem now requires databaseId parameter - DocumentsTreeItem uses databaseClient instead of direct SDK - Replace RulesTreeItem with AttributesTreeItem (Rules → Attributes) - Update PermissionsTreeItem for new flat permission array format Functions: - Add deployments/ folder with DeploymentsTreeItem and DeploymentTreeItem - FunctionTreeItem uses DeploymentsTreeItem instead of TagsTreeItem - Update all settings tree items (Name, Schedule, Timeout, Events, Vars) to use new update() method signature - ExecutionsTreeItem uses Query helpers for pagination - ExecutionTreeItem uses $createdAt and duration instead of old fields Storage: - Add BucketTreeItem to show buckets as root level items - FileTreeItem now requires bucketId parameter and shows file details - StorageTreeItemProvider shows bucket hierarchy Co-Authored-By: Claude Opus 4.5 --- src/tree/database/CollectionTreeItem.ts | 14 +++- src/tree/database/DatabaseTreeItemProvider.ts | 73 +++++++++++++---- src/tree/database/DocumentsTreeItem.ts | 18 +++-- .../database/settings/AttributeTreeItem.ts | 44 +++++++++++ .../database/settings/AttributesTreeItem.ts | 48 ++++++++++++ .../database/settings/PermissionTreeItem.ts | 27 ++++++- .../database/settings/PermissionsTreeItem.ts | 63 ++++++++++++--- src/tree/functions/FunctionTreeItem.ts | 14 +++- .../functions/FunctionsTreeItemProvider.ts | 22 +++--- .../deployments/DeploymentTreeItem.ts | 47 +++++++++++ .../deployments/DeploymentsTreeItem.ts | 42 ++++++++++ .../functions/executions/ExecutionTreeItem.ts | 57 +++++--------- .../executions/ExecutionsTreeItem.ts | 18 +++-- src/tree/functions/settings/EventsTreeItem.ts | 15 +++- src/tree/functions/settings/NameTreeItem.ts | 15 +++- .../functions/settings/ScheduleTreeItem.ts | 15 +++- .../functions/settings/TimeoutTreeItem.ts | 12 ++- src/tree/functions/settings/VarsTreeItem.ts | 26 +++++-- src/tree/storage/FileTreeItem.ts | 37 ++++++++- src/tree/storage/StorageTreeItemProvider.ts | 78 +++++++++++++++++-- 20 files changed, 570 insertions(+), 115 deletions(-) create mode 100644 src/tree/database/settings/AttributeTreeItem.ts create mode 100644 src/tree/database/settings/AttributesTreeItem.ts create mode 100644 src/tree/functions/deployments/DeploymentTreeItem.ts create mode 100644 src/tree/functions/deployments/DeploymentsTreeItem.ts diff --git a/src/tree/database/CollectionTreeItem.ts b/src/tree/database/CollectionTreeItem.ts index 22c3a02..52a40a2 100644 --- a/src/tree/database/CollectionTreeItem.ts +++ b/src/tree/database/CollectionTreeItem.ts @@ -5,22 +5,28 @@ import { AppwriteTreeItemBase } from "../../ui/AppwriteTreeItemBase"; import { DatabaseTreeItemProvider } from "./DatabaseTreeItemProvider"; import { DocumentsTreeItem } from "./DocumentsTreeItem"; import { PermissionsTreeItem } from "./settings/PermissionsTreeItem"; -import { RulesTreeItem } from "./settings/RulesTreeItem"; +import { AttributesTreeItem } from "./settings/AttributesTreeItem"; export class CollectionTreeItem extends AppwriteTreeItemBase { - constructor(public collection: Collection, public readonly provider: DatabaseTreeItemProvider) { + constructor( + public collection: Collection, + public readonly databaseId: string, + public readonly provider: DatabaseTreeItemProvider + ) { super(undefined, collection.name); + this.description = collection.$id; + this.tooltip = `Collection: ${collection.name}\nID: ${collection.$id}\nDatabase: ${databaseId}`; } public async getChildren(): Promise { - return [new RulesTreeItem(this), new PermissionsTreeItem(this), new DocumentsTreeItem(this)]; + return [new AttributesTreeItem(this), new PermissionsTreeItem(this), new DocumentsTreeItem(this)]; } public async refresh(): Promise { if (!databaseClient) { return; } - this.collection = (await databaseClient.getCollection(this.collection.$id)) ?? this.collection; + this.collection = (await databaseClient.getCollection(this.collection.$id, this.databaseId)) ?? this.collection; this.provider.refreshChild(this); } diff --git a/src/tree/database/DatabaseTreeItemProvider.ts b/src/tree/database/DatabaseTreeItemProvider.ts index 9d92c16..ba6f9af 100644 --- a/src/tree/database/DatabaseTreeItemProvider.ts +++ b/src/tree/database/DatabaseTreeItemProvider.ts @@ -1,15 +1,59 @@ import * as vscode from "vscode"; -import { client } from "../../client"; -import AppwriteCall from "../../utils/AppwriteCall"; -import { Collection, CollectionsList } from "../../appwrite"; +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; +import { databaseClient } from "../../client"; +import { Collection, Database } from "../../appwrite"; import { CollectionTreeItem } from "./CollectionTreeItem"; -import { AppwriteSDK } from "../../constants"; import { ext } from '../../extensionVariables'; import { AppwriteTreeItemBase } from '../../ui/AppwriteTreeItemBase'; +/** + * Tree item representing a database in the tree view + */ +export class DatabaseTreeItem extends AppwriteTreeItemBase { + constructor( + public database: Database, + public readonly provider: DatabaseTreeItemProvider + ) { + super(undefined, database.name); + this.description = database.$id; + this.tooltip = `Database: ${database.name}\nID: ${database.$id}\nEnabled: ${database.enabled}`; + } + + public async getChildren(): Promise { + if (!databaseClient) { + return []; + } + + const collections = await databaseClient.listCollections(this.database.$id); + if (!collections || collections.length === 0) { + return [{ label: "No collections found" }]; + } + + const collectionTreeItems = collections.map( + (collection: Collection) => new CollectionTreeItem(collection, this.database.$id, this.provider) + ); + const headerItem: TreeItem = { + label: `Total collections: ${collections.length}`, + }; + return [headerItem, ...collectionTreeItems]; + } + + public async refresh(): Promise { + if (!databaseClient) { + return; + } + this.database = (await databaseClient.getDatabase(this.database.$id)) ?? this.database; + this.provider.refreshChild(this); + } + + collapsibleState = TreeItemCollapsibleState.Collapsed; + contextValue = "database"; + iconPath = new ThemeIcon("database"); +} + export class DatabaseTreeItemProvider implements vscode.TreeDataProvider { private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter< - CollectionTreeItem | undefined | void + vscode.TreeItem | undefined | void >(); readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; @@ -29,7 +73,7 @@ export class DatabaseTreeItemProvider implements vscode.TreeDataProvider { ext.outputChannel?.appendLine('getChildren for: ' + parent?.label); - if (client === undefined) { + if (databaseClient === undefined) { return Promise.resolve([]); } @@ -37,17 +81,18 @@ export class DatabaseTreeItemProvider implements vscode.TreeDataProvider(databaseSdk.listCollections()); - if (collectionsList) { - const collectionTreeItems = collectionsList.collections.map((collection: Collection) => new CollectionTreeItem(collection, this)) ?? []; + // Root level: show databases + const databasesList = await databaseClient.listDatabases(); + if (databasesList && databasesList.databases.length > 0) { + const databaseTreeItems = databasesList.databases.map( + (database: Database) => new DatabaseTreeItem(database, this) + ); const headerItem: vscode.TreeItem = { - label: `Total collections: ${collectionsList.sum}`, + label: `Total databases: ${databasesList.total}`, }; - return [headerItem, ...collectionTreeItems]; + return [headerItem, ...databaseTreeItems]; } - return [{ label: "No collections found" }]; + return [{ label: "No databases found" }]; } } diff --git a/src/tree/database/DocumentsTreeItem.ts b/src/tree/database/DocumentsTreeItem.ts index 314c58c..eb9b01c 100644 --- a/src/tree/database/DocumentsTreeItem.ts +++ b/src/tree/database/DocumentsTreeItem.ts @@ -1,10 +1,7 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; -import { DocumentsList } from "../../appwrite"; -import { client } from "../../client"; -import { AppwriteSDK } from "../../constants"; +import { databaseClient } from "../../client"; import { ext } from "../../extensionVariables"; import { AppwriteTreeItemBase } from "../../ui/AppwriteTreeItemBase"; -import AppwriteCall from "../../utils/AppwriteCall"; import { CollectionTreeItem } from "./CollectionTreeItem"; import { DocumentTreeItem } from "./DocumentTreeItem"; @@ -14,8 +11,15 @@ export class DocumentsTreeItem extends AppwriteTreeItemBase } public async getChildren(): Promise { - const databaseSdk = new AppwriteSDK.Database(client); - const documentList = await AppwriteCall(databaseSdk.listDocuments(this.parent.collection.$id)); + if (!databaseClient) { + return []; + } + + const documentList = await databaseClient.listDocuments( + this.parent.collection.$id, + this.parent.databaseId + ); + if (documentList === undefined) { return []; } @@ -24,7 +28,7 @@ export class DocumentsTreeItem extends AppwriteTreeItemBase const documentTreeItems = documentList.documents.map((document) => new DocumentTreeItem(this, document)); const headerItem: TreeItem = { - label: `Total documents: ${documentTreeItems.length}`, + label: `Total documents: ${documentList.total}`, }; return [headerItem, ...documentTreeItems]; } diff --git a/src/tree/database/settings/AttributeTreeItem.ts b/src/tree/database/settings/AttributeTreeItem.ts new file mode 100644 index 0000000..101a2f9 --- /dev/null +++ b/src/tree/database/settings/AttributeTreeItem.ts @@ -0,0 +1,44 @@ +import { ThemeIcon } from "vscode"; +import { Attribute } from "../../../appwrite"; +import { ChildTreeItem } from "../../ChildTreeItem"; +import { AttributesTreeItem } from "./AttributesTreeItem"; + +export class AttributeTreeItem extends ChildTreeItem { + constructor(parent: AttributesTreeItem, public readonly attribute: Attribute) { + super(parent, { + label: attribute.key, + description: `${attribute.type}${attribute.required ? ' (required)' : ''}`, + }); + this.tooltip = `Key: ${attribute.key}\nType: ${attribute.type}\nRequired: ${attribute.required}\nStatus: ${attribute.status}`; + } + + iconPath = new ThemeIcon(this.getIconForType()); + contextValue = "collection.attribute"; + + private getIconForType(): string { + switch (this.attribute.type) { + case 'string': + return 'symbol-string'; + case 'integer': + case 'float': + case 'double': + return 'symbol-number'; + case 'boolean': + return 'symbol-boolean'; + case 'datetime': + return 'calendar'; + case 'email': + return 'mail'; + case 'url': + return 'link'; + case 'ip': + return 'globe'; + case 'enum': + return 'symbol-enum'; + case 'relationship': + return 'references'; + default: + return 'symbol-field'; + } + } +} diff --git a/src/tree/database/settings/AttributesTreeItem.ts b/src/tree/database/settings/AttributesTreeItem.ts new file mode 100644 index 0000000..b2b7f1a --- /dev/null +++ b/src/tree/database/settings/AttributesTreeItem.ts @@ -0,0 +1,48 @@ +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; +import { Attribute } from "../../../appwrite"; +import { databaseClient } from "../../../client"; +import { AppwriteTreeItemBase } from "../../../ui/AppwriteTreeItemBase"; +import { CommandTreeItem } from "../../CommandTreeItem"; +import { CollectionTreeItem } from "../CollectionTreeItem"; +import { AttributeTreeItem } from "./AttributeTreeItem"; + +export class AttributesTreeItem extends AppwriteTreeItemBase { + constructor(parent: CollectionTreeItem) { + super(parent, "Attributes"); + } + + public async getChildren(): Promise { + if (!databaseClient) { + return []; + } + + const attributesList = await databaseClient.listAttributes( + this.parent.collection.$id, + this.parent.databaseId + ); + + const attributes = attributesList?.attributes ?? []; + + if (attributes.length === 0) { + const addAttributeItem = new CommandTreeItem( + { label: "Add attribute", iconPath: new ThemeIcon("add") }, + { + command: "vscode-appwrite.createAttribute", + arguments: [this], + title: "Create attribute", + tooltip: "Create collection attribute" + } + ); + return [addAttributeItem]; + } + return attributes.map((attribute: Attribute) => new AttributeTreeItem(this, attribute)); + } + + public async refresh(): Promise { + await this.parent.refresh(); + } + + iconPath = new ThemeIcon("symbol-property"); + contextValue = "collection.attributes"; + collapsibleState = TreeItemCollapsibleState.Collapsed; +} diff --git a/src/tree/database/settings/PermissionTreeItem.ts b/src/tree/database/settings/PermissionTreeItem.ts index d4c76a5..41409cd 100644 --- a/src/tree/database/settings/PermissionTreeItem.ts +++ b/src/tree/database/settings/PermissionTreeItem.ts @@ -1,10 +1,35 @@ +import { ThemeIcon } from "vscode"; import { ChildTreeItem } from "../../ChildTreeItem"; import { PermissionsTreeItem } from "./PermissionsTreeItem"; +type PermissionType = 'read' | 'create' | 'update' | 'delete' | 'write'; + export class PermissionTreeItem extends ChildTreeItem { - constructor(parent: PermissionsTreeItem, public readonly permission: string, public readonly kind: "read" | "write") { + constructor( + parent: PermissionsTreeItem, + public readonly permission: string, + public readonly kind: PermissionType + ) { super(parent, { label: permission }); } + iconPath = new ThemeIcon(this.getIconForKind()); contextValue = 'permission'; + + private getIconForKind(): string { + switch (this.kind) { + case 'read': + return 'eye'; + case 'create': + return 'add'; + case 'update': + return 'edit'; + case 'delete': + return 'trash'; + case 'write': + return 'pencil'; + default: + return 'key'; + } + } } diff --git a/src/tree/database/settings/PermissionsTreeItem.ts b/src/tree/database/settings/PermissionsTreeItem.ts index 64788fd..509ea1a 100644 --- a/src/tree/database/settings/PermissionsTreeItem.ts +++ b/src/tree/database/settings/PermissionsTreeItem.ts @@ -1,25 +1,70 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; -import { Permissions } from "../../../appwrite"; import { AppwriteTreeItemBase } from "../../../ui/AppwriteTreeItemBase"; import { CollapsableTreeItem } from "../../CollapsableTreeItem"; import { CollectionTreeItem } from "../CollectionTreeItem"; import { PermissionTreeItem } from "./PermissionTreeItem"; +/** + * Permission types in SDK v21 + */ +type PermissionType = 'read' | 'create' | 'update' | 'delete' | 'write'; + export class PermissionsTreeItem extends AppwriteTreeItemBase { - public readonly permissions: Permissions; + public readonly permissions: string[]; constructor(parent: CollectionTreeItem) { super(parent, "Permissions"); - this.permissions = parent.collection.$permissions; + // In SDK v21, $permissions is a flat array of permission strings + this.permissions = parent.collection.$permissions ?? []; } public async getChildren(): Promise { - const readPermissions = this.permissions.read.map((perm) => new PermissionTreeItem(this, perm, "read")); - const writePermissions = this.permissions.write.map((perm) => new PermissionTreeItem(this, perm, "write")); - return [ - new CollapsableTreeItem(this, { label: "Read" }, readPermissions, "read"), - new CollapsableTreeItem(this, { label: "Write" }, writePermissions, "write"), - ]; + if (this.permissions.length === 0) { + return [{ label: "No permissions configured" }]; + } + + // Group permissions by type (read, create, update, delete, write) + const grouped = this.groupPermissions(); + + const children: TreeItem[] = []; + + for (const [type, perms] of Object.entries(grouped)) { + if (perms.length > 0) { + const permItems = perms.map((perm) => new PermissionTreeItem(this, perm, type as PermissionType)); + children.push(new CollapsableTreeItem(this, { label: this.capitalizeFirst(type) }, permItems, type)); + } + } + + return children; + } + + /** + * Group permissions by type (read, create, update, delete, write) + * Permissions are in format: "read(\"any\")", "create(\"users\")", etc. + */ + private groupPermissions(): Record { + const grouped: Record = { + read: [], + create: [], + update: [], + delete: [], + write: [], + }; + + for (const perm of this.permissions) { + const match = perm.match(/^(read|create|update|delete|write)\((.+)\)$/); + if (match) { + const type = match[1] as PermissionType; + const role = match[2].replace(/"/g, ''); // Remove quotes + grouped[type].push(role); + } + } + + return grouped; + } + + private capitalizeFirst(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); } iconPath = new ThemeIcon("shield"); diff --git a/src/tree/functions/FunctionTreeItem.ts b/src/tree/functions/FunctionTreeItem.ts index ae5e1ed..d553517 100644 --- a/src/tree/functions/FunctionTreeItem.ts +++ b/src/tree/functions/FunctionTreeItem.ts @@ -5,17 +5,23 @@ import { msToDate } from '../../utils/date'; import { ExecutionsTreeItem } from './executions/ExecutionsTreeItem'; import { FunctionsTreeItemProvider } from './FunctionsTreeItemProvider'; import { FunctionSettingsTreeItem } from './settings/FunctionSettingsTreeItem'; -import { TagsTreeItem } from './tags/TagsTreeItem'; +import { DeploymentsTreeItem } from './deployments/DeploymentsTreeItem'; export class FunctionTreeItem extends AppwriteTreeItemBase { constructor(public func: Function, public readonly provider: FunctionsTreeItemProvider) { super(undefined, func.name); - this.tooltip = new MarkdownString(`ID: ${func.$id} \nLast updated: ${msToDate(func.dateUpdated)} \nCreated: ${msToDate(func.dateCreated)}`); - this.description = func.env; + this.tooltip = new MarkdownString( + `**ID:** ${func.$id} \n` + + `**Runtime:** ${func.runtime} \n` + + `**Last updated:** ${msToDate(func.$updatedAt)} \n` + + `**Created:** ${msToDate(func.$createdAt)} \n` + + `**Enabled:** ${func.enabled}` + ); + this.description = func.runtime; } public async getChildren(): Promise { - return [new FunctionSettingsTreeItem(this), new TagsTreeItem(this), new ExecutionsTreeItem(this)]; + return [new FunctionSettingsTreeItem(this), new DeploymentsTreeItem(this), new ExecutionsTreeItem(this)]; } public async refresh(): Promise { diff --git a/src/tree/functions/FunctionsTreeItemProvider.ts b/src/tree/functions/FunctionsTreeItemProvider.ts index 6713b71..0445807 100644 --- a/src/tree/functions/FunctionsTreeItemProvider.ts +++ b/src/tree/functions/FunctionsTreeItemProvider.ts @@ -1,7 +1,6 @@ import * as vscode from "vscode"; -import { client } from "../../client"; -import { Function, FunctionsList } from "../../appwrite"; -import { AppwriteSDK } from "../../constants"; +import { functionsClient } from "../../client"; +import { Function } from "../../appwrite"; import { AppwriteTreeItemBase } from "../../ui/AppwriteTreeItemBase"; import { ext } from "../../extensionVariables"; import { EventEmitter, TreeItem } from "vscode"; @@ -26,18 +25,19 @@ export class FunctionsTreeItemProvider implements vscode.TreeDataProvider { - if (client === undefined) { + if (functionsClient === undefined) { return Promise.resolve([]); } if (parent === undefined) { - const functionsSdk = new AppwriteSDK.Functions(client); - - const list: FunctionsList = await functionsSdk.list(); - - if (list) { - const functionTreeItems = list.functions.map((func: Function) => new FunctionTreeItem(func, this)) ?? []; - return functionTreeItems; + const list = await functionsClient.list(); + + if (list && list.functions.length > 0) { + const functionTreeItems = list.functions.map((func: Function) => new FunctionTreeItem(func, this)); + const headerItem: TreeItem = { + label: `Total functions: ${list.total}`, + }; + return [headerItem, ...functionTreeItems]; } return [{ label: "No functions found" }]; diff --git a/src/tree/functions/deployments/DeploymentTreeItem.ts b/src/tree/functions/deployments/DeploymentTreeItem.ts new file mode 100644 index 0000000..0885cc0 --- /dev/null +++ b/src/tree/functions/deployments/DeploymentTreeItem.ts @@ -0,0 +1,47 @@ +import { MarkdownString, ThemeIcon, TreeItem } from "vscode"; +import { Deployment } from '../../../appwrite'; +import { msToDate } from '../../../utils/date'; +import { DeploymentsTreeItem } from './DeploymentsTreeItem'; + +export class DeploymentTreeItem extends TreeItem { + constructor(public readonly parent: DeploymentsTreeItem, public readonly deployment: Deployment) { + super(deployment.$id); + const func = parent.parent.func; + const active = func.deployment === deployment.$id; + this.label = `${msToDate(deployment.$createdAt)}${active ? ' (Active)' : ''}`; + this.description = `${deployment.status} - ${deployment.$id}`; + this.iconPath = new ThemeIcon(this.getStatusIcon(deployment.status, active)); + this.contextValue = `deployment${active ? '_active' : ''}`; + this.tooltip = new MarkdownString( + `**ID:** ${deployment.$id} \n` + + `**Created:** ${msToDate(deployment.$createdAt)} \n` + + `**Status:** ${deployment.status} \n` + + `**Size:** ${this.formatSize(deployment.size)} \n` + + `**Build Time:** ${deployment.buildTime}ms \n` + + `**Entrypoint:** ${deployment.entrypoint || 'N/A'}` + ); + } + + private getStatusIcon(status: string, active: boolean): string { + if (active) { + return 'circle-large-filled'; + } + switch (status) { + case 'ready': + return 'check'; + case 'processing': + case 'building': + return 'sync~spin'; + case 'failed': + return 'error'; + default: + return 'circle-large-outline'; + } + } + + private formatSize(bytes: number): string { + if (bytes < 1024) return `${bytes}B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`; + return `${(bytes / (1024 * 1024)).toFixed(1)}MB`; + } +} diff --git a/src/tree/functions/deployments/DeploymentsTreeItem.ts b/src/tree/functions/deployments/DeploymentsTreeItem.ts new file mode 100644 index 0000000..a0c03fd --- /dev/null +++ b/src/tree/functions/deployments/DeploymentsTreeItem.ts @@ -0,0 +1,42 @@ +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; +import { functionsClient } from "../../../client"; +import { AppwriteTreeItemBase } from '../../../ui/AppwriteTreeItemBase'; +import { FunctionTreeItem } from '../FunctionTreeItem'; +import { DeploymentTreeItem } from './DeploymentTreeItem'; + +export class DeploymentsTreeItem extends AppwriteTreeItemBase { + constructor(public readonly parent: FunctionTreeItem) { + super(parent, "Deployments"); + } + + public async getChildren(): Promise { + if (!functionsClient) { + return []; + } + const deployments = await functionsClient.listDeployments(this.parent.func.$id); + const children = deployments?.deployments + .sort((a, b) => new Date(b.$createdAt).getTime() - new Date(a.$createdAt).getTime()) + .map((deployment) => new DeploymentTreeItem(this, deployment)) ?? []; + + if (children.length === 0) { + const noDeploymentsItem: TreeItem = { + command: { + command: "vscode-appwrite.CreateDeployment", + title: "Create deployment", + arguments: [this], + tooltip: "Create a deployment" + }, + label: "Create a deployment", + iconPath: new ThemeIcon("cloud-upload"), + }; + return [noDeploymentsItem]; + } + return children; + } + + collapsibleState = TreeItemCollapsibleState.Collapsed; + + contextValue = "deployments"; + + iconPath = new ThemeIcon("package"); +} diff --git a/src/tree/functions/executions/ExecutionTreeItem.ts b/src/tree/functions/executions/ExecutionTreeItem.ts index 622486c..7fe7787 100644 --- a/src/tree/functions/executions/ExecutionTreeItem.ts +++ b/src/tree/functions/executions/ExecutionTreeItem.ts @@ -4,8 +4,9 @@ import { msToDate } from "../../../utils/date"; import { ExecutionsTreeItem } from "./ExecutionsTreeItem"; const executionStatusIcons: Record = { - processing: new ThemeIcon("loading"), + processing: new ThemeIcon("loading~spin"), waiting: new ThemeIcon("circle-outline"), + scheduled: new ThemeIcon("clock"), completed: new ThemeIcon("circle-filled", new ThemeColor("testing.iconPassed")), failed: new ThemeIcon("circle-filled", new ThemeColor("testing.iconFailed")), }; @@ -17,40 +18,21 @@ export class ExecutionTreeItem extends TreeItem { constructor(public readonly parent: ExecutionsTreeItem, public execution: Execution) { super(execution.$id); this.label = this.getLabel(execution); - this.iconPath = executionStatusIcons[execution.status]; - const md = `Id: ${execution.$id} \nCreated: ${this.getCreated(execution)} \nTrigger: ${execution.trigger}`; - this.tooltip = new MarkdownString(md); + this.iconPath = executionStatusIcons[execution.status] ?? new ThemeIcon("circle-outline"); + const md = new MarkdownString( + `**ID:** ${execution.$id} \n` + + `**Created:** ${this.getCreated(execution)} \n` + + `**Trigger:** ${execution.trigger} \n` + + `**Status:** ${execution.status} \n` + + `**Duration:** ${execution.duration}s \n` + + `**Status Code:** ${execution.responseStatusCode}` + ); + this.tooltip = md; this.description = execution.trigger; this.contextValue = this.getContextValue(execution); - this.isAutoRefreshing = execution.status === "processing" || execution.status === "waiting"; - // if (this.isAutoRefreshing) { - // this.autoRefresh(); - // } + this.isAutoRefreshing = execution.status === "processing" || execution.status === "waiting" || execution.status === "scheduled"; } - // async autoRefresh(): Promise { - // if (!this.isAutoRefreshing && this.refreshCount < 5) { - // return; - // } - // this.refreshCount++; - // ext.outputChannel.appendLog("Refreshing execution."); - // const execution = await functionsClient?.getExecution(this.parent.parent.func.$id, this.execution.$id); - - // if (!execution) { - // ext.outputChannel.appendLog("Execution is undefined"); - // this.isAutoRefreshing = false; - // return; - // } - // this.execution = execution; - // this.contextValue = this.getContextValue(execution); - // this.iconPath = executionStatusIcons[execution.status]; - // this.label = this.getLabel(execution); - // this.isAutoRefreshing = execution.status === "processing" || execution.status === "waiting"; - // ext.tree?.functions?.refreshChild(this); - // await sleep(1000); - // this.autoRefresh(); - // } - getLabel(execution: Execution): string { if (execution.status === "completed" || execution.status === "failed") { return `${this.getCreated(execution)} (${this.getExecutionTime(execution)}s)`; @@ -59,18 +41,21 @@ export class ExecutionTreeItem extends TreeItem { } getExecutionTime(execution: Execution): string { - return execution.time.toPrecision(2); + return execution.duration.toPrecision(2); } getContextValue(execution: Execution): string { if (execution.status === "completed" || execution.status === "failed") { - if (execution.stderr === "" && execution.stdout === "") { + const hasLogs = execution.logs && execution.logs.length > 0; + const hasErrors = execution.errors && execution.errors.length > 0; + + if (!hasErrors && !hasLogs) { return "execution_noErrorOrOutput"; } - if (execution.stderr === "") { + if (!hasErrors) { return "execution_outputOnly"; } - if (execution.stdout === "") { + if (!hasLogs) { return "execution_errorOnly"; } } @@ -78,6 +63,6 @@ export class ExecutionTreeItem extends TreeItem { } getCreated(execution: Execution): string { - return msToDate(execution.dateCreated); + return msToDate(execution.$createdAt); } } diff --git a/src/tree/functions/executions/ExecutionsTreeItem.ts b/src/tree/functions/executions/ExecutionsTreeItem.ts index 148409b..d13ce69 100644 --- a/src/tree/functions/executions/ExecutionsTreeItem.ts +++ b/src/tree/functions/executions/ExecutionsTreeItem.ts @@ -1,6 +1,7 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { Execution, ExecutionList } from "../../../appwrite"; import { functionsClient } from "../../../client"; +import { Query } from "../../../constants"; import { ExecutionTreeItem } from "./ExecutionTreeItem"; import { FunctionTreeItem } from "../FunctionTreeItem"; import { ext } from "../../../extensionVariables"; @@ -17,21 +18,26 @@ export class ExecutionsTreeItem extends AppwriteTreeItemBase { if (!functionsClient) { return []; } + + // Use Query helpers for pagination and sorting + const queries = [ + Query.limit(this.executionsToShow), + Query.orderDesc('$createdAt') + ]; + const executions: ExecutionList | undefined = await functionsClient.listExecutions( this.parent.func.$id, - undefined, - this.executionsToShow, - undefined, - "DESC" + queries ); + const children = executions?.executions.map((execution: Execution) => new ExecutionTreeItem(this, execution)) ?? [ new TreeItem("No executions."), ]; if (children.length === 0) { children.push(new TreeItem("No executions.")); } - ext.outputChannel.appendLog(`Found ${executions?.sum} executions`); - if (executions?.sum ?? (0 > this.executionsToShow && this.executionsToShow !== 100)) { + ext.outputChannel.appendLog(`Found ${executions?.total} executions`); + if ((executions?.total ?? 0) > this.executionsToShow && this.executionsToShow !== 100) { const viewMoreItem: TreeItem = { command: { command: "vscode-appwrite.viewMore", diff --git a/src/tree/functions/settings/EventsTreeItem.ts b/src/tree/functions/settings/EventsTreeItem.ts index 89bf252..fc35594 100644 --- a/src/tree/functions/settings/EventsTreeItem.ts +++ b/src/tree/functions/settings/EventsTreeItem.ts @@ -25,7 +25,20 @@ export class EventsTreeItem extends EnumEditableTreeItemBase { } public async setValue(value: string[]): Promise { - await functionsClient?.update(this.func.$id, this.func.name, [], this.func.vars, value, this.func.schedule, this.func.timeout); + await functionsClient?.update( + this.func.$id, + this.func.name, + this.func.runtime, + this.func.execute, + value, + this.func.schedule, + this.func.timeout, + this.func.enabled, + this.func.logging, + this.func.entrypoint, + this.func.commands, + this.func.scopes + ); ext.tree?.functions?.refresh(); } } diff --git a/src/tree/functions/settings/NameTreeItem.ts b/src/tree/functions/settings/NameTreeItem.ts index 25f6c30..55e1686 100644 --- a/src/tree/functions/settings/NameTreeItem.ts +++ b/src/tree/functions/settings/NameTreeItem.ts @@ -31,7 +31,20 @@ export class NameTreeItem extends StringEditableTreeItemBase { if (value.length === 0) { return; } - await functionsClient?.update(this.func.$id, value, [], this.func.vars, this.func.events, this.func.schedule, this.func.timeout); + await functionsClient?.update( + this.func.$id, + value, + this.func.runtime, + this.func.execute, + this.func.events, + this.func.schedule, + this.func.timeout, + this.func.enabled, + this.func.logging, + this.func.entrypoint, + this.func.commands, + this.func.scopes + ); ext.tree?.functions?.refresh(); } diff --git a/src/tree/functions/settings/ScheduleTreeItem.ts b/src/tree/functions/settings/ScheduleTreeItem.ts index 10a2e15..9ce5871 100644 --- a/src/tree/functions/settings/ScheduleTreeItem.ts +++ b/src/tree/functions/settings/ScheduleTreeItem.ts @@ -25,7 +25,20 @@ export class ScheduleTreeItem extends StringEditableTreeItemBase { }; public async setValue(value: string): Promise { - await functionsClient?.update(this.func.$id, this.func.name, [], this.func.vars, this.func.events, value === "" ? undefined : value, this.func.timeout); + await functionsClient?.update( + this.func.$id, + this.func.name, + this.func.runtime, + this.func.execute, + this.func.events, + value === "" ? undefined : value, + this.func.timeout, + this.func.enabled, + this.func.logging, + this.func.entrypoint, + this.func.commands, + this.func.scopes + ); ext.tree?.functions?.refresh(); } diff --git a/src/tree/functions/settings/TimeoutTreeItem.ts b/src/tree/functions/settings/TimeoutTreeItem.ts index b2e8a62..9549fd5 100644 --- a/src/tree/functions/settings/TimeoutTreeItem.ts +++ b/src/tree/functions/settings/TimeoutTreeItem.ts @@ -5,7 +5,6 @@ import { ext } from "../../../extensionVariables"; import { StringEditableTreeItemBase } from "../../common/editable/StringEditableTreeItem"; function isNumeric(str: string) { - console.log("here"); return !isNaN(+str); } @@ -31,11 +30,16 @@ export class TimeoutTreeItem extends StringEditableTreeItemBase { await functionsClient?.update( this.func.$id, this.func.name, - [], - this.func.vars, + this.func.runtime, + this.func.execute, this.func.events, this.func.schedule, - parseInt(value) + parseInt(value), + this.func.enabled, + this.func.logging, + this.func.entrypoint, + this.func.commands, + this.func.scopes ); ext.tree?.functions?.refresh(); } diff --git a/src/tree/functions/settings/VarsTreeItem.ts b/src/tree/functions/settings/VarsTreeItem.ts index 165b8dc..b115f0a 100644 --- a/src/tree/functions/settings/VarsTreeItem.ts +++ b/src/tree/functions/settings/VarsTreeItem.ts @@ -1,21 +1,33 @@ -import { TreeItem, TreeItemCollapsibleState } from "vscode"; -import { Vars } from "../../../appwrite"; +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; +import { functionsClient } from "../../../client"; import { AppwriteTreeItemBase } from '../../../ui/AppwriteTreeItemBase'; import { FunctionSettingsTreeItem } from "./FunctionSettingsTreeItem"; import { VarTreeItem } from "./VarTreeItem"; export class VarsTreeItem extends AppwriteTreeItemBase { - public readonly vars: Vars; - constructor(parent: FunctionSettingsTreeItem) { - super(parent, "Environment variables"); - this.vars = parent.func.vars; + super(parent, "Variables"); this.description = undefined; } public async getChildren(): Promise { - return Object.keys(this.vars).map((key) => new VarTreeItem(this, key, this.vars[key])); + if (!functionsClient) { + return []; + } + + const variablesList = await functionsClient.listVariables(this.parent.func.$id); + const variables = variablesList?.variables ?? []; + + if (variables.length === 0) { + return [{ + label: "No variables", + iconPath: new ThemeIcon("info") + }]; + } + + return variables.map((variable) => new VarTreeItem(this, variable.key, variable.value)); } + contextValue = "vars"; collapsibleState = TreeItemCollapsibleState.Collapsed; } diff --git a/src/tree/storage/FileTreeItem.ts b/src/tree/storage/FileTreeItem.ts index a88f0c7..4f5edb8 100644 --- a/src/tree/storage/FileTreeItem.ts +++ b/src/tree/storage/FileTreeItem.ts @@ -1,12 +1,43 @@ -import { ThemeIcon, TreeItem } from "vscode"; +import { MarkdownString, ThemeIcon, TreeItem } from "vscode"; import { File } from "../../appwrite"; export class FileTreeItem extends TreeItem { - constructor(public readonly file: File) { + constructor( + public readonly file: File, + public readonly bucketId: string + ) { super(file.name); + this.description = this.formatSize(file.sizeOriginal); + this.tooltip = new MarkdownString( + `**Name:** ${file.name} \n` + + `**ID:** ${file.$id} \n` + + `**Size:** ${this.formatSize(file.sizeOriginal)} \n` + + `**MIME Type:** ${file.mimeType} \n` + + `**Bucket:** ${bucketId}` + ); } - iconPath = new ThemeIcon("file"); + private formatSize(bytes: number): string { + if (bytes < 1024) return `${bytes}B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`; + if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`; + return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`; + } + + private getIconForMimeType(): string { + const mimeType = this.file.mimeType.toLowerCase(); + if (mimeType.startsWith('image/')) return 'file-media'; + if (mimeType.startsWith('video/')) return 'play'; + if (mimeType.startsWith('audio/')) return 'play'; + if (mimeType.includes('pdf')) return 'file-pdf'; + if (mimeType.includes('json')) return 'json'; + if (mimeType.includes('xml')) return 'file-code'; + if (mimeType.includes('text/')) return 'file-text'; + if (mimeType.includes('zip') || mimeType.includes('tar') || mimeType.includes('gzip')) return 'file-zip'; + return 'file'; + } + + iconPath = new ThemeIcon(this.getIconForMimeType()); contextValue = "file"; } diff --git a/src/tree/storage/StorageTreeItemProvider.ts b/src/tree/storage/StorageTreeItemProvider.ts index 42877c0..66d3c20 100644 --- a/src/tree/storage/StorageTreeItemProvider.ts +++ b/src/tree/storage/StorageTreeItemProvider.ts @@ -1,7 +1,60 @@ import * as vscode from "vscode"; +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { storageClient } from "../../client"; +import { Bucket, File } from "../../appwrite"; +import { AppwriteTreeItemBase } from "../../ui/AppwriteTreeItemBase"; import { FileTreeItem } from "./FileTreeItem"; +/** + * Tree item representing a storage bucket + */ +export class BucketTreeItem extends AppwriteTreeItemBase { + constructor( + public bucket: Bucket, + public readonly provider: StorageTreeItemProvider + ) { + super(undefined, bucket.name); + this.description = bucket.$id; + this.tooltip = `Bucket: ${bucket.name}\nID: ${bucket.$id}\nEnabled: ${bucket.enabled}\nMax File Size: ${this.formatSize(bucket.maximumFileSize)}`; + } + + public async getChildren(): Promise { + if (!storageClient) { + return []; + } + + const files = await storageClient.listFiles(this.bucket.$id); + if (!files || files.files.length === 0) { + return [{ label: "No files found" }]; + } + + const fileTreeItems = files.files.map((file: File) => new FileTreeItem(file, this.bucket.$id)); + const headerItem: TreeItem = { + label: `Total files: ${files.total}`, + }; + return [headerItem, ...fileTreeItems]; + } + + public async refresh(): Promise { + if (!storageClient) { + return; + } + this.bucket = (await storageClient.getBucket(this.bucket.$id)) ?? this.bucket; + this.provider.refreshChild(this); + } + + private formatSize(bytes: number): string { + if (bytes < 1024) return `${bytes}B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`; + if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`; + return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`; + } + + collapsibleState = TreeItemCollapsibleState.Collapsed; + contextValue = "bucket"; + iconPath = new ThemeIcon("archive"); +} + export class StorageTreeItemProvider implements vscode.TreeDataProvider { private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter< vscode.TreeItem | undefined | void @@ -13,20 +66,33 @@ export class StorageTreeItemProvider implements vscode.TreeDataProvider { + async getChildren(parent?: vscode.TreeItem): Promise { if (storageClient === undefined) { return []; } - const files = await storageClient.listFiles(); - if (files === undefined || files?.files.length === 0) { - const noStorage = new vscode.TreeItem("No files found"); - return [noStorage]; + if (parent instanceof AppwriteTreeItemBase) { + return await parent.getChildren?.() ?? []; } - return files.files.map((file) => new FileTreeItem(file)); + + // Root level: show buckets + const buckets = await storageClient.listBuckets(); + if (buckets && buckets.buckets.length > 0) { + const bucketTreeItems = buckets.buckets.map((bucket: Bucket) => new BucketTreeItem(bucket, this)); + const headerItem: TreeItem = { + label: `Total buckets: ${buckets.total}`, + }; + return [headerItem, ...bucketTreeItems]; + } + + return [{ label: "No buckets found" }]; } } From 4ee59f34cf9c6f7bcfcd1c354924b9aad5d8e697 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Fri, 23 Jan 2026 16:09:17 +0100 Subject: [PATCH 08/14] refactor: Update commands for SDK v21 Database commands: - createCollection: Add database selection when no default configured - deleteCollection: Pass databaseId from CollectionTreeItem - deleteDocument: Pass databaseId from CollectionTreeItem hierarchy Function commands: - Add new deployment commands (createDeployment, deleteDeployment, activateDeployment) - Keep tag commands as backward compatibility aliases - createFunction: Add success message and error handling - createExecution: Use duration instead of time, handle scheduled status - viewExecutionOutput/Errors: Use logs/errors instead of stdout/stderr - copyExecutionOutput/Errors: Use logs/errors instead of stdout/stderr registerCommands: - Import new deployment commands - Register both deployment and legacy tag commands Co-Authored-By: Claude Opus 4.5 --- src/commands/database/createCollection.ts | 33 +++- src/commands/database/deleteCollection.ts | 6 +- src/commands/database/deleteDocument.ts | 9 +- src/commands/functions/activateDeployment.ts | 34 ++++ src/commands/functions/copyExecutionErrors.ts | 3 +- src/commands/functions/copyExecutionOutput.ts | 3 +- src/commands/functions/createDeployment.ts | 183 ++++++++++++++++++ src/commands/functions/createExecution.ts | 22 ++- src/commands/functions/createFunction.ts | 20 +- src/commands/functions/deleteDeployment.ts | 30 +++ src/commands/functions/viewExecutionErrors.ts | 8 +- src/commands/functions/viewExecutionOutput.ts | 9 +- src/commands/registerCommands.ts | 17 +- 13 files changed, 347 insertions(+), 30 deletions(-) create mode 100644 src/commands/functions/activateDeployment.ts create mode 100644 src/commands/functions/createDeployment.ts create mode 100644 src/commands/functions/deleteDeployment.ts diff --git a/src/commands/database/createCollection.ts b/src/commands/database/createCollection.ts index 4973b37..e97877f 100644 --- a/src/commands/database/createCollection.ts +++ b/src/commands/database/createCollection.ts @@ -1,17 +1,44 @@ import { window } from "vscode"; -import { databaseClient } from "../../client"; +import { clientConfig, databaseClient } from "../../client"; +import { DatabaseTreeItem } from "../../tree/database/DatabaseTreeItemProvider"; -export async function createCollection(): Promise { +export async function createCollection(databaseTreeItem?: DatabaseTreeItem): Promise { if (!databaseClient) { return; } + // Get databaseId from tree item, config, or let user select + let databaseId = databaseTreeItem?.database.$id || clientConfig?.databaseId; + + if (!databaseId) { + // List databases and let user select + const databases = await databaseClient.listDatabases(); + if (!databases || databases.databases.length === 0) { + window.showErrorMessage("No databases found. Please create a database first."); + return; + } + + const selected = await window.showQuickPick( + databases.databases.map(db => ({ + label: db.name, + description: db.$id, + id: db.$id + })), + { placeHolder: "Select a database" } + ); + + if (!selected) { + return; + } + databaseId = selected.id; + } + const name = await window.showInputBox({ prompt: "Collection name", }); if (name && name.length > 0) { - await databaseClient.createCollection({ name }); + await databaseClient.createCollection({ name, $permissions: [] }, databaseId); window.showInformationMessage(`Created collection "${name}".`); } } diff --git a/src/commands/database/deleteCollection.ts b/src/commands/database/deleteCollection.ts index fe1458f..828c652 100644 --- a/src/commands/database/deleteCollection.ts +++ b/src/commands/database/deleteCollection.ts @@ -8,13 +8,15 @@ export async function deleteCollection(collectionTreeItem: CollectionTreeItem): return; } const collection = collectionTreeItem.collection; + const databaseId = collectionTreeItem.databaseId; + try { const shouldDelete = await confirmDialog(`Delete collection "${collection.name}"?`); if (shouldDelete) { - await databaseClient.deleteCollection(collection.$id); + await databaseClient.deleteCollection(collection.$id, databaseId); window.showInformationMessage(`Deleted collection "${collection.name}".`); } } catch (e) { - window.showErrorMessage(e); + window.showErrorMessage(e.message || String(e)); } } diff --git a/src/commands/database/deleteDocument.ts b/src/commands/database/deleteDocument.ts index 996f72f..d2a0aac 100644 --- a/src/commands/database/deleteDocument.ts +++ b/src/commands/database/deleteDocument.ts @@ -8,14 +8,17 @@ export async function deleteDocument(documentTreeItem: DocumentTreeItem): Promis return; } const document = documentTreeItem.document; - const collection = documentTreeItem.parent.parent.collection; + const collectionTreeItem = documentTreeItem.parent.parent; + const collection = collectionTreeItem.collection; + const databaseId = collectionTreeItem.databaseId; + try { const shouldDelete = await confirmDialog(`Delete document "${document["$id"]}" from ${collection.name}?`); if (shouldDelete) { - await databaseClient.deleteDocument(collection.$id, document["$id"]); + await databaseClient.deleteDocument(collection.$id, document["$id"], databaseId); window.showInformationMessage(`Deleted document "${document["$id"]}" from ${collection.name}.`); } } catch (e) { - window.showErrorMessage(e); + window.showErrorMessage(e.message || String(e)); } } diff --git a/src/commands/functions/activateDeployment.ts b/src/commands/functions/activateDeployment.ts new file mode 100644 index 0000000..269c10b --- /dev/null +++ b/src/commands/functions/activateDeployment.ts @@ -0,0 +1,34 @@ +import { window } from "vscode"; +import { Deployment } from '../../appwrite'; +import { functionsClient } from '../../client'; +import { DeploymentTreeItem } from '../../tree/functions/deployments/DeploymentTreeItem'; +import { ext } from "../../extensionVariables"; + +export async function activateDeployment(deploymentItem: DeploymentTreeItem | Deployment): Promise { + if (!functionsClient) { + return; + } + + let functionId: string; + let deploymentId: string; + + if (deploymentItem instanceof DeploymentTreeItem) { + functionId = deploymentItem.parent.parent.func.$id; + deploymentId = deploymentItem.deployment.$id; + } else { + // It's a Deployment object - we need the functionId from it + functionId = deploymentItem.resourceId; + deploymentId = deploymentItem.$id; + } + + try { + await functionsClient.updateDeployment(functionId, deploymentId); + window.showInformationMessage(`Activated deployment "${deploymentId}".`); + ext.tree?.functions?.refresh(); + } catch (e) { + window.showErrorMessage(e.message || String(e)); + } +} + +// Backward compatibility alias +export { activateDeployment as activateTag }; diff --git a/src/commands/functions/copyExecutionErrors.ts b/src/commands/functions/copyExecutionErrors.ts index 889bdd0..aacf998 100644 --- a/src/commands/functions/copyExecutionErrors.ts +++ b/src/commands/functions/copyExecutionErrors.ts @@ -7,5 +7,6 @@ export async function copyExecutionErrors(executionItem: ExecutionTreeItem): Pro } const execution = executionItem.execution; - env.clipboard.writeText(execution.stderr); + // SDK v21: stderr renamed to errors + env.clipboard.writeText(execution.errors || ''); } diff --git a/src/commands/functions/copyExecutionOutput.ts b/src/commands/functions/copyExecutionOutput.ts index a1edf27..87084f2 100644 --- a/src/commands/functions/copyExecutionOutput.ts +++ b/src/commands/functions/copyExecutionOutput.ts @@ -7,5 +7,6 @@ export async function copyExecutionOutput(executionItem: ExecutionTreeItem): Pro } const execution = executionItem.execution; - env.clipboard.writeText(execution.stdout); + // SDK v21: stdout renamed to logs + env.clipboard.writeText(execution.logs || ''); } diff --git a/src/commands/functions/createDeployment.ts b/src/commands/functions/createDeployment.ts new file mode 100644 index 0000000..89973c4 --- /dev/null +++ b/src/commands/functions/createDeployment.ts @@ -0,0 +1,183 @@ +import { ProgressLocation, QuickPickItem, Uri, window, workspace } from "vscode"; +import { functionsClient } from "../../client"; +import { getTarReadStream } from "../../utils/tar"; +import { ext } from "../../extensionVariables"; +import * as fs from "fs"; +import { DeploymentsTreeItem } from "../../tree/functions/deployments/DeploymentsTreeItem"; +import { selectWorkspaceFolder } from "../../utils/workspace"; +import { ProgressMessage } from "../../utils/types"; +import { Deployment } from "../../appwrite"; +import { activateDeployment } from "./activateDeployment"; + +export async function createDeployment(item?: DeploymentsTreeItem | Uri): Promise { + if (item instanceof Uri) { + const functions = await functionsClient?.list(); + if (functions === undefined) { + return; + } + const pick = await window.showQuickPick( + functions.functions.map( + (func): QuickPickItem => ({ label: func.name, description: func.runtime, detail: func.$id }) + ), + { placeHolder: "Select a function to create deployment" } + ); + if (pick === undefined || pick.detail === undefined) { + return; + } + const deployments = await functionsClient?.listDeployments(pick.detail); + let value; + if (deployments && deployments.deployments.length > 0) { + value = deployments.deployments[deployments.deployments.length - 1].entrypoint; + } + const entrypoint = await window.showInputBox({ value, prompt: "Entrypoint for your function" }); + if (entrypoint === undefined) { + return; + } + const deployment = await window.withProgress( + { location: ProgressLocation.Notification, title: "Creating deployment..." }, + async (progress, _token) => { + if (pick.detail === undefined) { + return; + } + return await createDeploymentFromUri(pick.detail, entrypoint, item, progress); + } + ); + if (deployment) { + await deploymentNotification(deployment); + } + + return; + } + + if (item instanceof DeploymentsTreeItem) { + const func = item.parent.func; + const folder = await selectWorkspaceFolder("Select folder of your function code."); + if (folder === undefined || folder === "") { + return; + } + const deployments = await functionsClient?.listDeployments(func.$id); + let value; + if (deployments && deployments.deployments.length > 0) { + value = deployments.deployments[deployments.deployments.length - 1].entrypoint; + } + const entrypoint = await window.showInputBox({ value, prompt: "Entrypoint for your function" }); + if (entrypoint === undefined) { + return; + } + const deployment = await window.withProgress( + { location: ProgressLocation.Notification, title: "Creating deployment..." }, + async (progress, _token) => { + return await createDeploymentFromUri(func.$id, entrypoint, Uri.parse(folder), progress); + } + ); + + if (deployment) { + await deploymentNotification(deployment); + return; + } + } + + if (item === undefined) { + const functions = await functionsClient?.list(); + if (functions === undefined) { + return; + } + const pick = await window.showQuickPick( + functions.functions.map( + (func): QuickPickItem => ({ label: func.name, description: func.runtime, detail: func.$id }) + ), + { placeHolder: "Select a function to create deployment" } + ); + if (pick === undefined || pick.detail === undefined) { + return; + } + const funcId = pick.detail; + const folder = await selectWorkspaceFolder("Select folder of your function code."); + const deployments = await functionsClient?.listDeployments(funcId); + let value; + if (deployments && deployments.deployments.length > 0) { + value = deployments.deployments[deployments.deployments.length - 1].entrypoint; + } + const entrypoint = await window.showInputBox({ value, prompt: "Entrypoint for your function" }); + if (entrypoint === undefined) { + return; + } + const deployment = await window.withProgress( + { location: ProgressLocation.Notification, title: "Creating deployment..." }, + async (progress, _token) => { + return await createDeploymentFromUri(funcId, entrypoint, Uri.parse(folder), progress); + } + ); + + if (deployment) { + await deploymentNotification(deployment); + return; + } + } +} + +async function createDeploymentFromUri( + functionId: string, + entrypoint: string, + uri: Uri, + progress: ProgressMessage +): Promise { + progress.report({ message: "Creating tarball", increment: 10 }); + + if (functionsClient === undefined) { + return; + } + + let tarFilePath; + try { + tarFilePath = await getTarReadStream(uri); + } catch (e) { + window.showErrorMessage("Error creating tar file.\n" + e); + return; + } + if (tarFilePath === undefined) { + window.showErrorMessage("Failed to create tar file."); + ext.outputChannel.appendLog("Failed to create tar file."); + return; + } + // somehow makes the upload work + await workspace.fs.readFile(Uri.file(tarFilePath)); + progress.report({ message: "Uploading deployment", increment: 60 }); + try { + return await functionsClient.createDeployment( + functionId, + fs.createReadStream(tarFilePath), + true, // activate + entrypoint + ); + } catch (e) { + ext.outputChannel.appendLog("Creating deployment error: " + e); + } +} + +async function deploymentNotification(deployment: Deployment): Promise { + ext.tree?.functions?.refresh(); + if (deployment) { + const action = await window.showInformationMessage( + `Successfully created deployment with size ${formatSize(deployment.size)}.`, + "Activate deployment", + "View in console" + ); + if (action === "Activate deployment") { + await activateDeployment(deployment); + } + if (action === "View in console") { + // + } + return; + } +} + +function formatSize(bytes: number): string { + if (bytes < 1024) return `${bytes}B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`; + return `${(bytes / (1024 * 1024)).toFixed(1)}MB`; +} + +// Backward compatibility alias +export { createDeployment as createTag }; diff --git a/src/commands/functions/createExecution.ts b/src/commands/functions/createExecution.ts index 76e299f..2b9e795 100644 --- a/src/commands/functions/createExecution.ts +++ b/src/commands/functions/createExecution.ts @@ -13,8 +13,12 @@ export async function createExecution(functionTreeItem: FunctionTreeItem): Promi } export async function executeFunction(functionId: string): Promise { + if (!functionsClient) { + return; + } + ext.outputChannel.appendLog(`Creating execution for function with ID: ${functionId}`); - let execution = await functionsClient?.createExecution(functionId); + let execution = await functionsClient.createExecution(functionId); ext.outputChannel.appendLog(JSON.stringify(execution, null, 2)); await ext.tree?.functions?.refresh(); @@ -22,7 +26,7 @@ export async function executeFunction(functionId: string): Promise { return; } - execution = await waitForExecution(execution); + execution = await waitForExecution(functionId, execution); ext.tree?.functions?.refresh(); if (execution === undefined) { @@ -31,7 +35,10 @@ export async function executeFunction(functionId: string): Promise { const failed = execution.status === "failed"; const item = !failed ? "View output" : "View errors"; - const action = await window.showInformationMessage(`Execution ${failed ? "failed" : "completed"} in ${execution.time.toFixed(2)}s.`, item); + const action = await window.showInformationMessage( + `Execution ${failed ? "failed" : "completed"} in ${execution.duration.toFixed(2)}s.`, + item + ); if (action === item) { if (item === "View output") { await viewExecutionOutput(execution); @@ -42,15 +49,16 @@ export async function executeFunction(functionId: string): Promise { } } -async function waitForExecution(execution: Execution | undefined): Promise { +async function waitForExecution(functionId: string, execution: Execution | undefined): Promise { if (execution === undefined) { return; } - if (execution.status === "processing" || execution.status === "waiting") { + // Handle all non-terminal states + if (execution.status === "processing" || execution.status === "waiting" || execution.status === "scheduled") { await sleep(5000); - ext.outputChannel.appendLog("Execution still ..."); - return await waitForExecution(await functionsClient?.getExecution(execution.functionId, execution.$id)); + ext.outputChannel.appendLog(`Execution still ${execution.status}...`); + return await waitForExecution(functionId, await functionsClient?.getExecution(functionId, execution.$id)); } return execution; diff --git a/src/commands/functions/createFunction.ts b/src/commands/functions/createFunction.ts index c90d48c..1f11bb9 100644 --- a/src/commands/functions/createFunction.ts +++ b/src/commands/functions/createFunction.ts @@ -1,19 +1,33 @@ import { window } from 'vscode'; import { functionsClient } from '../../client'; import { appwriteFunctionRuntimes } from '../../constants'; +import { ext } from '../../extensionVariables'; import { validateFunctionName } from '../../tree/functions/settings/NameTreeItem'; export async function createFunction(): Promise { + if (!functionsClient) { + return; + } const name = await window.showInputBox({ prompt: 'Function name', validateInput: validateFunctionName }); if (name === undefined) { return; } - const env: string | undefined = await window.showQuickPick(appwriteFunctionRuntimes); - if (env === undefined) { + const runtime: string | undefined = await window.showQuickPick(appwriteFunctionRuntimes, { + placeHolder: 'Select runtime environment' + }); + if (runtime === undefined) { return; } - await functionsClient?.create(name, [], env); + try { + const func = await functionsClient.create(name, [], runtime); + if (func) { + window.showInformationMessage(`Created function "${name}" with runtime ${runtime}.`); + ext.tree?.functions?.refresh(); + } + } catch (e) { + window.showErrorMessage(e.message || String(e)); + } } diff --git a/src/commands/functions/deleteDeployment.ts b/src/commands/functions/deleteDeployment.ts new file mode 100644 index 0000000..98d81f8 --- /dev/null +++ b/src/commands/functions/deleteDeployment.ts @@ -0,0 +1,30 @@ +import { window } from "vscode"; +import { functionsClient } from "../../client"; +import { DeploymentTreeItem } from "../../tree/functions/deployments/DeploymentTreeItem"; +import { confirmDialog } from "../../ui/confirmDialog"; +import { ext } from "../../extensionVariables"; + +export async function deleteDeployment(deploymentItem: DeploymentTreeItem): Promise { + if (deploymentItem === undefined) { + return; + } + + const func = deploymentItem.parent.parent.func; + const deployment = deploymentItem.deployment; + + try { + const shouldDelete = await confirmDialog( + `Delete deployment "${deployment.$id}" from function "${func.name}"?` + ); + if (shouldDelete) { + await functionsClient?.deleteDeployment(func.$id, deployment.$id); + window.showInformationMessage(`Deleted deployment "${deployment.$id}".`); + ext.tree?.functions?.refresh(); + } + } catch (e) { + window.showErrorMessage(e.message || String(e)); + } +} + +// Backward compatibility alias +export { deleteDeployment as deleteTag }; diff --git a/src/commands/functions/viewExecutionErrors.ts b/src/commands/functions/viewExecutionErrors.ts index 2a79f28..7192227 100644 --- a/src/commands/functions/viewExecutionErrors.ts +++ b/src/commands/functions/viewExecutionErrors.ts @@ -12,5 +12,11 @@ export async function viewExecutionErrors(executionItem: ExecutionTreeItem | Exe if (executionItem instanceof ExecutionTreeItem) { execution = executionItem.execution; } - await openReadOnlyContent({ label: `Execution stderr`, fullId: `${execution.$id}-errors.txt` }, execution.stderr, '.txt'); + + // SDK v21: stderr renamed to errors + await openReadOnlyContent( + { label: `Execution errors`, fullId: `${execution.$id}-errors.txt` }, + execution.errors || '', + '.txt' + ); } diff --git a/src/commands/functions/viewExecutionOutput.ts b/src/commands/functions/viewExecutionOutput.ts index 28088c5..2a41332 100644 --- a/src/commands/functions/viewExecutionOutput.ts +++ b/src/commands/functions/viewExecutionOutput.ts @@ -7,13 +7,16 @@ export async function viewExecutionOutput(executionItem: ExecutionTreeItem | Exe return; } - let execution = executionItem as Execution; if (executionItem instanceof ExecutionTreeItem) { execution = executionItem.execution; } - console.log(execution.dateCreated); - await openReadOnlyContent({ label: `Execution stdout`, fullId: `${execution.$id}-output.txt` }, execution.stdout, '.txt'); + // SDK v21: stdout renamed to logs + await openReadOnlyContent( + { label: `Execution logs`, fullId: `${execution.$id}-logs.txt` }, + execution.logs || '', + '.txt' + ); } diff --git a/src/commands/registerCommands.ts b/src/commands/registerCommands.ts index 4bb1f94..b4bd8de 100644 --- a/src/commands/registerCommands.ts +++ b/src/commands/registerCommands.ts @@ -25,15 +25,15 @@ import { viewUserPrefs } from "./users/viewUserPrefs"; import { editPermission } from "./database/permissions/editPermission"; import { setActiveProject } from "./project/setActiveProject"; import { removeProject } from "./project/removeProject"; -import { createTag } from './functions/createTag'; +import { createDeployment } from './functions/createDeployment'; import { createExecution } from './functions/createExecution'; -import { activateTag } from './functions/activateTag'; +import { activateDeployment } from './functions/activateDeployment'; import { editValue } from './common/editValue'; import { deleteFunction } from './functions/deleteFunction'; import { createFunction } from './functions/createFunction'; import { createFunctionVar } from './functions/createFunctionVar'; import { deleteFunctionVar } from './functions/deleteFunctionVar'; -import { deleteTag } from './functions/deleteTag'; +import { deleteDeployment } from './functions/deleteDeployment'; import { viewExecutionErrors } from './functions/viewExecutionErrors'; import { viewExecutionOutput } from './functions/viewExecutionOutput'; import { copyExecutionErrors } from './functions/copyExecutionErrors'; @@ -124,9 +124,14 @@ export function registerCommands(context: ExtensionContext): void { /** Functions **/ registerCommand("refreshFunctions", undefined, "functions"); registerCommand("CreateExecution", createExecution, "functions"); - registerCommand("CreateTag", createTag, "functions"); - registerCommand("activateTag", activateTag, "functions"); - registerCommand("deleteTag", deleteTag, "functions"); + // Deployment commands (replaces Tag commands) + registerCommand("CreateDeployment", createDeployment, "functions"); + registerCommand("activateDeployment", activateDeployment, "functions"); + registerCommand("deleteDeployment", deleteDeployment, "functions"); + // Backward compatibility aliases for Tag commands + registerCommand("CreateTag", createDeployment, "functions"); + registerCommand("activateTag", activateDeployment, "functions"); + registerCommand("deleteTag", deleteDeployment, "functions"); registerCommand("deleteFunction", deleteFunction, "functions"); registerCommand("openFunctionsDocumentation", () => openDocumentation("functions")); registerCommand("createFunction", createFunction, "functions"); From 9500767255d81e21ccf50ced2a99f13d9f1c549c Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Fri, 23 Jan 2026 17:41:39 +0100 Subject: [PATCH 09/14] fix: resolve TypeScript compilation errors and remove legacy code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix Set spread using Array.from() in Database.ts - Fix LogList→LogsList import typo in Users.ts - Update AppwriteCall to accept void promises for delete operations - Update msToDate to handle ISO date strings (SDK v21+) - Replace Rules with Attributes (createAttribute, deleteAttribute) - Remove legacy tag files (replaced by deployments in previous commit) - Update permission commands for new flat array format - Update variable management in VarTreeItem - Update UserTreeItemProvider for SDK v21 Co-Authored-By: Claude Opus 4.5 --- package-lock.json | 3308 +++++++++++------ src/appwrite/Database.ts | 2 +- src/appwrite/Users.ts | 4 +- src/commands/database/createAttribute.ts | 102 + src/commands/database/createRule.ts | 27 - src/commands/database/deleteAttribute.ts | 35 + .../database/permissions/createPermission.ts | 108 +- .../database/permissions/deletePermission.ts | 35 +- .../database/permissions/editPermission.ts | 36 +- src/commands/database/removeRule.ts | 13 - src/commands/functions/activateTag.ts | 8 - src/commands/functions/createFunctionVar.ts | 15 +- src/commands/functions/createTag.ts | 164 - src/commands/functions/deleteFunctionVar.ts | 27 +- src/commands/functions/deleteTag.ts | 11 - src/commands/registerCommands.ts | 12 +- src/tree/database/settings/RuleTreeItem.ts | 10 - src/tree/database/settings/RulesTreeItem.ts | 34 - src/tree/functions/settings/VarTreeItem.ts | 43 +- src/tree/functions/tags/TagTreeItem.ts | 17 - src/tree/functions/tags/TagsTreeItem.ts | 40 - src/tree/users/UserTreeItemProvider.ts | 19 +- src/utils/AppwriteCall.ts | 2 +- src/utils/date.ts | 13 +- 24 files changed, 2567 insertions(+), 1518 deletions(-) create mode 100644 src/commands/database/createAttribute.ts delete mode 100644 src/commands/database/createRule.ts create mode 100644 src/commands/database/deleteAttribute.ts delete mode 100644 src/commands/database/removeRule.ts delete mode 100644 src/commands/functions/activateTag.ts delete mode 100644 src/commands/functions/createTag.ts delete mode 100644 src/commands/functions/deleteTag.ts delete mode 100644 src/tree/database/settings/RuleTreeItem.ts delete mode 100644 src/tree/database/settings/RulesTreeItem.ts delete mode 100644 src/tree/functions/tags/TagTreeItem.ts delete mode 100644 src/tree/functions/tags/TagsTreeItem.ts diff --git a/package-lock.json b/package-lock.json index 2484cf5..cc233b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,113 +1,164 @@ { "name": "vscode-appwrite", - "version": "0.0.9", - "lockfileVersion": 1, + "version": "0.1.3", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@babel/code-frame": { + "packages": { + "": { + "name": "vscode-appwrite", + "version": "0.1.3", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "cron-validate": "^1.4.3", + "cronstrue": "^1.113.0", + "dayjs": "^1.10.4", + "fs-extra": "^9.1.0", + "node-appwrite": "^21.1.0", + "tar": "^6.1.0" + }, + "devDependencies": { + "@types/fs-extra": "^9.0.11", + "@types/glob": "^7.1.3", + "@types/mocha": "^8.0.4", + "@types/node": "^12.11.7", + "@types/tar": "^4.0.4", + "@types/vscode": "^1.55.0", + "@typescript-eslint/eslint-plugin": "^4.14.1", + "@typescript-eslint/parser": "^4.14.1", + "eslint": "^7.19.0", + "glob": "^7.1.6", + "mocha": "^8.2.1", + "ts-loader": "^8.0.14", + "typescript": "^4.1.3", + "vsce": "^1.88.0", + "vscode-test": "^1.5.0", + "webpack": "^5.19.0", + "webpack-cli": "^4.4.0" + }, + "engines": { + "vscode": "^1.55.0" + } + }, + "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, - "requires": { + "dependencies": { "@babel/highlight": "^7.10.4" } }, - "@babel/helper-validator-identifier": { + "node_modules/@babel/helper-validator-identifier": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", "dev": true }, - "@babel/highlight": { + "node_modules/@babel/highlight": { "version": "7.13.10", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-validator-identifier": "^7.12.11", "chalk": "^2.0.0", "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "@babel/runtime": { + "node_modules/@babel/runtime": { "version": "7.14.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "requires": { + "dependencies": { "regenerator-runtime": "^0.13.4" } }, - "@discoveryjs/json-ext": { + "node_modules/@discoveryjs/json-ext": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz", "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==", - "dev": true + "dev": true, + "engines": { + "node": ">=10.0.0" + } }, - "@eslint/eslintrc": { + "node_modules/@eslint/eslintrc": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", "dev": true, - "requires": { + "dependencies": { "ajv": "^6.12.4", "debug": "^4.1.1", "espree": "^7.3.0", @@ -118,161 +169,183 @@ "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, "dependencies": { - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@nodelib/fs.scandir": { + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@nodelib/fs.scandir": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", "dev": true, - "requires": { + "dependencies": { "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" } }, - "@nodelib/fs.stat": { + "node_modules/@nodelib/fs.stat": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", - "dev": true + "dev": true, + "engines": { + "node": ">= 8" + } }, - "@nodelib/fs.walk": { + "node_modules/@nodelib/fs.walk": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", "dev": true, - "requires": { + "dependencies": { "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" } }, - "@tootallnate/once": { + "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true + "dev": true, + "engines": { + "node": ">= 6" + } }, - "@types/eslint": { + "node_modules/@types/eslint": { "version": "7.2.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.10.tgz", "integrity": "sha512-kUEPnMKrqbtpCq/KTaGFFKAcz6Ethm2EjCoKIDaCmfRBWLbFuTcOJfTlorwbnboXBzahqWLgUp1BQeKHiJzPUQ==", "dev": true, - "requires": { + "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, - "@types/eslint-scope": { + "node_modules/@types/eslint-scope": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", "dev": true, - "requires": { + "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, - "@types/estree": { + "node_modules/@types/estree": { "version": "0.0.46", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==", "dev": true }, - "@types/fs-extra": { + "node_modules/@types/fs-extra": { "version": "9.0.11", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz", "integrity": "sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*" } }, - "@types/glob": { + "node_modules/@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", "dev": true, - "requires": { + "dependencies": { "@types/minimatch": "*", "@types/node": "*" } }, - "@types/json-schema": { + "node_modules/@types/json-schema": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", "dev": true }, - "@types/lodash": { + "node_modules/@types/lodash": { "version": "4.14.170", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.170.tgz", "integrity": "sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q==" }, - "@types/minimatch": { + "node_modules/@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", "dev": true }, - "@types/minipass": { + "node_modules/@types/minipass": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@types/minipass/-/minipass-2.2.0.tgz", "integrity": "sha512-wuzZksN4w4kyfoOv/dlpov4NOunwutLA/q7uc00xU02ZyUY+aoM5PWIXEKBMnm0NHd4a+N71BMjq+x7+2Af1fg==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*" } }, - "@types/mocha": { + "node_modules/@types/mocha": { "version": "8.2.2", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.2.tgz", "integrity": "sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==", "dev": true }, - "@types/node": { + "node_modules/@types/node": { "version": "12.20.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.10.tgz", "integrity": "sha512-TxCmnSSppKBBOzYzPR2BR25YlX5Oay8z2XGwFBInuA/Co0V9xJhLlW4kjbxKtgeNo3NOMbQP1A5Rc03y+XecPw==", "dev": true }, - "@types/tar": { + "node_modules/@types/tar": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/tar/-/tar-4.0.4.tgz", "integrity": "sha512-0Xv+xcmkTsOZdIF4yCnd7RkOOyfyqPaqJ7RZFKnwdxfDbkN3eAAE9sHl8zJFqBz4VhxolW9EErbjR1oyH7jK2A==", "dev": true, - "requires": { + "dependencies": { "@types/minipass": "*", "@types/node": "*" } }, - "@types/vscode": { + "node_modules/@types/vscode": { "version": "1.55.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.55.0.tgz", "integrity": "sha512-49hysH7jneTQoSC8TWbAi7nKK9Lc5osQNjmDHVosrcU8o3jecD9GrK0Qyul8q4aGPSXRfNGqIp9CBdb13akETg==", "dev": true }, - "@typescript-eslint/eslint-plugin": { + "node_modules/@typescript-eslint/eslint-plugin": { "version": "4.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz", "integrity": "sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/experimental-utils": "4.22.0", "@typescript-eslint/scope-manager": "4.22.0", "debug": "^4.1.1", @@ -281,56 +354,111 @@ "regexpp": "^3.0.0", "semver": "^7.3.2", "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "@typescript-eslint/experimental-utils": { + "node_modules/@typescript-eslint/experimental-utils": { "version": "4.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz", "integrity": "sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==", "dev": true, - "requires": { + "dependencies": { "@types/json-schema": "^7.0.3", "@typescript-eslint/scope-manager": "4.22.0", "@typescript-eslint/types": "4.22.0", "@typescript-eslint/typescript-estree": "4.22.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" } }, - "@typescript-eslint/parser": { + "node_modules/@typescript-eslint/parser": { "version": "4.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.0.tgz", "integrity": "sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/scope-manager": "4.22.0", "@typescript-eslint/types": "4.22.0", "@typescript-eslint/typescript-estree": "4.22.0", "debug": "^4.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "@typescript-eslint/scope-manager": { + "node_modules/@typescript-eslint/scope-manager": { "version": "4.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz", "integrity": "sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/types": "4.22.0", "@typescript-eslint/visitor-keys": "4.22.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "@typescript-eslint/types": { + "node_modules/@typescript-eslint/types": { "version": "4.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.0.tgz", "integrity": "sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==", - "dev": true + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } }, - "@typescript-eslint/typescript-estree": { + "node_modules/@typescript-eslint/typescript-estree": { "version": "4.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz", "integrity": "sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/types": "4.22.0", "@typescript-eslint/visitor-keys": "4.22.0", "debug": "^4.1.1", @@ -338,111 +466,130 @@ "is-glob": "^4.0.1", "semver": "^7.3.2", "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "@typescript-eslint/visitor-keys": { + "node_modules/@typescript-eslint/visitor-keys": { "version": "4.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz", "integrity": "sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/types": "4.22.0", "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "@ungap/promise-all-settled": { + "node_modules/@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, - "@webassemblyjs/ast": { + "node_modules/@webassemblyjs/ast": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", "dev": true, - "requires": { + "dependencies": { "@webassemblyjs/helper-numbers": "1.11.0", "@webassemblyjs/helper-wasm-bytecode": "1.11.0" } }, - "@webassemblyjs/floating-point-hex-parser": { + "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", "dev": true }, - "@webassemblyjs/helper-api-error": { + "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", "dev": true }, - "@webassemblyjs/helper-buffer": { + "node_modules/@webassemblyjs/helper-buffer": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", "dev": true }, - "@webassemblyjs/helper-numbers": { + "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", "dev": true, - "requires": { + "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.0", "@webassemblyjs/helper-api-error": "1.11.0", "@xtuc/long": "4.2.2" } }, - "@webassemblyjs/helper-wasm-bytecode": { + "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", "dev": true }, - "@webassemblyjs/helper-wasm-section": { + "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", "dev": true, - "requires": { + "dependencies": { "@webassemblyjs/ast": "1.11.0", "@webassemblyjs/helper-buffer": "1.11.0", "@webassemblyjs/helper-wasm-bytecode": "1.11.0", "@webassemblyjs/wasm-gen": "1.11.0" } }, - "@webassemblyjs/ieee754": { + "node_modules/@webassemblyjs/ieee754": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", "dev": true, - "requires": { + "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, - "@webassemblyjs/leb128": { + "node_modules/@webassemblyjs/leb128": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", "dev": true, - "requires": { + "dependencies": { "@xtuc/long": "4.2.2" } }, - "@webassemblyjs/utf8": { + "node_modules/@webassemblyjs/utf8": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", "dev": true }, - "@webassemblyjs/wasm-edit": { + "node_modules/@webassemblyjs/wasm-edit": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", "dev": true, - "requires": { + "dependencies": { "@webassemblyjs/ast": "1.11.0", "@webassemblyjs/helper-buffer": "1.11.0", "@webassemblyjs/helper-wasm-bytecode": "1.11.0", @@ -453,12 +600,12 @@ "@webassemblyjs/wast-printer": "1.11.0" } }, - "@webassemblyjs/wasm-gen": { + "node_modules/@webassemblyjs/wasm-gen": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", "dev": true, - "requires": { + "dependencies": { "@webassemblyjs/ast": "1.11.0", "@webassemblyjs/helper-wasm-bytecode": "1.11.0", "@webassemblyjs/ieee754": "1.11.0", @@ -466,24 +613,24 @@ "@webassemblyjs/utf8": "1.11.0" } }, - "@webassemblyjs/wasm-opt": { + "node_modules/@webassemblyjs/wasm-opt": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", "dev": true, - "requires": { + "dependencies": { "@webassemblyjs/ast": "1.11.0", "@webassemblyjs/helper-buffer": "1.11.0", "@webassemblyjs/wasm-gen": "1.11.0", "@webassemblyjs/wasm-parser": "1.11.0" } }, - "@webassemblyjs/wasm-parser": { + "node_modules/@webassemblyjs/wasm-parser": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", "dev": true, - "requires": { + "dependencies": { "@webassemblyjs/ast": "1.11.0", "@webassemblyjs/helper-api-error": "1.11.0", "@webassemblyjs/helper-wasm-bytecode": "1.11.0", @@ -492,337 +639,439 @@ "@webassemblyjs/utf8": "1.11.0" } }, - "@webassemblyjs/wast-printer": { + "node_modules/@webassemblyjs/wast-printer": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", "dev": true, - "requires": { + "dependencies": { "@webassemblyjs/ast": "1.11.0", "@xtuc/long": "4.2.2" } }, - "@webpack-cli/configtest": { + "node_modules/@webpack-cli/configtest": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.2.tgz", "integrity": "sha512-3OBzV2fBGZ5TBfdW50cha1lHDVf9vlvRXnjpVbJBa20pSZQaSkMJZiwA8V2vD9ogyeXn8nU5s5A6mHyf5jhMzA==", - "dev": true + "dev": true, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } }, - "@webpack-cli/info": { + "node_modules/@webpack-cli/info": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.3.tgz", "integrity": "sha512-lLek3/T7u40lTqzCGpC6CAbY6+vXhdhmwFRxZLMnRm6/sIF/7qMpT8MocXCRQfz0JAh63wpbXLMnsQ5162WS7Q==", "dev": true, - "requires": { + "dependencies": { "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" } }, - "@webpack-cli/serve": { + "node_modules/@webpack-cli/serve": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.3.1.tgz", "integrity": "sha512-0qXvpeYO6vaNoRBI52/UsbcaBydJCggoBBnIo/ovQQdn6fug0BgwsjorV1hVS7fMqGVTZGcVxv8334gjmbj5hw==", - "dev": true + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } }, - "@xtuc/ieee754": { + "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", "dev": true }, - "@xtuc/long": { + "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, - "acorn": { + "node_modules/acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } }, - "acorn-jsx": { + "node_modules/acorn-jsx": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "agent-base": { + "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, - "requires": { + "dependencies": { "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" } }, - "ajv": { + "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "requires": { + "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "ajv-keywords": { + "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } }, - "ansi-colors": { + "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "ansi-regex": { + "node_modules/ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "ansi-styles": { + "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "requires": { + "dependencies": { "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "anymatch": { + "node_modules/anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, - "requires": { + "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "argparse": { + "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "requires": { + "dependencies": { "sprintf-js": "~1.0.2" } }, - "array-union": { + "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "astral-regex": { + "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "dev": true, + "engines": { + "node": ">=8" + } }, - "at-least-node": { + "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, - "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", - "requires": { - "follow-redirects": "^1.10.0" + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" } }, - "azure-devops-node-api": { + "node_modules/azure-devops-node-api": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-10.2.2.tgz", "integrity": "sha512-4TVv2X7oNStT0vLaEfExmy3J4/CzfuXolEcQl/BRUmvGySqKStTG2O55/hUQ0kM7UJlZBLgniM0SBq4d/WkKow==", "dev": true, - "requires": { + "dependencies": { "tunnel": "0.0.6", "typed-rest-client": "^1.8.4" } }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "big-integer": { + "node_modules/big-integer": { "version": "1.6.48", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.6" + } }, - "big.js": { + "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true + "dev": true, + "engines": { + "node": "*" + } }, - "binary": { + "node_modules/binary": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", "dev": true, - "requires": { + "dependencies": { "buffers": "~0.1.1", "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" } }, - "binary-extensions": { + "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "bluebird": { + "node_modules/bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", "dev": true }, - "boolbase": { + "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, - "brace-expansion": { + "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "requires": { + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "braces": { + "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, - "requires": { + "dependencies": { "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" } }, - "browser-stdout": { + "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "browserslist": { + "node_modules/browserslist": { "version": "4.16.6", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", "dev": true, - "requires": { + "dependencies": { "caniuse-lite": "^1.0.30001219", "colorette": "^1.2.2", "electron-to-chromium": "^1.3.723", "escalade": "^3.1.1", "node-releases": "^1.1.71" }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001230", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz", - "integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.742", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.742.tgz", - "integrity": "sha512-ihL14knI9FikJmH2XUIDdZFWJxvr14rPSdOhJ7PpS27xbz8qmaRwCwyg/bmFwjWKmWK9QyamiCZVCvXm5CH//Q==", - "dev": true - } + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/browserslist/node_modules/caniuse-lite": { + "version": "1.0.30001230", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz", + "integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" } }, - "buffer-crc32": { + "node_modules/browserslist/node_modules/electron-to-chromium": { + "version": "1.3.742", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.742.tgz", + "integrity": "sha512-ihL14knI9FikJmH2XUIDdZFWJxvr14rPSdOhJ7PpS27xbz8qmaRwCwyg/bmFwjWKmWK9QyamiCZVCvXm5CH//Q==", + "dev": true + }, + "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true + "dev": true, + "engines": { + "node": "*" + } }, - "buffer-from": { + "node_modules/buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, - "buffer-indexof-polyfill": { + "node_modules/buffer-indexof-polyfill": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10" + } }, - "buffers": { + "node_modules/buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.2.0" + } }, - "call-bind": { + "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, - "requires": { + "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "callsites": { + "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "camelcase": { + "node_modules/camelcase": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "chainsaw": { + "node_modules/chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", "dev": true, - "requires": { + "dependencies": { "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" } }, - "chalk": { + "node_modules/chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, - "requires": { + "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "cheerio": { + "node_modules/cheerio": { "version": "1.0.0-rc.9", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.9.tgz", "integrity": "sha512-QF6XVdrLONO6DXRF5iaolY+odmhj2CLj+xzNod7INPWMi/x9X4SOylH0S/vaPpX+AUU6t04s34SQNh7DbkuCng==", "dev": true, - "requires": { + "dependencies": { "cheerio-select": "^1.4.0", "dom-serializer": "^1.3.1", "domhandler": "^4.2.0", @@ -831,351 +1080,446 @@ "parse5-htmlparser2-tree-adapter": "^6.0.1", "tslib": "^2.2.0" }, - "dependencies": { - "tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", - "dev": true - } + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" } }, - "cheerio-select": { + "node_modules/cheerio-select": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.4.0.tgz", "integrity": "sha512-sobR3Yqz27L553Qa7cK6rtJlMDbiKPdNywtR95Sj/YgfpLfy0u6CGJuaBKe5YE/vTc23SCRKxWSdlon/w6I/Ew==", "dev": true, - "requires": { + "dependencies": { "css-select": "^4.1.2", "css-what": "^5.0.0", "domelementtype": "^2.2.0", "domhandler": "^4.2.0", "domutils": "^2.6.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "chokidar": { + "node_modules/cheerio/node_modules/tslib": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", + "dev": true + }, + "node_modules/chokidar": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", "dev": true, - "requires": { + "dependencies": { "anymatch": "~3.1.1", "braces": "~3.0.2", - "fsevents": "~2.3.1", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.5.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.1" } }, - "chownr": { + "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } }, - "chrome-trace-event": { + "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.0" + } }, - "cliui": { + "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, - "requires": { + "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, - "clone-deep": { + "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, - "requires": { + "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "color-convert": { + "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "requires": { + "dependencies": { "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "color-name": { + "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "colorette": { + "node_modules/colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", "dev": true }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { + "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "concat-map": { + "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "core-util-is": { + "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, - "cron-validate": { + "node_modules/cron-validate": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/cron-validate/-/cron-validate-1.4.3.tgz", "integrity": "sha512-N+qKw019oQBEPIP5Qwi8Z5XelQ00ThN6Maahwv+9UGu2u/b/MPb35zngMQI0T8pBoNiBrIXGlhvsmspNSYae/w==", - "requires": { + "dependencies": { "yup": "0.32.9" } }, - "cronstrue": { + "node_modules/cronstrue": { "version": "1.113.0", "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-1.113.0.tgz", "integrity": "sha512-j0+CQsQx0g0Iv6nQs0bHkLcpeCzYShWUdQ3QwSHV+dUyTLqI/3NPrHceeDfTXmC3Re4osMli5+wAYpffNO+e9w==" }, - "cross-spawn": { + "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, - "requires": { + "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "css-select": { + "node_modules/css-select": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.2.tgz", "integrity": "sha512-nu5ye2Hg/4ISq4XqdLY2bEatAcLIdt3OYGFc9Tm9n7VSlFBcfRv0gBNksHRgSdUDQGtN3XrZ94ztW+NfzkFSUw==", "dev": true, - "requires": { + "dependencies": { "boolbase": "^1.0.0", "css-what": "^5.0.0", "domhandler": "^4.2.0", "domutils": "^2.6.0", "nth-check": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "css-what": { + "node_modules/css-what": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.0.tgz", "integrity": "sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA==", - "dev": true + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } }, - "dayjs": { + "node_modules/dayjs": { "version": "1.10.4", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz", "integrity": "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw==" }, - "debug": { + "node_modules/debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, - "requires": { + "dependencies": { "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "decamelize": { + "node_modules/decamelize": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "deep-is": { + "node_modules/deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "denodeify": { + "node_modules/denodeify": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", "dev": true }, - "diff": { + "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.3.1" + } }, - "dir-glob": { + "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "requires": { + "dependencies": { "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "doctrine": { + "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "requires": { + "dependencies": { "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" } }, - "dom-serializer": { + "node_modules/dom-serializer": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.1.tgz", "integrity": "sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==", "dev": true, - "requires": { + "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "domelementtype": { + "node_modules/domelementtype": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] }, - "domhandler": { + "node_modules/domhandler": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", "dev": true, - "requires": { + "dependencies": { "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "domutils": { + "node_modules/domutils": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.6.0.tgz", "integrity": "sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==", "dev": true, - "requires": { + "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "duplexer2": { + "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, - "requires": { + "dependencies": { "readable-stream": "^2.0.2" } }, - "emoji-regex": { + "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "emojis-list": { + "node_modules/emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true + "dev": true, + "engines": { + "node": ">= 4" + } }, - "enhanced-resolve": { + "node_modules/enhanced-resolve": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", "dev": true, - "requires": { + "dependencies": { "graceful-fs": "^4.1.2", "memory-fs": "^0.5.0", "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "enquirer": { + "node_modules/enquirer": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, - "requires": { + "dependencies": { "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" } }, - "entities": { + "node_modules/entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, - "envinfo": { + "node_modules/envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } }, - "errno": { + "node_modules/errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, - "requires": { + "dependencies": { "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" } }, - "es-module-lexer": { + "node_modules/es-module-lexer": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", "integrity": "sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==", "dev": true }, - "escalade": { + "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "escape-string-regexp": { + "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "eslint": { + "node_modules/eslint": { "version": "7.24.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.24.0.tgz", "integrity": "sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, - "requires": { + "dependencies": { "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.4.0", "ajv": "^6.10.0", @@ -1213,124 +1557,174 @@ "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "eslint-scope": { + "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "requires": { + "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" } }, - "eslint-utils": { + "node_modules/eslint-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, - "requires": { + "dependencies": { "eslint-visitor-keys": "^1.1.0" }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "eslint-visitor-keys": { + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + } }, - "espree": { + "node_modules/espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, - "requires": { + "dependencies": { "acorn": "^7.4.0", "acorn-jsx": "^5.3.1", "eslint-visitor-keys": "^1.3.0" }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" } }, - "esprima": { + "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } }, - "esquery": { + "node_modules/esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, - "requires": { + "dependencies": { "estraverse": "^5.1.0" }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" } }, - "esrecurse": { + "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "requires": { + "dependencies": { "estraverse": "^5.2.0" }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" } }, - "estraverse": { + "node_modules/estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true + "dev": true, + "engines": { + "node": ">=4.0" + } }, - "esutils": { + "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "events": { + "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.8.x" + } }, - "execa": { + "node_modules/execa": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", "dev": true, - "requires": { + "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", @@ -1340,263 +1734,322 @@ "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "fast-deep-equal": { + "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-glob": { + "node_modules/fast-glob": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", "dev": true, - "requires": { + "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.0", "merge2": "^1.3.0", "micromatch": "^4.0.2", "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" } }, - "fast-json-stable-stringify": { + "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "fast-levenshtein": { + "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fastest-levenshtein": { + "node_modules/fastest-levenshtein": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", "dev": true }, - "fastq": { + "node_modules/fastq": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", "dev": true, - "requires": { + "dependencies": { "reusify": "^1.0.4" } }, - "fd-slicer": { + "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, - "requires": { + "dependencies": { "pend": "~1.2.0" } }, - "file-entry-cache": { + "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "requires": { + "dependencies": { "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, - "fill-range": { + "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, - "requires": { + "dependencies": { "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "find-up": { + "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, - "requires": { + "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "flat": { + "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true + "dev": true, + "bin": { + "flat": "cli.js" + } }, - "flat-cache": { + "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, - "requires": { + "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, - "flatted": { + "node_modules/flatted": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, - "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "fs-extra": { + "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "requires": { + "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "fs-minipass": { + "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { + "dependencies": { "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" } }, - "fs.realpath": { + "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { + "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, - "optional": true + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "fstream": { + "node_modules/fstream": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", "dev": true, - "requires": { + "dependencies": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", "mkdirp": ">=0.5 0", "rimraf": "2" }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" } }, - "function-bind": { + "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "functional-red-black-tree": { + "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, - "get-caller-file": { + "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } }, - "get-intrinsic": { + "node_modules/get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, - "requires": { + "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "get-stream": { + "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "glob": { + "node_modules/glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, - "requires": { + "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "glob-parent": { + "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "requires": { + "dependencies": { "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "glob-to-regexp": { + "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "globals": { + "node_modules/globals": { "version": "13.8.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz", "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==", "dev": true, - "requires": { + "dependencies": { "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "globby": { + "node_modules/globby": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", "dev": true, - "requires": { + "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.1.1", @@ -1604,554 +2057,745 @@ "merge2": "^1.3.0", "slash": "^3.0.0" }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - } + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" } }, - "graceful-fs": { + "node_modules/graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" }, - "growl": { + "node_modules/growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true + "dev": true, + "engines": { + "node": ">=4.x" + } }, - "has": { + "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, - "requires": { + "dependencies": { "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" } }, - "has-flag": { + "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "has-symbols": { + "node_modules/has-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "he": { + "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true + "dev": true, + "bin": { + "he": "bin/he" + } }, - "htmlparser2": { + "node_modules/htmlparser2": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", "dev": true, - "requires": { + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", "domutils": "^2.5.2", "entities": "^2.0.0" } }, - "http-proxy-agent": { + "node_modules/http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "dev": true, - "requires": { + "dependencies": { "@tootallnate/once": "1", "agent-base": "6", "debug": "4" + }, + "engines": { + "node": ">= 6" } }, - "https-proxy-agent": { + "node_modules/https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "dev": true, - "requires": { + "dependencies": { "agent-base": "6", "debug": "4" + }, + "engines": { + "node": ">= 6" } }, - "human-signals": { + "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true + "dev": true, + "engines": { + "node": ">=10.17.0" + } }, - "ignore": { + "node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true + "dev": true, + "engines": { + "node": ">= 4" + } }, - "import-fresh": { + "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, - "requires": { + "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "import-local": { + "node_modules/import-local": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", "dev": true, - "requires": { + "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" } }, - "imurmurhash": { + "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.8.19" + } }, - "inflight": { + "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, - "requires": { + "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "inherits": { + "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "interpret": { + "node_modules/interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.10" + } }, - "is-binary-path": { + "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "requires": { + "dependencies": { "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "is-boolean-object": { + "node_modules/is-boolean-object": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", "dev": true, - "requires": { + "dependencies": { "call-bind": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-core-module": { + "node_modules/is-core-module": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", "dev": true, - "requires": { + "dependencies": { "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-extglob": { + "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "is-fullwidth-code-point": { + "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "is-glob": { + "node_modules/is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, - "requires": { + "dependencies": { "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-number": { + "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.12.0" + } }, - "is-number-object": { + "node_modules/is-number-object": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-plain-obj": { + "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "is-plain-object": { + "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, - "requires": { + "dependencies": { "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-stream": { + "node_modules/is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "is-string": { + "node_modules/is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "isarray": { + "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "isexe": { + "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isobject": { + "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "jest-worker": { + "node_modules/jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "js-tokens": { + "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "js-yaml": { + "node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "requires": { + "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "json-parse-better-errors": { + "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, - "json-schema-traverse": { + "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "json-stable-stringify-without-jsonify": { + "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "json5": { + "node_modules/json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, - "requires": { + "dependencies": { "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "jsonfile": { + "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", + "dependencies": { "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "kind-of": { + "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "leven": { + "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "levn": { + "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "requires": { + "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "linkify-it": { + "node_modules/linkify-it": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "dev": true, - "requires": { + "dependencies": { "uc.micro": "^1.0.1" } }, - "listenercount": { + "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", "dev": true }, - "loader-runner": { + "node_modules/loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.11.5" + } }, - "loader-utils": { + "node_modules/loader-utils": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", "dev": true, - "requires": { + "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" } }, - "locate-path": { + "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "requires": { + "dependencies": { "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "lodash": { + "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash-es": { + "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, - "lodash.clonedeep": { + "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, - "lodash.flatten": { + "node_modules/lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", "dev": true }, - "lodash.truncate": { + "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, - "log-symbols": { + "node_modules/log-symbols": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, - "requires": { + "dependencies": { "chalk": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "lru-cache": { + "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "requires": { + "dependencies": { "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "markdown-it": { + "node_modules/markdown-it": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", "dev": true, - "requires": { + "dependencies": { "argparse": "^1.0.7", "entities": "~2.0.0", "linkify-it": "^2.0.0", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" }, - "dependencies": { - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true - } + "bin": { + "markdown-it": "bin/markdown-it.js" } }, - "mdurl": { - "version": "1.0.1", + "node_modules/markdown-it/node_modules/entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "dev": true + }, + "node_modules/mdurl": { + "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", "dev": true }, - "memory-fs": { + "node_modules/memory-fs": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "dev": true, - "requires": { + "dependencies": { "errno": "^0.1.3", "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" } }, - "merge-stream": { + "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, - "merge2": { + "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true + "dev": true, + "engines": { + "node": ">= 8" + } }, - "micromatch": { + "node_modules/micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, - "requires": { + "dependencies": { "braces": "^3.0.1", "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" } }, - "mime": { + "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } }, - "mime-db": { + "node_modules/mime-db": { "version": "1.47.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==" + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "mime-types": { + "node_modules/mime-types": { "version": "2.1.30", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", - "requires": { + "dev": true, + "dependencies": { "mime-db": "1.47.0" + }, + "engines": { + "node": ">= 0.6" } }, - "mimic-fn": { + "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "minimatch": { + "node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "requires": { + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { + "node_modules/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, - "minipass": { + "node_modules/minipass": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", - "requires": { + "dependencies": { "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "minizlib": { + "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { + "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" } }, - "mkdirp": { + "node_modules/mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, - "requires": { + "dependencies": { "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" } }, - "mocha": { + "node_modules/mocha": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.2.tgz", "integrity": "sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg==", "dev": true, - "requires": { + "dependencies": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", @@ -2178,402 +2822,545 @@ "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "ms": { + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "mute-stream": { + "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "nanoclone": { + "node_modules/nanoclone": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==" }, - "nanoid": { + "node_modules/nanoid": { "version": "3.1.20", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", - "dev": true + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } }, - "natural-compare": { + "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "neo-async": { + "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node-appwrite": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-2.2.3.tgz", - "integrity": "sha512-2j7AIKUxbjN25QrqZfMBRuWVRYlB5fixmW0HF/XP5QnrttCfozjPa5wWrgVRrJLYCoqwe2wwgWc9S3fyZeP/0g==", - "requires": { - "axios": "^0.21.1", - "form-data": "^4.0.0" + "node_modules/node-appwrite": { + "version": "21.1.0", + "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-21.1.0.tgz", + "integrity": "sha512-HRK5BzN19vgvaH/EeNsigK24t4ngJ1AoiltK5JtahxP6uyMRztzkD8cXP+z9jj/xOjz7ySfQ9YypNyhNr6zVkA==", + "license": "BSD-3-Clause", + "dependencies": { + "node-fetch-native-with-agent": "1.7.2" } }, - "node-releases": { + "node_modules/node-fetch-native-with-agent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz", + "integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g==", + "license": "MIT" + }, + "node_modules/node-releases": { "version": "1.1.71", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", "dev": true }, - "normalize-path": { + "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "npm-run-path": { + "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, - "requires": { + "dependencies": { "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "nth-check": { + "node_modules/nth-check": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", "dev": true, - "requires": { + "dependencies": { "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "object-inspect": { + "node_modules/object-inspect": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", - "dev": true + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "once": { + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "requires": { + "dependencies": { "wrappy": "1" } }, - "onetime": { + "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, - "requires": { + "dependencies": { "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "optionator": { + "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, - "requires": { + "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" } }, - "os-homedir": { + "node_modules/os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "os-tmpdir": { + "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "osenv": { + "node_modules/osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "deprecated": "This package is no longer supported.", "dev": true, - "requires": { + "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" } }, - "p-limit": { + "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "requires": { + "dependencies": { "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-locate": { + "node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "requires": { + "dependencies": { "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-try": { + "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "parent-module": { + "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "requires": { + "dependencies": { "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "parse-semver": { + "node_modules/parse-semver": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", "dev": true, - "requires": { - "semver": "^5.1.0" - }, "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "semver": "^5.1.0" } }, - "parse5": { + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, - "parse5-htmlparser2-tree-adapter": { + "node_modules/parse5-htmlparser2-tree-adapter": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", "dev": true, - "requires": { + "dependencies": { "parse5": "^6.0.1" } }, - "path-exists": { + "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-key": { + "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "path-parse": { + "node_modules/path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, - "path-type": { + "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "pend": { + "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, - "picomatch": { + "node_modules/picomatch": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", - "dev": true + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "pkg-dir": { + "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, - "requires": { + "dependencies": { "find-up": "^4.0.0" }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" } }, - "prelude-ls": { + "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "process-nextick-args": { + "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "progress": { + "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4.0" + } }, - "property-expr": { + "node_modules/property-expr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz", "integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==" }, - "prr": { + "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", "dev": true }, - "punycode": { + "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "qs": { + "node_modules/qs": { "version": "6.10.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", "dev": true, - "requires": { + "dependencies": { "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "queue-microtask": { + "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "randombytes": { + "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, - "requires": { + "dependencies": { "safe-buffer": "^5.1.0" } }, - "read": { + "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", "dev": true, - "requires": { + "dependencies": { "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" } }, - "readable-stream": { + "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, - "requires": { + "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", @@ -2581,305 +3368,423 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, - "readdirp": { + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/readdirp": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", "dev": true, - "requires": { + "dependencies": { "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "rechoir": { + "node_modules/rechoir": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", "dev": true, - "requires": { + "dependencies": { "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" } }, - "regenerator-runtime": { + "node_modules/regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, - "regexpp": { + "node_modules/regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } }, - "require-directory": { + "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "require-from-string": { + "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "resolve": { + "node_modules/resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, - "requires": { + "dependencies": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "resolve-cwd": { + "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, - "requires": { + "dependencies": { "resolve-from": "^5.0.0" }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" } }, - "resolve-from": { + "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "reusify": { + "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } }, - "rimraf": { + "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "requires": { + "dependencies": { "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "run-parallel": { + "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, - "requires": { + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { "queue-microtask": "^1.2.2" } }, - "safe-buffer": { + "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "schema-utils": { + "node_modules/schema-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", "dev": true, - "requires": { + "dependencies": { "@types/json-schema": "^7.0.6", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "semver": { + "node_modules/semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, - "requires": { + "dependencies": { "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "serialize-javascript": { + "node_modules/serialize-javascript": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", "dev": true, - "requires": { + "dependencies": { "randombytes": "^2.1.0" } }, - "setimmediate": { + "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", "dev": true }, - "shallow-clone": { + "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, - "requires": { + "dependencies": { "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" } }, - "shebang-command": { + "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "requires": { + "dependencies": { "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "shebang-regex": { + "node_modules/shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "side-channel": { + "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, - "requires": { + "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "signal-exit": { + "node_modules/signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, - "slash": { + "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "slice-ansi": { + "node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, - "requires": { + "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "source-list-map": { + "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", "dev": true }, - "source-map": { + "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "source-map-support": { + "node_modules/source-map-support": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "dev": true, - "requires": { + "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "sprintf-js": { + "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "string-width": { + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/string-width": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", "dev": true, - "requires": { + "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } + "engines": { + "node": ">=8" } }, - "strip-ansi": { + "node_modules/strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, - "requires": { + "dependencies": { "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" } }, - "strip-final-newline": { + "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "strip-json-comments": { + "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "supports-color": { + "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { + "dependencies": { "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "table": { + "node_modules/table": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/table/-/table-6.1.0.tgz", "integrity": "sha512-T4G5KMmqIk6X87gLKWyU5exPpTjLjY5KyrFWaIjv3SvgaIUGXV7UEzGEnZJdTA38/yUS6f9PlKezQ0bYXG3iIQ==", "dev": true, - "requires": { + "dependencies": { "ajv": "^8.0.1", "is-boolean-object": "^1.1.0", "is-number-object": "^1.0.4", @@ -2890,38 +3795,47 @@ "slice-ansi": "^4.0.0", "string-width": "^4.2.0" }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.1.0.tgz", + "integrity": "sha512-B/Sk2Ix7A36fs/ZkuGLIR86EdjbgR6fsAcbx9lOP/QBSXujDNbVmIS/U4Itz5k8fPFDeVZl/zQ/gJW4Jrq6XjQ==", + "dev": true, "dependencies": { - "ajv": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.1.0.tgz", - "integrity": "sha512-B/Sk2Ix7A36fs/ZkuGLIR86EdjbgR6fsAcbx9lOP/QBSXujDNbVmIS/U4Itz5k8fPFDeVZl/zQ/gJW4Jrq6XjQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "tapable": { + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "tar": { + "node_modules/tar": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", - "requires": { + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me", + "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^3.0.0", @@ -2929,171 +3843,239 @@ "mkdirp": "^1.0.3", "yallist": "^4.0.0" }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - } + "engines": { + "node": ">= 10" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" } }, - "terser": { + "node_modules/terser": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.6.1.tgz", "integrity": "sha512-yv9YLFQQ+3ZqgWCUk+pvNJwgUTdlIxUk1WTN+RnaFJe2L7ipG2csPT0ra2XRm7Cs8cxN7QXmK1rFzEwYEQkzXw==", "dev": true, - "requires": { + "dependencies": { "commander": "^2.20.0", "source-map": "~0.7.2", "source-map-support": "~0.5.19" }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" } }, - "terser-webpack-plugin": { + "node_modules/terser-webpack-plugin": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz", "integrity": "sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==", "dev": true, - "requires": { + "dependencies": { "jest-worker": "^26.6.2", "p-limit": "^3.1.0", "schema-utils": "^3.0.0", "serialize-javascript": "^5.0.1", "source-map": "^0.6.1", "terser": "^5.5.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" } }, - "text-table": { + "node_modules/terser/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "tmp": { + "node_modules/tmp": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", "dev": true, - "requires": { + "dependencies": { "os-tmpdir": "~1.0.1" + }, + "engines": { + "node": ">=0.4.0" } }, - "to-regex-range": { + "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { + "dependencies": { "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "toposort": { + "node_modules/toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=" }, - "traverse": { + "node_modules/traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", - "dev": true + "dev": true, + "engines": { + "node": "*" + } }, - "ts-loader": { + "node_modules/ts-loader": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.1.0.tgz", "integrity": "sha512-YiQipGGAFj2zBfqLhp28yUvPP9jUGqHxRzrGYuc82Z2wM27YIHbElXiaZDc93c3x0mz4zvBmS6q/DgExpdj37A==", "dev": true, - "requires": { + "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^4.0.0", "loader-utils": "^2.0.0", "micromatch": "^4.0.0", "semver": "^7.3.4" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "*" } }, - "tslib": { + "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "tsutils": { + "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, - "requires": { + "dependencies": { "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "tunnel": { + "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } }, - "type-check": { + "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "requires": { + "dependencies": { "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "type-fest": { + "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "typed-rest-client": { + "node_modules/typed-rest-client": { "version": "1.8.4", "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.4.tgz", "integrity": "sha512-MyfKKYzk3I6/QQp6e1T50py4qg+c+9BzOEl2rBmQIpStwNUoqQ73An+Tkfy9YuV7O+o2mpVVJpe+fH//POZkbg==", "dev": true, - "requires": { + "dependencies": { "qs": "^6.9.1", "tunnel": "0.0.6", "underscore": "^1.12.1" } }, - "typescript": { + "node_modules/typescript": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", - "dev": true + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } }, - "uc.micro": { + "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, - "underscore": { + "node_modules/underscore": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, - "universalify": { + "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } }, - "unzipper": { + "node_modules/unzipper": { "version": "0.10.11", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", "dev": true, - "requires": { + "dependencies": { "big-integer": "^1.6.17", "binary": "~0.3.0", "bluebird": "~3.4.1", @@ -3106,39 +4088,40 @@ "setimmediate": "~1.0.4" } }, - "uri-js": { + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "requires": { + "dependencies": { "punycode": "^2.1.0" } }, - "url-join": { + "node_modules/url-join": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz", "integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=", "dev": true }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "v8-compile-cache": { + "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "vsce": { + "node_modules/vsce": { "version": "1.88.0", "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.88.0.tgz", "integrity": "sha512-FS5ou3G+WRnPPr/tWVs8b/jVzeDacgZHy/y7/QQW7maSPFEAmRt2bFGUJtJVEUDLBqtDm/3VGMJ7D31cF2U1tw==", + "deprecated": "vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead.", "dev": true, - "requires": { + "dependencies": { "azure-devops-node-api": "^10.2.2", "chalk": "^2.4.2", "cheerio": "^1.0.0-rc.1", @@ -3160,105 +4143,137 @@ "yauzl": "^2.3.1", "yazl": "^2.2.2" }, + "bin": { + "vsce": "out/vsce" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/vsce/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "vscode-test": { + "node_modules/vsce/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/vsce/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/vsce/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/vsce/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/vsce/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/vsce/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/vsce/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/vsce/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/vscode-test": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.5.2.tgz", "integrity": "sha512-x9PVfKxF6EInH9iSFGQi0V8H5zIW1fC7RAer6yNQR6sy3WyOwlWkuT3I+wf75xW/cO53hxMi1aj/EvqQfDFOAg==", + "deprecated": "This package has been renamed to @vscode/test-electron, please update to the new name", "dev": true, - "requires": { + "dependencies": { "http-proxy-agent": "^4.0.1", "https-proxy-agent": "^5.0.0", "rimraf": "^3.0.2", "unzipper": "^0.10.11" + }, + "engines": { + "node": ">=8.9.3" } }, - "watchpack": { + "node_modules/watchpack": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz", "integrity": "sha512-Oo7LXCmc1eE1AjyuSBmtC3+Wy4HcV8PxWh2kP6fOl8yTlNS7r0K9l1ao2lrrUza7V39Y3D/BbJgY8VeSlc5JKw==", "dev": true, - "requires": { + "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" } }, - "webpack": { + "node_modules/webpack": { "version": "5.33.2", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.33.2.tgz", "integrity": "sha512-X4b7F1sYBmJx8mlh2B7mV5szEkE0jYNJ2y3akgAP0ERi0vLCG1VvdsIxt8lFd4st6SUy0lf7W0CCQS566MBpJg==", "dev": true, - "requires": { + "dependencies": { "@types/eslint-scope": "^3.7.0", "@types/estree": "^0.0.46", "@webassemblyjs/ast": "1.11.0", @@ -3283,37 +4298,28 @@ "watchpack": "^2.0.0", "webpack-sources": "^2.1.1" }, - "dependencies": { - "acorn": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.1.tgz", - "integrity": "sha512-xYiIVjNuqtKXMxlRMDc6mZUhXehod4a3gbZ1qRlM7icK4EbxUFNLhWoPblCvFtB2Y9CIqHP3CF/rdxLItaQv8g==", - "dev": true - }, - "enhanced-resolve": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz", - "integrity": "sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "tapable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", - "dev": true + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true } } }, - "webpack-cli": { + "node_modules/webpack-cli": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.6.0.tgz", "integrity": "sha512-9YV+qTcGMjQFiY7Nb1kmnupvb1x40lfpj8pwdO/bom+sQiP4OBMKjHq29YQrlDWDPZO9r/qWaRRywKaRDKqBTA==", "dev": true, - "requires": { + "dependencies": { "@discoveryjs/json-ext": "^0.5.0", "@webpack-cli/configtest": "^1.0.2", "@webpack-cli/info": "^1.2.3", @@ -3329,138 +4335,230 @@ "v8-compile-cache": "^2.2.0", "webpack-merge": "^5.7.3" }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true } } }, - "webpack-merge": { + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-merge": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz", "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==", "dev": true, - "requires": { + "dependencies": { "clone-deep": "^4.0.1", "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" } }, - "webpack-sources": { + "node_modules/webpack-sources": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz", "integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==", "dev": true, - "requires": { + "dependencies": { "source-list-map": "^2.0.1", "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10.13.0" } }, - "which": { + "node_modules/webpack/node_modules/acorn": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.1.tgz", + "integrity": "sha512-xYiIVjNuqtKXMxlRMDc6mZUhXehod4a3gbZ1qRlM7icK4EbxUFNLhWoPblCvFtB2Y9CIqHP3CF/rdxLItaQv8g==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/enhanced-resolve": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz", + "integrity": "sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/tapable": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", + "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "wide-align": { + "node_modules/wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, - "requires": { + "dependencies": { "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "wildcard": { + "node_modules/wildcard": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", "dev": true }, - "word-wrap": { + "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "workerpool": { + "node_modules/workerpool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", "dev": true }, - "wrap-ansi": { + "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "requires": { + "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "y18n": { + "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + } }, - "yallist": { + "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "yargs": { + "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, - "requires": { + "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", @@ -3468,56 +4566,71 @@ "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" } }, - "yargs-parser": { + "node_modules/yargs-parser": { "version": "20.2.4", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + } }, - "yargs-unparser": { + "node_modules/yargs-unparser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, - "requires": { + "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" } }, - "yauzl": { + "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, - "requires": { + "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, - "yazl": { + "node_modules/yazl": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", "dev": true, - "requires": { + "dependencies": { "buffer-crc32": "~0.2.3" } }, - "yocto-queue": { + "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "yup": { + "node_modules/yup": { "version": "0.32.9", "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.9.tgz", "integrity": "sha512-Ci1qN+i2H0XpY7syDQ0k5zKQ/DoxO0LzPg8PAR/X4Mpj6DqaeCoIYEEjDJwhArh3Fa7GWbQQVDZKeXYlSH4JMg==", - "requires": { + "dependencies": { "@babel/runtime": "^7.10.5", "@types/lodash": "^4.14.165", "lodash": "^4.17.20", @@ -3525,6 +4638,9 @@ "nanoclone": "^0.2.1", "property-expr": "^2.0.4", "toposort": "^2.0.2" + }, + "engines": { + "node": ">=10" } } } diff --git a/src/appwrite/Database.ts b/src/appwrite/Database.ts index 2895372..1530bc8 100644 --- a/src/appwrite/Database.ts +++ b/src/appwrite/Database.ts @@ -269,7 +269,7 @@ export class Database { permissions.push(Permission.delete(this.normalizeRole(role))); }); - return [...new Set(permissions)]; // Remove duplicates + return Array.from(new Set(permissions)); // Remove duplicates } /** diff --git a/src/appwrite/Users.ts b/src/appwrite/Users.ts index 0dbeb53..9c5fde6 100644 --- a/src/appwrite/Users.ts +++ b/src/appwrite/Users.ts @@ -1,5 +1,5 @@ import { window } from "vscode"; -import { Client, Log, LogList, User, UsersList, UsersClient } from "../appwrite"; +import { Client, Log, LogsList, User, UsersList, UsersClient } from "../appwrite"; import { AppwriteSDK, ID } from "../constants"; import AppwriteCall from "../utils/AppwriteCall"; @@ -43,7 +43,7 @@ export class Users { * Note: In SDK v21, getLogs returns LogList with logs array */ public async getLogs(userId: string, queries?: string[]): Promise { - const result = await AppwriteCall(this.users.getLogs(userId, queries)); + const result = await AppwriteCall(this.users.getLogs(userId, queries)); return result?.logs ?? []; } diff --git a/src/commands/database/createAttribute.ts b/src/commands/database/createAttribute.ts new file mode 100644 index 0000000..ae5a963 --- /dev/null +++ b/src/commands/database/createAttribute.ts @@ -0,0 +1,102 @@ +import { window } from "vscode"; +import { databaseClient } from "../../client"; +import { ext } from "../../extensionVariables"; +import { AttributesTreeItem } from "../../tree/database/settings/AttributesTreeItem"; + +const ATTRIBUTE_TYPES = [ + { label: "String", description: "Text content" }, + { label: "Integer", description: "Whole numbers" }, + { label: "Float", description: "Decimal numbers" }, + { label: "Boolean", description: "True/false values" }, + { label: "Email", description: "Email addresses" }, + { label: "URL", description: "Web URLs" }, + { label: "IP", description: "IP addresses" }, + { label: "Datetime", description: "Date and time values" }, + { label: "Enum", description: "Predefined options" }, +]; + +export async function createAttribute(attributesTreeItem: AttributesTreeItem): Promise { + if (!databaseClient) { + return; + } + + const collectionTreeItem = attributesTreeItem.parent; + const collection = collectionTreeItem.collection; + const databaseId = collectionTreeItem.databaseId; + + // Select attribute type + const typeChoice = await window.showQuickPick(ATTRIBUTE_TYPES, { + placeHolder: "Select attribute type", + }); + + if (!typeChoice) { + return; + } + + // Get attribute key + const key = await window.showInputBox({ + prompt: "Attribute key (name)", + validateInput: (value) => { + if (!value || value.length === 0) return "Key is required"; + if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(value)) return "Key must start with letter/underscore and contain only letters, numbers, underscores"; + return undefined; + }, + }); + + if (!key) { + return; + } + + // Ask if required + const requiredChoice = await window.showQuickPick( + [{ label: "Required", picked: false }, { label: "Optional", picked: true }], + { placeHolder: "Is this attribute required?" } + ); + + if (!requiredChoice) { + return; + } + + const required = requiredChoice.label === "Required"; + + try { + switch (typeChoice.label) { + case "String": { + const sizeStr = await window.showInputBox({ + prompt: "Maximum string length (1-16384)", + value: "255", + }); + const size = parseInt(sizeStr || "255"); + await databaseClient.createStringAttribute(collection.$id, key, size, required, undefined, false, databaseId); + break; + } + case "Integer": { + await databaseClient.createIntegerAttribute(collection.$id, key, required, undefined, undefined, undefined, false, databaseId); + break; + } + case "Boolean": { + await databaseClient.createBooleanAttribute(collection.$id, key, required, undefined, false, databaseId); + break; + } + case "Email": { + await databaseClient.createEmailAttribute(collection.$id, key, required, undefined, false, databaseId); + break; + } + case "URL": { + await databaseClient.createUrlAttribute(collection.$id, key, required, undefined, false, databaseId); + break; + } + default: + window.showWarningMessage(`Attribute type "${typeChoice.label}" is not yet supported in this extension.`); + return; + } + + window.showInformationMessage(`Created ${typeChoice.label.toLowerCase()} attribute "${key}".`); + ext.tree?.database?.refresh(); + } catch (e) { + window.showErrorMessage(e.message || String(e)); + } +} + +// Backward compatibility alias +export { createAttribute as createRule }; diff --git a/src/commands/database/createRule.ts b/src/commands/database/createRule.ts deleted file mode 100644 index 689611d..0000000 --- a/src/commands/database/createRule.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { CreatedRule } from "../../appwrite"; -import { databaseClient } from "../../client"; -import { RulesTreeItem } from "../../tree/database/settings/RulesTreeItem"; -import { createRuleWizard } from "../../ui/createRuleWizard"; -import { refreshTree } from '../../utils/refreshTree'; - -export async function createRule(rulesTreeItem: RulesTreeItem): Promise { - - if (!databaseClient) { - return; - } - - const collection = rulesTreeItem.parent.collection; - const ruleContext = await createRuleWizard(collection); - - if (ruleContext) { - const newRule: CreatedRule = { - ...ruleContext, - type: ruleContext.type, - }; - - databaseClient.createRule(collection, newRule); - - await rulesTreeItem.refresh(); - refreshTree("database"); - } -} diff --git a/src/commands/database/deleteAttribute.ts b/src/commands/database/deleteAttribute.ts new file mode 100644 index 0000000..903e9f6 --- /dev/null +++ b/src/commands/database/deleteAttribute.ts @@ -0,0 +1,35 @@ +import { window } from "vscode"; +import { databaseClient } from "../../client"; +import { ext } from "../../extensionVariables"; +import { AttributeTreeItem } from "../../tree/database/settings/AttributeTreeItem"; +import { confirmDialog } from "../../ui/confirmDialog"; + +export async function deleteAttribute(attributeItem: AttributeTreeItem): Promise { + if (!databaseClient) { + return; + } + + const attribute = attributeItem.attribute; + const collectionTreeItem = attributeItem.parent.parent; + const collection = collectionTreeItem.collection; + const databaseId = collectionTreeItem.databaseId; + + try { + const shouldDelete = await confirmDialog( + `Delete attribute "${attribute.key}" from collection "${collection.name}"?` + ); + + if (!shouldDelete) { + return; + } + + await databaseClient.deleteAttribute(collection.$id, attribute.key, databaseId); + window.showInformationMessage(`Deleted attribute "${attribute.key}".`); + ext.tree?.database?.refresh(); + } catch (e) { + window.showErrorMessage(e.message || String(e)); + } +} + +// Backward compatibility alias +export { deleteAttribute as removeRule }; diff --git a/src/commands/database/permissions/createPermission.ts b/src/commands/database/permissions/createPermission.ts index bd0929b..7712223 100644 --- a/src/commands/database/permissions/createPermission.ts +++ b/src/commands/database/permissions/createPermission.ts @@ -1,25 +1,61 @@ import { window } from "vscode"; import { databaseClient } from "../../../client"; +import { Permission, Role } from "../../../constants"; +import { ext } from "../../../extensionVariables"; import { PermissionsTreeItem } from "../../../tree/database/settings/PermissionsTreeItem"; +type PermissionType = "read" | "create" | "update" | "delete" | "write"; + export type CreatePermissionWizardContext = { - kind: "read" | "write"; - permission: string; + kind: PermissionType; + role: string; }; -export async function createPermissionWizard(kind?: "read" | "write"): Promise { - const permissionKind = kind ?? (await window.showQuickPick(["read", "write"])); - if (permissionKind && (permissionKind === "read" || permissionKind === "write")) { - const permission = await window.showInputBox({ prompt: "Add * for wildcard access", placeHolder: "User ID, Team ID, or Role" }); - if (permission === undefined) { - return undefined; - } - - return { - kind: permissionKind, - permission, - }; + +export async function createPermissionWizard(): Promise { + const permissionKind = await window.showQuickPick( + ["read", "create", "update", "delete", "write"], + { placeHolder: "Select permission type" } + ) as PermissionType | undefined; + + if (!permissionKind) { + return undefined; + } + + const roleType = await window.showQuickPick( + [ + { label: "any", description: "Anyone (public)" }, + { label: "users", description: "Any authenticated user" }, + { label: "guests", description: "Any unauthenticated user" }, + { label: "user", description: "Specific user by ID" }, + { label: "team", description: "Specific team by ID" }, + ], + { placeHolder: "Select role type" } + ); + + if (!roleType) { + return undefined; + } + + let role: string; + if (roleType.label === "any") { + role = Role.any(); + } else if (roleType.label === "users") { + role = Role.users(); + } else if (roleType.label === "guests") { + role = Role.guests(); + } else if (roleType.label === "user") { + const userId = await window.showInputBox({ prompt: "Enter user ID" }); + if (!userId) return undefined; + role = Role.user(userId); + } else if (roleType.label === "team") { + const teamId = await window.showInputBox({ prompt: "Enter team ID" }); + if (!teamId) return undefined; + role = Role.team(teamId); + } else { + return undefined; } - return undefined; + + return { kind: permissionKind, role }; } export async function createPermission(treeItem: PermissionsTreeItem): Promise { @@ -27,21 +63,43 @@ export async function createPermission(treeItem: PermissionsTreeItem): Promise { if (!databaseClient) { return; } - const collection = treeItem.parent.parent.collection; - const kind = treeItem.kind; - let read = Array.from(collection.$permissions.read); - let write = Array.from(collection.$permissions.write); + const collectionTreeItem = treeItem.parent.parent; + const collection = collectionTreeItem.collection; + const databaseId = collectionTreeItem.databaseId; - if (kind === "read") { - read = read.filter((item) => item !== treeItem.permission); - } else { - write = write.filter((item) => item !== treeItem.permission); - } + // Build the full permission string to remove + const permissionToRemove = `${treeItem.kind}("${treeItem.permission}")`; + + try { + const shouldDelete = await confirmDialog(`Delete ${treeItem.kind} permission for "${treeItem.permission}"?`); + if (!shouldDelete) { + return; + } - await databaseClient.updatePermissions(collection, read, write); + // Remove the permission from the array + const permissions = (collection.$permissions || []).filter( + perm => perm !== permissionToRemove + ); + + await databaseClient.updateCollection(collection.$id, collection.name, permissions, databaseId); + window.showInformationMessage(`Removed ${treeItem.kind} permission for "${treeItem.permission}".`); + ext.tree?.database?.refresh(); + } catch (e) { + window.showErrorMessage(e.message || String(e)); + } } diff --git a/src/commands/database/permissions/editPermission.ts b/src/commands/database/permissions/editPermission.ts index 81f5aa1..1c038bc 100644 --- a/src/commands/database/permissions/editPermission.ts +++ b/src/commands/database/permissions/editPermission.ts @@ -1,32 +1,40 @@ import { window } from "vscode"; import { databaseClient } from "../../../client"; +import { ext } from "../../../extensionVariables"; import { PermissionTreeItem } from "../../../tree/database/settings/PermissionTreeItem"; export async function editPermission(treeItem: PermissionTreeItem): Promise { if (!databaseClient) { return; } - const editedPermission = await window.showInputBox({ + + const editedRole = await window.showInputBox({ value: treeItem.permission, + prompt: `Edit the role for ${treeItem.kind} permission`, }); - if (editedPermission === undefined) { + if (editedRole === undefined || editedRole === treeItem.permission) { return; } - const collection = treeItem.parent.parent.collection; - const kind = treeItem.kind; + const collectionTreeItem = treeItem.parent.parent; + const collection = collectionTreeItem.collection; + const databaseId = collectionTreeItem.databaseId; - let read = Array.from(collection.$permissions.read); - let write = Array.from(collection.$permissions.write); + // Build permission strings + const oldPermission = `${treeItem.kind}("${treeItem.permission}")`; + const newPermission = `${treeItem.kind}("${editedRole}")`; - if (kind === "read") { - read = read.filter((item) => item !== treeItem.permission); - read.push(editedPermission); - } else { - write = write.filter((item) => item !== treeItem.permission); - write.push(editedPermission); - } + try { + // Update permissions: remove old, add new + const permissions = (collection.$permissions || []) + .filter(perm => perm !== oldPermission) + .concat(newPermission); - await databaseClient.updatePermissions(collection, read, write); + await databaseClient.updateCollection(collection.$id, collection.name, permissions, databaseId); + window.showInformationMessage(`Updated ${treeItem.kind} permission to "${editedRole}".`); + ext.tree?.database?.refresh(); + } catch (e) { + window.showErrorMessage(e.message || String(e)); + } } diff --git a/src/commands/database/removeRule.ts b/src/commands/database/removeRule.ts deleted file mode 100644 index 5c455d5..0000000 --- a/src/commands/database/removeRule.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { databaseClient } from '../../client'; -import { RuleTreeItem } from '../../tree/database/settings/RuleTreeItem'; -import { refreshTree } from '../../utils/refreshTree'; - -export async function removeRule(ruleItem: RuleTreeItem): Promise { - if (!databaseClient) { - return; - } - const rule = ruleItem.rule; - const collection = ruleItem.parent.parent.collection; - await databaseClient.removeRule(collection, rule); - refreshTree('database'); -} diff --git a/src/commands/functions/activateTag.ts b/src/commands/functions/activateTag.ts deleted file mode 100644 index b34a423..0000000 --- a/src/commands/functions/activateTag.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tag } from '../../appwrite'; -import { functionsClient } from '../../client'; -import { TagTreeItem } from '../../tree/functions/tags/TagTreeItem'; - -export async function activateTag(tagItem: TagTreeItem | Tag): Promise { - const tag = tagItem instanceof TagTreeItem ? tagItem.tag : tagItem; - await functionsClient?.updateTag(tag.functionId, tag.$id); -} diff --git a/src/commands/functions/createFunctionVar.ts b/src/commands/functions/createFunctionVar.ts index d2d7c77..6ddc7ad 100644 --- a/src/commands/functions/createFunctionVar.ts +++ b/src/commands/functions/createFunctionVar.ts @@ -1,16 +1,23 @@ +import { window } from 'vscode'; import { functionsClient } from '../../client'; +import { ext } from '../../extensionVariables'; import { VarsTreeItem } from '../../tree/functions/settings/VarsTreeItem'; import { keyValuePrompt } from '../../tree/functions/settings/VarTreeItem'; export async function createFunctionVar(treeItem: VarsTreeItem): Promise { - if (treeItem === undefined) { + if (treeItem === undefined || !functionsClient) { return; } const func = treeItem.parent.func; const keyval = await keyValuePrompt(); if (keyval) { - const newVars = {...func.vars}; - newVars[keyval.key] = keyval.value; - await functionsClient?.update(func.$id, func.name, [], newVars, func.events, func.schedule, func.timeout); + try { + // SDK v21: Use createVariable instead of updating func.vars + await functionsClient.createVariable(func.$id, keyval.key, keyval.value); + window.showInformationMessage(`Created variable "${keyval.key}".`); + ext.tree?.functions?.refresh(); + } catch (e) { + window.showErrorMessage(e.message || String(e)); + } } } diff --git a/src/commands/functions/createTag.ts b/src/commands/functions/createTag.ts deleted file mode 100644 index b154d33..0000000 --- a/src/commands/functions/createTag.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { ProgressLocation, QuickPickItem, Uri, window, workspace } from "vscode"; -import { functionsClient } from "../../client"; -import { getTarReadStream } from "../../utils/tar"; -import { ext } from "../../extensionVariables"; -import * as fs from "fs"; -import { TagsTreeItem } from "../../tree/functions/tags/TagsTreeItem"; -import { selectWorkspaceFolder } from "../../utils/workspace"; -import { ProgressMessage } from "../../utils/types"; -import { Tag } from "../../appwrite"; -import { activateTag } from "./activateTag"; - -export async function createTag(item?: TagsTreeItem | Uri): Promise { - if (item instanceof Uri) { - const functions = await functionsClient?.list(); - if (functions === undefined) { - return; - } - const pick = await window.showQuickPick( - functions.functions.map( - (func): QuickPickItem => ({ label: func.name, description: func.env, detail: func.$id }) - ), - { placeHolder: "Select a function to create tag" } - ); - if (pick === undefined || pick.detail === undefined) { - return; - } - const tags = await functionsClient?.listTags(pick.detail); - let value; - if (tags && tags.tags.length > 0) { - value = tags.tags[tags.tags.length - 1].command; - } - const command = await window.showInputBox({ value, prompt: "Command to run your code" }); - if (command === undefined) { - return; - } - const tag = await window.withProgress( - { location: ProgressLocation.Notification, title: "Creating tag..." }, - async (progress, _token) => { - if (pick.detail === undefined) { - return; - } - return await createTagFromUri(pick.detail, command, item, progress); - } - ); - if (tag) { - await tagNotification(tag); - } - - return; - } - - if (item instanceof TagsTreeItem) { - const func = item.parent.func; - const folder = await selectWorkspaceFolder("Select folder of your function code."); - if (folder === undefined || folder === "") { - return; - } - const tags = await functionsClient?.listTags(func.$id); - let value; - if (tags && tags.tags.length > 0) { - value = tags.tags[tags.tags.length - 1].command; - } - const command = await window.showInputBox({ value, prompt: "Command to run your code" }); - if (command === undefined) { - return; - } - const tag = await window.withProgress( - { location: ProgressLocation.Notification, title: "Creating tag..." }, - async (progress, _token) => { - return await createTagFromUri(func.$id, command, Uri.parse(folder), progress); - } - ); - - if (tag) { - await tagNotification(tag); - return; - } - } - - if (item === undefined) { - const functions = await functionsClient?.list(); - if (functions === undefined) { - return; - } - const pick = await window.showQuickPick( - functions.functions.map( - (func): QuickPickItem => ({ label: func.name, description: func.env, detail: func.$id }) - ), - { placeHolder: "Select a function to create tag" } - ); - if (pick === undefined || pick.detail === undefined) { - return; - } - const funcId = pick.detail; - const folder = await selectWorkspaceFolder("Select folder of your function code."); - const tags = await functionsClient?.listTags(funcId); - let value; - if (tags && tags.tags.length > 0) { - value = tags.tags[tags.tags.length - 1].command; - } - const command = await window.showInputBox({ value, prompt: "Command to run your code" }); - if (command === undefined) { - return; - } - const tag = await window.withProgress( - { location: ProgressLocation.Notification, title: "Creating tag..." }, - async (progress, _token) => { - return await createTagFromUri(funcId, command, Uri.parse(folder), progress); - } - ); - - if (tag) { - await tagNotification(tag); - return; - } - } -} - -async function createTagFromUri(functionId: string, command: string, uri: Uri, progress: ProgressMessage): Promise { - progress.report({ message: "Creating tarball", increment: 10 }); - - if (functionsClient === undefined) { - return; - } - - let tarFilePath; - try { - tarFilePath = await getTarReadStream(uri); - } catch (e) { - window.showErrorMessage("Error creating tar file.\n" + e); - return; - } - if (tarFilePath === undefined) { - window.showErrorMessage("Failed to create tar file."); - ext.outputChannel.appendLog("Failed to create tar file."); - return; - } - // somehow makes the upload work - await workspace.fs.readFile(Uri.file(tarFilePath)); - progress.report({ message: "Uploading tag", increment: 60 }); - try { - return await functionsClient.createTag(functionId, command, fs.createReadStream(tarFilePath)); - } catch (e) { - ext.outputChannel.appendLog("Creating tag error: " + e); - } -} - -async function tagNotification(tag: Tag): Promise { - ext.tree?.functions?.refresh(); - if (tag) { - const action = await window.showInformationMessage( - `Successfully created tag with size ${tag.size}B.`, - "Activate tag", - "View in console" - ); - if (action === "Activate tag") { - await activateTag(tag); - } - if (action === "View in console") { - // - } - return; - } -} diff --git a/src/commands/functions/deleteFunctionVar.ts b/src/commands/functions/deleteFunctionVar.ts index cac27e3..b0fe9f8 100644 --- a/src/commands/functions/deleteFunctionVar.ts +++ b/src/commands/functions/deleteFunctionVar.ts @@ -1,13 +1,30 @@ +import { window } from 'vscode'; import { functionsClient } from '../../client'; +import { ext } from '../../extensionVariables'; import { VarTreeItem } from '../../tree/functions/settings/VarTreeItem'; +import { confirmDialog } from '../../ui/confirmDialog'; export async function deleteFunctionVar(treeItem: VarTreeItem): Promise { - if (treeItem === undefined) { + if (treeItem === undefined || !functionsClient) { return; } - const func = treeItem.func; - const newVars = {...func.vars}; - delete newVars[treeItem.key]; - await functionsClient?.update(func.$id, func.name, [], newVars, func.events, func.schedule, func.timeout); + const func = treeItem.parent.parent.func; + const variableKey = treeItem.key; + + try { + const shouldDelete = await confirmDialog(`Delete variable "${variableKey}"?`); + if (shouldDelete) { + // SDK v21: Need to get variable ID first, then delete + const variables = await functionsClient.listVariables(func.$id); + const variable = variables?.variables.find(v => v.key === variableKey); + if (variable) { + await functionsClient.deleteVariable(func.$id, variable.$id); + window.showInformationMessage(`Deleted variable "${variableKey}".`); + ext.tree?.functions?.refresh(); + } + } + } catch (e) { + window.showErrorMessage(e.message || String(e)); + } } diff --git a/src/commands/functions/deleteTag.ts b/src/commands/functions/deleteTag.ts deleted file mode 100644 index 1d3b885..0000000 --- a/src/commands/functions/deleteTag.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { functionsClient } from "../../client"; -import { TagTreeItem } from "../../tree/functions/tags/TagTreeItem"; - -export async function deleteTag(tagItem: TagTreeItem): Promise { - if (tagItem === undefined) { - return; - } - - const func = tagItem.parent.parent.func; - await functionsClient?.deleteTag(func.$id, tagItem.tag.$id); -} diff --git a/src/commands/registerCommands.ts b/src/commands/registerCommands.ts index b4bd8de..243bea3 100644 --- a/src/commands/registerCommands.ts +++ b/src/commands/registerCommands.ts @@ -4,14 +4,14 @@ import { refreshAllViews, refreshTree } from "../utils/refreshTree"; import { connectAppwrite } from "./connectAppwrite"; import { createCollection } from "./database/createCollection"; import { createPermission } from "./database/permissions/createPermission"; -import { createRule } from "./database/createRule"; +import { createAttribute } from "./database/createAttribute"; import { deleteCollection } from "./database/deleteCollection"; import { deleteDocument } from "./database/deleteDocument"; import { deletePermission } from "./database/permissions/deletePermission"; import { viewDocumentAsJson } from "./database/openDocument"; import { refreshCollection } from "./database/refreshCollection"; import { refreshCollectionsList } from "./database/refreshCollectionsList"; -import { removeRule } from "./database/removeRule"; +import { deleteAttribute } from "./database/deleteAttribute"; import { viewCollectionAsJson } from "./database/viewCollectionAsJson"; import { openDocumentation } from "./openDocumentation"; import { copyUserEmail } from "./users/copyUserEmail"; @@ -96,8 +96,12 @@ export function registerCommands(context: ExtensionContext): void { registerCommand("OpenDatabaseDocumentation", () => openDocumentation("database")); registerCommand("viewDocumentAsJson", viewDocumentAsJson); registerCommand("viewCollectionAsJson", viewCollectionAsJson); - registerCommand("createRule", createRule); - registerCommand("removeRule", removeRule); + // Attribute commands (replaces Rule commands) + registerCommand("createAttribute", createAttribute, "database"); + registerCommand("deleteAttribute", deleteAttribute, "database"); + // Backward compatibility aliases for Rule commands + registerCommand("createRule", createAttribute, "database"); + registerCommand("removeRule", deleteAttribute, "database"); registerCommand("deleteDocument", deleteDocument, "database"); registerCommand("deleteCollection", deleteCollection, "database"); registerCommand("refreshCollection", refreshCollection); diff --git a/src/tree/database/settings/RuleTreeItem.ts b/src/tree/database/settings/RuleTreeItem.ts deleted file mode 100644 index 7d635ac..0000000 --- a/src/tree/database/settings/RuleTreeItem.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Rule } from "../../../appwrite"; -import { ChildTreeItem } from "../../ChildTreeItem"; -import { RulesTreeItem } from "./RulesTreeItem"; - -export class RuleTreeItem extends ChildTreeItem { - constructor(parent: RulesTreeItem, public readonly rule: Rule) { - super(parent, { label: rule.label, description: rule.type }); - } - contextValue = "collection.rule"; -} diff --git a/src/tree/database/settings/RulesTreeItem.ts b/src/tree/database/settings/RulesTreeItem.ts deleted file mode 100644 index d4722e7..0000000 --- a/src/tree/database/settings/RulesTreeItem.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; -import { Rule } from "../../../appwrite"; -import { AppwriteTreeItemBase } from "../../../ui/AppwriteTreeItemBase"; -import { CommandTreeItem } from "../../CommandTreeItem"; -import { CollectionTreeItem } from "../CollectionTreeItem"; -import { RuleTreeItem } from "./RuleTreeItem"; - -export class RulesTreeItem extends AppwriteTreeItemBase { - public readonly rules: Rule[]; - - constructor(parent: CollectionTreeItem) { - super(parent, "Rules"); - this.rules = parent.collection.rules; - } - - public async getChildren(): Promise { - if (this.rules.length === 0) { - const addRuleItem = new CommandTreeItem( - { label: "Add rule", iconPath: new ThemeIcon("add") }, - { command: "vscode-appwrite.createRule", arguments: [this], title: "Create rule", tooltip: "Create collection rule" } - ); - return [addRuleItem]; - } - return this.rules.map((rule) => new RuleTreeItem(this, rule)); - } - - public async refresh(): Promise { - await this.parent.refresh(); - } - - iconPath = new ThemeIcon("symbol-property"); - contextValue = "collection.rules"; - collapsibleState = TreeItemCollapsibleState.Collapsed; -} diff --git a/src/tree/functions/settings/VarTreeItem.ts b/src/tree/functions/settings/VarTreeItem.ts index cd64572..c48c0a2 100644 --- a/src/tree/functions/settings/VarTreeItem.ts +++ b/src/tree/functions/settings/VarTreeItem.ts @@ -5,16 +5,15 @@ import { ext } from "../../../extensionVariables"; import { StringEditableTreeItemBase } from "../../common/editable/StringEditableTreeItem"; import { VarsTreeItem } from "./VarsTreeItem"; -const tooltip = "Environment var"; -const description = "Function name. Max length: 128 chars."; -const tooLongInvalid = "Value exceeds maximum length of 128 characters."; +const tooltip = "Environment variable"; +const description = "Variable value"; export async function keyValuePrompt(keyInit?: string, valueInit?: string): Promise<{ key: string; value: string } | undefined> { - const key = await window.showInputBox({ value: keyInit, prompt: "Environment variable name" }); + const key = await window.showInputBox({ value: keyInit, prompt: "Variable name" }); if (key === undefined) { return; } - const value = await window.showInputBox({ value: valueInit, prompt: "Environment variable value" }); + const value = await window.showInputBox({ value: valueInit, prompt: "Variable value" }); if (value === undefined) { return; } @@ -25,26 +24,32 @@ export class VarTreeItem extends StringEditableTreeItemBase { public readonly func: Function; inputBoxOptions: InputBoxOptions = { - validateInput: (value) => { - if (value.length > 128) { - return tooLongInvalid; - } - }, prompt: description, }; public async setValue(value: string, key?: string): Promise { - if (value.length === 0) { + if (value.length === 0 || !functionsClient) { return; } - const newVars = { ...this.func.vars }; - newVars[this.key] = value; - if (key) { - delete newVars[this.key]; - newVars[key] = value; + + try { + // SDK v21: Use updateVariable to change value + // First get the variable ID + const variables = await functionsClient.listVariables(this.func.$id); + const variable = variables?.variables.find(v => v.key === this.key); + if (variable) { + // If key changed, we need to delete and recreate + if (key && key !== this.key) { + await functionsClient.deleteVariable(this.func.$id, variable.$id); + await functionsClient.createVariable(this.func.$id, key, value); + } else { + await functionsClient.updateVariable(this.func.$id, variable.$id, this.key, value); + } + ext.tree?.functions?.refresh(); + } + } catch (e) { + window.showErrorMessage(e.message || String(e)); } - await functionsClient?.update(this.func.$id, this.func.name, [], newVars, this.func.events, this.func.schedule, this.func.timeout); - ext.tree?.functions?.refresh(); } constructor(public readonly parent: VarsTreeItem, public readonly key: string, value: string) { @@ -58,7 +63,7 @@ export class VarTreeItem extends StringEditableTreeItemBase { public async prompt(): Promise { const keyval = await keyValuePrompt(this.key, this.value); if (keyval) { - this.setValue(keyval.value, keyval.key); + await this.setValue(keyval.value, keyval.key); } } } diff --git a/src/tree/functions/tags/TagTreeItem.ts b/src/tree/functions/tags/TagTreeItem.ts deleted file mode 100644 index b34208a..0000000 --- a/src/tree/functions/tags/TagTreeItem.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MarkdownString, ThemeIcon, TreeItem } from "vscode"; -import { Tag } from '../../../appwrite'; -import { msToDate } from '../../../utils/date'; -import { TagsTreeItem } from './TagsTreeItem'; - -export class TagTreeItem extends TreeItem { - constructor(public readonly parent: TagsTreeItem, public readonly tag: Tag) { - super(tag.$id); - const func = parent.parent.func; - const active = func.tag === tag.$id; - this.label = `${msToDate(tag.dateCreated)}${active ? ' (Active)' : ''}`; - this.description = tag.$id; - this.iconPath = new ThemeIcon(active ? 'circle-large-filled' : 'circle-large-outline'); - this.contextValue = `tag${active ? '_active' : ''}`; - this.tooltip = new MarkdownString(`ID: ${tag.$id} \nCreated: ${msToDate(tag.dateCreated)} \nCommand: ${tag.command} \nSize: ${tag.size}B`); - } -} diff --git a/src/tree/functions/tags/TagsTreeItem.ts b/src/tree/functions/tags/TagsTreeItem.ts deleted file mode 100644 index e9f7f4a..0000000 --- a/src/tree/functions/tags/TagsTreeItem.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; -import { functionsClient } from "../../../client"; -import { AppwriteTreeItemBase } from '../../../ui/AppwriteTreeItemBase'; -import { FunctionTreeItem } from '../FunctionTreeItem'; -import { TagTreeItem } from './TagTreeItem'; - -export class TagsTreeItem extends AppwriteTreeItemBase { - constructor(public readonly parent: FunctionTreeItem) { - super(parent, "Tags"); - } - - public async getChildren(): Promise { - if (!functionsClient) { - return []; - } - const tags = await functionsClient.listTags(this.parent.func.$id); - const children = tags?.tags.sort((a, b) => b.dateCreated - a.dateCreated).map((tag) => new TagTreeItem(this, tag)) ?? [new TreeItem('No tags.')]; - - if (children.length === 0) { - const noTagsItem: TreeItem = { - command: { - command: "vscode-appwrite.CreateTag", - title: "Create tag", - arguments: [this], - tooltip: "Create a tag" - }, - label: "Create a tag", - iconPath: new ThemeIcon("cloud-upload"), - }; - children.push(noTagsItem); - } - return children; - } - - collapsibleState = TreeItemCollapsibleState.Collapsed; - - contextValue = "tags"; - - iconPath = new ThemeIcon("tag"); -} diff --git a/src/tree/users/UserTreeItemProvider.ts b/src/tree/users/UserTreeItemProvider.ts index f2d73ff..a86b7cc 100644 --- a/src/tree/users/UserTreeItemProvider.ts +++ b/src/tree/users/UserTreeItemProvider.ts @@ -1,13 +1,10 @@ import * as vscode from "vscode"; -import { client } from "../../client"; -import AppwriteCall from "../../utils/AppwriteCall"; -import { User, UsersList } from "../../appwrite"; +import { usersClient } from "../../client"; +import { User } from "../../appwrite"; import { ThemeIcon } from "vscode"; import { UserPrefsTreeItem } from "./properties/UserPrefsTreeItem"; import { ChildTreeItem } from "../ChildTreeItem"; import { UserTreeItem } from "./UserTreeItem"; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const sdk = require("node-appwrite"); export class UserTreeItemProvider implements vscode.TreeDataProvider { private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter< @@ -25,13 +22,13 @@ export class UserTreeItemProvider implements vscode.TreeDataProvider { - if (client === undefined) { + if (usersClient === undefined) { return Promise.resolve([]); } if (element instanceof UserTreeItem) { - const regDate = new Date(); - regDate.setMilliseconds(element.user.registration); + // SDK v21: registration is now an ISO date string + const regDate = new Date(element.user.registration); const items: vscode.TreeItem[] = [ new ChildTreeItem(element, { contextValue: "user.name", @@ -62,12 +59,12 @@ export class UserTreeItemProvider implements vscode.TreeDataProvider(usersSdk.list()); + const usersList = await usersClient.list(); if (usersList) { const userTreeItems = usersList.users.map((user: User) => new UserTreeItem(user)) ?? []; const headerItem: vscode.TreeItem = { - label: `Total users: ${usersList.sum}`, + // SDK v21: sum renamed to total + label: `Total users: ${usersList.total}`, }; return [headerItem, ...userTreeItems]; } diff --git a/src/utils/AppwriteCall.ts b/src/utils/AppwriteCall.ts index 7101e5b..fccfb5d 100644 --- a/src/utils/AppwriteCall.ts +++ b/src/utils/AppwriteCall.ts @@ -4,7 +4,7 @@ import { Error } from "../appwrite"; import { ext } from "../extensionVariables"; export default function AppwriteCall( - promise: Promise, + promise: Promise, onSuccess?: (success: T) => R, onError?: (error: Error) => R ): Promise { diff --git a/src/utils/date.ts b/src/utils/date.ts index adad317..31bb271 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -4,6 +4,15 @@ import timezone = require("dayjs/plugin/timezone"); // dependent on utc plugin dayjs.extend(utc); dayjs.extend(timezone); -export function msToDate(ms: number): string { - return dayjs(ms * 1000).tz(dayjs.tz.guess()).format("LTS"); +/** + * Convert a timestamp to localized time string + * @param dateValue - Can be a Unix timestamp (number) or ISO date string + */ +export function msToDate(dateValue: number | string): string { + if (typeof dateValue === 'string') { + // ISO date string (SDK v21+) + return dayjs(dateValue).tz(dayjs.tz.guess()).format("LTS"); + } + // Legacy: Unix timestamp in seconds + return dayjs(dateValue * 1000).tz(dayjs.tz.guess()).format("LTS"); } From 0303df4e81c2d06910e8c0068da254b7b0711228 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Mon, 26 Jan 2026 16:40:38 +0100 Subject: [PATCH 10/14] fix: add defensive guards and improve error handling - Validate queries/search params in Functions.list() and Users.list() to avoid passing empty strings to SDK v21 API - Add null guards for this.parent?.func in DeploymentsTreeItem, ExecutionsTreeItem, and VarsTreeItem - Make AppwriteCall error handler defensive: type errResp as unknown, add console.error logging, wrap handler in try-catch Co-Authored-By: Claude Opus 4.5 --- src/appwrite/Functions.ts | 5 ++- src/appwrite/Users.ts | 5 ++- .../deployments/DeploymentsTreeItem.ts | 2 +- .../executions/ExecutionsTreeItem.ts | 2 +- src/tree/functions/settings/VarsTreeItem.ts | 2 +- src/utils/AppwriteCall.ts | 34 +++++++++++++------ 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/appwrite/Functions.ts b/src/appwrite/Functions.ts index 2073e23..c3d0a55 100644 --- a/src/appwrite/Functions.ts +++ b/src/appwrite/Functions.ts @@ -53,7 +53,10 @@ export class Functions { } public async list(queries?: string[], search?: string): Promise { - return await AppwriteCall(this.functions.list(queries, search)); + // Ensure we pass undefined (not empty string) for search to avoid API validation errors + const validQueries = queries && queries.length > 0 ? queries : undefined; + const validSearch = search && search.length > 0 ? search : undefined; + return await AppwriteCall(this.functions.list(validQueries, validSearch)); } public async get(functionId: string): Promise { diff --git a/src/appwrite/Users.ts b/src/appwrite/Users.ts index 9c5fde6..de50dff 100644 --- a/src/appwrite/Users.ts +++ b/src/appwrite/Users.ts @@ -29,7 +29,10 @@ export class Users { } public async list(queries?: string[], search?: string): Promise { - return await AppwriteCall(this.users.list(queries, search)); + // Ensure we pass undefined (not empty string) for search to avoid API validation errors + const validQueries = queries && queries.length > 0 ? queries : undefined; + const validSearch = search && search.length > 0 ? search : undefined; + return await AppwriteCall(this.users.list(validQueries, validSearch)); } public async delete(userId: string): Promise { diff --git a/src/tree/functions/deployments/DeploymentsTreeItem.ts b/src/tree/functions/deployments/DeploymentsTreeItem.ts index a0c03fd..82bb587 100644 --- a/src/tree/functions/deployments/DeploymentsTreeItem.ts +++ b/src/tree/functions/deployments/DeploymentsTreeItem.ts @@ -10,7 +10,7 @@ export class DeploymentsTreeItem extends AppwriteTreeItemBase } public async getChildren(): Promise { - if (!functionsClient) { + if (!functionsClient || !this.parent?.func) { return []; } const deployments = await functionsClient.listDeployments(this.parent.func.$id); diff --git a/src/tree/functions/executions/ExecutionsTreeItem.ts b/src/tree/functions/executions/ExecutionsTreeItem.ts index d13ce69..e866586 100644 --- a/src/tree/functions/executions/ExecutionsTreeItem.ts +++ b/src/tree/functions/executions/ExecutionsTreeItem.ts @@ -15,7 +15,7 @@ export class ExecutionsTreeItem extends AppwriteTreeItemBase { private executionsToShow = 10; public async getChildren(): Promise { - if (!functionsClient) { + if (!functionsClient || !this.parent?.func) { return []; } diff --git a/src/tree/functions/settings/VarsTreeItem.ts b/src/tree/functions/settings/VarsTreeItem.ts index b115f0a..dcdd263 100644 --- a/src/tree/functions/settings/VarsTreeItem.ts +++ b/src/tree/functions/settings/VarsTreeItem.ts @@ -11,7 +11,7 @@ export class VarsTreeItem extends AppwriteTreeItemBase } public async getChildren(): Promise { - if (!functionsClient) { + if (!functionsClient || !this.parent?.func) { return []; } diff --git a/src/utils/AppwriteCall.ts b/src/utils/AppwriteCall.ts index fccfb5d..89bdeb8 100644 --- a/src/utils/AppwriteCall.ts +++ b/src/utils/AppwriteCall.ts @@ -1,29 +1,43 @@ /* eslint-disable @typescript-eslint/ban-types */ import { window } from "vscode"; -import { Error } from "../appwrite"; +import { Error as AppwriteError } from "../appwrite"; import { ext } from "../extensionVariables"; export default function AppwriteCall( promise: Promise, onSuccess?: (success: T) => R, - onError?: (error: Error) => R + onError?: (error: AppwriteError) => R ): Promise { return promise.then( (successResp) => { - ext.outputChannel?.appendLog(`Appwrite call success:`); if (onSuccess) { return onSuccess((successResp as unknown) as T); } return successResp as unknown as R; }, - (errResp: Error) => { - if (onError) { - onError(errResp as Error); - return undefined; - } + (errResp: unknown) => { + try { + const err = errResp as AppwriteError; + const message = err?.message || String(errResp); + + console.error(`[Appwrite] API error:`, errResp); + ext.outputChannel?.appendLog(`Appwrite API error: ${message}`); + if (err?.code) { + ext.outputChannel?.appendLog(`Error code: ${err.code}`); + } + if (err?.type) { + ext.outputChannel?.appendLog(`Error type: ${err.type}`); + } - window.showErrorMessage(errResp.message); - ext.outputChannel?.appendLog(errResp.message); + if (onError) { + onError(err); + return undefined; + } + + window.showErrorMessage(message); + } catch (handlerError) { + console.error(`[Appwrite] Error in error handler:`, handlerError); + } return undefined; } ); From aa4c8f33cef49157178c71c3f86db1c08ee987b8 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Mon, 26 Jan 2026 16:40:58 +0100 Subject: [PATCH 11/14] fix: resolve ES5 class inheritance issues with TreeItem properties When TypeScript compiles to ES5, the `_super.call(this, ...) || this` pattern can lose properties set in parent constructors if VS Code's TreeItem (an ES2022 class) interferes with the object identity. This caused two categories of bugs: 1. `this.parent` undefined in tree items missing `public readonly parent` 2. `this.label` empty because TreeItem constructor label assignment was lost Fixes: - Add `public readonly parent` to DocumentsTreeItem, AttributesTreeItem, and PermissionsTreeItem constructors (generates explicit _this.parent=) - Add explicit `this.label = label` in AppwriteTreeItemBase after super() - Add explicit `this.label = item.label` in ChildTreeItem after super() - Replace Object.assign with explicit property assignments in ChildTreeItem and CollapsableTreeItem - Add explicit label/description in AttributeTreeItem and PermissionTreeItem - Clean up debug logging in DatabaseTreeItemProvider, add try-catch safety Co-Authored-By: Claude Opus 4.5 --- src/tree/ChildTreeItem.ts | 9 +++-- src/tree/CollapsableTreeItem.ts | 4 +- src/tree/database/DatabaseTreeItemProvider.ts | 38 +++++++++++-------- src/tree/database/DocumentsTreeItem.ts | 37 +++++++++--------- .../database/settings/AttributeTreeItem.ts | 2 + .../database/settings/AttributesTreeItem.ts | 19 +++------- .../database/settings/PermissionTreeItem.ts | 1 + .../database/settings/PermissionsTreeItem.ts | 4 +- src/ui/AppwriteTreeItemBase.ts | 1 + 9 files changed, 63 insertions(+), 52 deletions(-) diff --git a/src/tree/ChildTreeItem.ts b/src/tree/ChildTreeItem.ts index 97a2c44..4bc329f 100644 --- a/src/tree/ChildTreeItem.ts +++ b/src/tree/ChildTreeItem.ts @@ -1,8 +1,11 @@ import { TreeItem } from "vscode"; export class ChildTreeItem extends TreeItem { - constructor(public readonly parent: Parent, item: TreeItem) { - super(item.label || 'Please provide label'); - Object.assign(this, item); + constructor(public readonly parent: Parent, item: Partial & { label: string }) { + super(item.label); + this.label = item.label; + if (item.description !== undefined) { + this.description = item.description; + } } } diff --git a/src/tree/CollapsableTreeItem.ts b/src/tree/CollapsableTreeItem.ts index 6eeeb7b..058bc99 100644 --- a/src/tree/CollapsableTreeItem.ts +++ b/src/tree/CollapsableTreeItem.ts @@ -4,7 +4,9 @@ import { AppwriteTreeItemBase } from "../ui/AppwriteTreeItemBase"; export class CollapsableTreeItem extends AppwriteTreeItemBase { constructor(parent: Parent, item: Partial & { label: string }, private readonly children: TreeItem[], public readonly brand?: string) { super(parent, item.label); - Object.assign(this, item); + if (item.description !== undefined) { + this.description = item.description; + } } public async getChildren(): Promise { diff --git a/src/tree/database/DatabaseTreeItemProvider.ts b/src/tree/database/DatabaseTreeItemProvider.ts index ba6f9af..80ed18a 100644 --- a/src/tree/database/DatabaseTreeItemProvider.ts +++ b/src/tree/database/DatabaseTreeItemProvider.ts @@ -74,25 +74,31 @@ export class DatabaseTreeItemProvider implements vscode.TreeDataProvider { ext.outputChannel?.appendLine('getChildren for: ' + parent?.label); if (databaseClient === undefined) { - return Promise.resolve([]); + return []; } - if (parent instanceof AppwriteTreeItemBase) { - return await parent.getChildren?.() ?? []; - } + try { + if (parent instanceof AppwriteTreeItemBase) { + return await parent.getChildren?.() ?? []; + } - // Root level: show databases - const databasesList = await databaseClient.listDatabases(); - if (databasesList && databasesList.databases.length > 0) { - const databaseTreeItems = databasesList.databases.map( - (database: Database) => new DatabaseTreeItem(database, this) - ); - const headerItem: vscode.TreeItem = { - label: `Total databases: ${databasesList.total}`, - }; - return [headerItem, ...databaseTreeItems]; - } + // Root level: show databases + const databasesList = await databaseClient.listDatabases(); + if (databasesList && databasesList.databases.length > 0) { + const databaseTreeItems = databasesList.databases.map( + (database: Database) => new DatabaseTreeItem(database, this) + ); + const headerItem: vscode.TreeItem = { + label: `Total databases: ${databasesList.total}`, + }; + return [headerItem, ...databaseTreeItems]; + } - return [{ label: "No databases found" }]; + return [{ label: "No databases found" }]; + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + ext.outputChannel?.appendLog(`Error in database tree: ${message}`); + return [{ label: `Error: ${message}` }]; + } } } diff --git a/src/tree/database/DocumentsTreeItem.ts b/src/tree/database/DocumentsTreeItem.ts index eb9b01c..929f8b2 100644 --- a/src/tree/database/DocumentsTreeItem.ts +++ b/src/tree/database/DocumentsTreeItem.ts @@ -6,31 +6,34 @@ import { CollectionTreeItem } from "./CollectionTreeItem"; import { DocumentTreeItem } from "./DocumentTreeItem"; export class DocumentsTreeItem extends AppwriteTreeItemBase { - constructor(parent: CollectionTreeItem) { + constructor(public readonly parent: CollectionTreeItem) { super(parent, "Documents"); } public async getChildren(): Promise { - if (!databaseClient) { + if (!databaseClient || !this.parent?.collection) { return []; } - const documentList = await databaseClient.listDocuments( - this.parent.collection.$id, - this.parent.databaseId - ); - - if (documentList === undefined) { - return []; + try { + const documentList = await databaseClient.listDocuments( + this.parent.collection.$id, + this.parent.databaseId + ); + if (documentList === undefined) { + return [{ label: "Failed to load documents" }]; + } + + const documentTreeItems = documentList.documents.map((document) => new DocumentTreeItem(this, document)); + const headerItem: TreeItem = { + label: `Total documents: ${documentList.total}`, + }; + return [headerItem, ...documentTreeItems]; + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + ext.outputChannel?.appendLog(`Error loading documents: ${message}`); + return [{ label: `Error: ${message}` }]; } - - ext.outputChannel?.append(JSON.stringify(documentList, null, 4)); - - const documentTreeItems = documentList.documents.map((document) => new DocumentTreeItem(this, document)); - const headerItem: TreeItem = { - label: `Total documents: ${documentList.total}`, - }; - return [headerItem, ...documentTreeItems]; } collapsibleState = TreeItemCollapsibleState.Collapsed; diff --git a/src/tree/database/settings/AttributeTreeItem.ts b/src/tree/database/settings/AttributeTreeItem.ts index 101a2f9..3b50b86 100644 --- a/src/tree/database/settings/AttributeTreeItem.ts +++ b/src/tree/database/settings/AttributeTreeItem.ts @@ -9,6 +9,8 @@ export class AttributeTreeItem extends ChildTreeItem { label: attribute.key, description: `${attribute.type}${attribute.required ? ' (required)' : ''}`, }); + this.label = attribute.key; + this.description = `${attribute.type}${attribute.required ? ' (required)' : ''}`; this.tooltip = `Key: ${attribute.key}\nType: ${attribute.type}\nRequired: ${attribute.required}\nStatus: ${attribute.status}`; } diff --git a/src/tree/database/settings/AttributesTreeItem.ts b/src/tree/database/settings/AttributesTreeItem.ts index b2b7f1a..e5aaf1c 100644 --- a/src/tree/database/settings/AttributesTreeItem.ts +++ b/src/tree/database/settings/AttributesTreeItem.ts @@ -1,27 +1,18 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode"; import { Attribute } from "../../../appwrite"; -import { databaseClient } from "../../../client"; import { AppwriteTreeItemBase } from "../../../ui/AppwriteTreeItemBase"; import { CommandTreeItem } from "../../CommandTreeItem"; import { CollectionTreeItem } from "../CollectionTreeItem"; import { AttributeTreeItem } from "./AttributeTreeItem"; export class AttributesTreeItem extends AppwriteTreeItemBase { - constructor(parent: CollectionTreeItem) { + constructor(public readonly parent: CollectionTreeItem) { super(parent, "Attributes"); } public async getChildren(): Promise { - if (!databaseClient) { - return []; - } - - const attributesList = await databaseClient.listAttributes( - this.parent.collection.$id, - this.parent.databaseId - ); - - const attributes = attributesList?.attributes ?? []; + // Read attributes directly from the collection object (same pattern as PermissionsTreeItem) + const attributes: Attribute[] = this.parent?.collection?.attributes ?? []; if (attributes.length === 0) { const addAttributeItem = new CommandTreeItem( @@ -39,7 +30,9 @@ export class AttributesTreeItem extends AppwriteTreeItemBase } public async refresh(): Promise { - await this.parent.refresh(); + if (this.parent?.refresh) { + await this.parent.refresh(); + } } iconPath = new ThemeIcon("symbol-property"); diff --git a/src/tree/database/settings/PermissionTreeItem.ts b/src/tree/database/settings/PermissionTreeItem.ts index 41409cd..804d687 100644 --- a/src/tree/database/settings/PermissionTreeItem.ts +++ b/src/tree/database/settings/PermissionTreeItem.ts @@ -11,6 +11,7 @@ export class PermissionTreeItem extends ChildTreeItem { public readonly kind: PermissionType ) { super(parent, { label: permission }); + this.label = permission; } iconPath = new ThemeIcon(this.getIconForKind()); diff --git a/src/tree/database/settings/PermissionsTreeItem.ts b/src/tree/database/settings/PermissionsTreeItem.ts index 509ea1a..fa9ae59 100644 --- a/src/tree/database/settings/PermissionsTreeItem.ts +++ b/src/tree/database/settings/PermissionsTreeItem.ts @@ -12,10 +12,10 @@ type PermissionType = 'read' | 'create' | 'update' | 'delete' | 'write'; export class PermissionsTreeItem extends AppwriteTreeItemBase { public readonly permissions: string[]; - constructor(parent: CollectionTreeItem) { + constructor(public readonly parent: CollectionTreeItem) { super(parent, "Permissions"); // In SDK v21, $permissions is a flat array of permission strings - this.permissions = parent.collection.$permissions ?? []; + this.permissions = parent?.collection?.$permissions ?? []; } public async getChildren(): Promise { diff --git a/src/ui/AppwriteTreeItemBase.ts b/src/ui/AppwriteTreeItemBase.ts index a38ead9..2ddbe80 100644 --- a/src/ui/AppwriteTreeItemBase.ts +++ b/src/ui/AppwriteTreeItemBase.ts @@ -3,6 +3,7 @@ import { TreeItem } from "vscode"; export abstract class AppwriteTreeItemBase extends TreeItem { constructor(public readonly parent: Parent, label: string) { super(label); + this.label = label; } abstract getChildren?(): Promise; From 6dabcad6df88e7b507bd7ab2e2cd05d06cf3f332 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Mon, 26 Jan 2026 16:41:08 +0100 Subject: [PATCH 12/14] feat: make document tree items expandable with field details Rewrite DocumentTreeItem to extend AppwriteTreeItemBase instead of ChildTreeItem. Documents are now collapsible tree items that expand to show all non-system fields as key-value pairs. - Label: document $id - Description: document name or collection ID - Tooltip: document ID, created/updated timestamps - Children: all user-defined fields with symbol-field icons Co-Authored-By: Claude Opus 4.5 --- src/tree/database/DocumentTreeItem.ts | 29 ++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/tree/database/DocumentTreeItem.ts b/src/tree/database/DocumentTreeItem.ts index fe420ee..07e59d6 100644 --- a/src/tree/database/DocumentTreeItem.ts +++ b/src/tree/database/DocumentTreeItem.ts @@ -1,14 +1,29 @@ -import { ThemeIcon } from 'vscode'; -import { ChildTreeItem } from '../ChildTreeItem'; +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; +import { AppwriteTreeItemBase } from '../../ui/AppwriteTreeItemBase'; import { DocumentsTreeItem } from './DocumentsTreeItem'; -export class DocumentTreeItem extends ChildTreeItem { +export class DocumentTreeItem extends AppwriteTreeItemBase { // eslint-disable-next-line @typescript-eslint/no-explicit-any - constructor(parent: DocumentsTreeItem, public readonly document: Record) { - super(parent, { - label: document['$id'], - }); + constructor(public readonly parent: DocumentsTreeItem, public readonly document: Record) { + super(parent, document['$id']); + this.description = document['name'] || document['$collectionId']; + this.tooltip = `Document ID: ${document['$id']}\nCreated: ${document['$createdAt']}\nUpdated: ${document['$updatedAt']}`; } + + public async getChildren(): Promise { + return Object.entries(this.document) + .filter(([key]) => !key.startsWith('$')) + .map(([key, value]) => { + const displayValue = value === null ? 'null' : typeof value === 'object' ? JSON.stringify(value) : String(value); + const item = new TreeItem(key); + item.description = displayValue; + item.iconPath = new ThemeIcon('symbol-field'); + item.contextValue = 'documentField'; + return item; + }); + } + + collapsibleState = TreeItemCollapsibleState.Collapsed; iconPath = new ThemeIcon('json'); contextValue = 'document'; } From acbf46ad893aba87345727bc608117a9e9962995 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Mon, 26 Jan 2026 16:41:18 +0100 Subject: [PATCH 13/14] fix: show project name and endpoint in Projects tab - Use || instead of ?? for nickname fallback so empty strings fall through to projectId (previously showed blank label) - Add endpoint URL as tree item description - Add tooltip with project name, ID, and endpoint Co-Authored-By: Claude Opus 4.5 --- src/tree/projects/ProjectTreeItem.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tree/projects/ProjectTreeItem.ts b/src/tree/projects/ProjectTreeItem.ts index 1ea1976..f6b18e3 100644 --- a/src/tree/projects/ProjectTreeItem.ts +++ b/src/tree/projects/ProjectTreeItem.ts @@ -3,10 +3,12 @@ import { AppwriteProjectConfiguration } from "../../settings"; export class ProjectTreeItem extends TreeItem { constructor(public readonly project: AppwriteProjectConfiguration, active: boolean) { - super("Project"); + super(project.nickname || project.projectId); + const name = project.nickname || project.projectId; + this.label = `${name}${active ? " (Active)" : ""}`; + this.description = project.endpoint; + this.tooltip = `Project: ${name}\nID: ${project.projectId}\nEndpoint: ${project.endpoint}`; this.iconPath = new ThemeIcon("rocket"); - const name = project.nickname ?? "Project"; - this.label = `${name} ${active ? "(Active)" : ""}`; this.contextValue = `appwriteProject${active ? "_active" : ""}`; if (!active) { this.command = { command: "vscode-appwrite.setActiveProject", title: "Set active", arguments: [this] }; From fe85383c3d67e7ef31bbebdef985df6d738c6119 Mon Sep 17 00:00:00 2001 From: Roberto Boero Date: Mon, 26 Jan 2026 16:41:30 +0100 Subject: [PATCH 14/14] chore: update build config, icons, and remove legacy code - Add NODE_OPTIONS=--openssl-legacy-provider to webpack scripts for compatibility with modern Node.js - Update webpack config: externalize node-appwrite, add Node.js polyfill fallbacks - Update AddProjectWizard for SDK v21 project setup flow - Replace extension marketplace icon and sidebar SVG - Remove legacy createRuleWizard (rules replaced by attributes in v21) Co-Authored-By: Claude Opus 4.5 --- README.md | 2 +- package.json | 6 +- resources/AppwriteIcon.png | Bin 10672 -> 1269 bytes resources/vscode-appwrite.svg | 14 ++-- src/ui/AddProjectWizard.ts | 24 +++++- src/ui/createRuleWizard.ts | 140 ---------------------------------- webpack.config.js | 25 ++++-- 7 files changed, 53 insertions(+), 158 deletions(-) delete mode 100644 src/ui/createRuleWizard.ts diff --git a/README.md b/README.md index eddf2a9..2bedb59 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Use the Appwrite extension to quickly monitor, manage, and interact with your Appwrite instance directly from VS Code. -[![Version](https://vsmarketplacebadge.apphb.com/version/streamlux.vscode-appwrite.svg)](https://marketplace.visualstudio.com/items?itemName=streamlux.vscode-appwrite) [![Installs](https://vsmarketplacebadge.apphb.com/installs-short/streamlux.vscode-appwrite.svg)](https://marketplace.visualstudio.com/items?itemName=streamlux.vscode-appwrite) +[View on VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=streamlux.vscode-appwrite) ## What is Appwrite? diff --git a/package.json b/package.json index 5019e78..56622cc 100644 --- a/package.json +++ b/package.json @@ -737,9 +737,9 @@ }, "scripts": { "vscode:prepublish": "npm run package", - "compile": "webpack", - "watch": "webpack --watch", - "package": "webpack --mode production --devtool hidden-source-map", + "compile": "NODE_OPTIONS=--openssl-legacy-provider webpack", + "watch": "NODE_OPTIONS=--openssl-legacy-provider webpack --watch", + "package": "NODE_OPTIONS=--openssl-legacy-provider webpack --mode production --devtool hidden-source-map", "test-compile": "tsc -p ./", "test-watch": "tsc -watch -p ./", "pretest": "npm run test-compile && npm run lint", diff --git a/resources/AppwriteIcon.png b/resources/AppwriteIcon.png index ad5860e8f7624eb462e8825293a2932f8627deb1..5d993a6b337b7f9df297863bba24b97defed7861 100644 GIT binary patch delta 1256 zcmVK#t&9b;LQo5JouxKcG^8_qXG+9?R+dN#IK6tOIp?Z zr@ObOyBBz5xgi9GTS)_7(2yUS&}d|gMno7v$(P|L3~A6G;hyj=0Do^MO+CqW5vg@B zTJo1>@tZIrMMGwOqm&xZ-~9n9!ixa;E`QQpCThtdT5u-?(LfO$i5MvY;v_)6+ss{P zZp)P#2mpx?^i7BX0$?S;<&JAc5^CW;A|kw&uLIu}QCa}m^_JHBVlLkffC74SesTm) zloEh9yU#Uog8L_xV1K#e!y4uiz?eLL=2K4r&KGGGtG(5~`a?KSC_oZnsJM7rFgSz!UANg=W7H?=o6Mbqd z7A3h+0N&~x)+E}Op(#Q71xhmG0^j^zf54(bd=S0;vp?_4XMZe!HJ@UUVLB}13h~un zCYwo{p?&-PNb*>T(E1v$% zOFe#FGACFtq6&BaN`u8Kv8=rb3z+Z*6_S0#u9rmZ2b68}Cx%lkt}Ic60Ro_4iMUOQ z3JKLAvKJtVQak{x1)wZz;sIbSK-KU@5~KxZ1h7hB<@Q-=!F0T4ceg4+1Ry&BK5#~l~ z=Mvd%sOTadz@BC%>$sIt%tROfw}! zKr}5n=@|s^{Y&zam`O79s{RiS$Zc^*YqaC5G=KKJQq@Lare$&cw0q`Z0>sxl# zVbjHdJ7(A38`H&taIH1w$qFt>MctQB>Q$XB;+g>C?WCo&K7)T!xzh~UOn@@~j~X#E zA28nR^rcc-O@dPcW{$)0SoNgdonlFt5x^uynrI(O!i@zH)7m!8PAma;&Iv9H3-Nsx+(Uo^6$wQ3^rN-qa+euq0Gl#wgnd*Se0~6i` znd*S`GeZx>8l0aRGeRiM-31z~zJ|Bw1}`>~4Jk1vK8GEvAjp%WMvO>hEoKr?=odL+ z8|$d9hfspxkIr5t)Re~~kJ$4Sf>ZB)^eJU3rvLx|4rN$LW=%~1DgXcg2mk;800000 S(o>TF000038ad-CsVF{Yx1X$c%6LfJ45IndB4Y0TcC$K{DJ#k8002mcTO(@$V;Qf#Znqg z$>(Di7JfBQD=&8hk&?v3Fk6>?d0%FF0%>!+4cgC}ZLvQ-l9cN1_N@9~6>%WCmp2OR z=fVB|cG&WRO4KCMuIcvWwnF^1l8GfKK)zb|JHZ|$-1=Tnd7hGhr^;1}eQpZ;+W~(_S_Os|;2}ss8805V z9Skc_F;8EXot3WWE!FX!73N_0jNC0PB})yhgnT<-5yN^Rj4JrpH@m}&3TrgnER{s$`3~j@AEGR25oN}wcnfeE{U<;EX1ESO7 zXtTN+4v*;E98!VFF0l>-wue6OE+avMr%mC=a8MLT3+Oh=Kgx*hKp$>UI5jP8v@D%V z&Q#Fy$U^9ujSW>}!VSRV49_UgV7nhx;+^=fCH%}7mQE<31(cs4_X17I5J=Ce^Vt0c zc&Y^4cM;C*w`w`EnnIT%ZlLn8*mB)0&tXd5K_qChj#MD&rF|4=#woH5^9D3F1$G!L zn1X6J1YP>WfpAJzj-j~gpbt*0({1#gDh;^JL)Y}I!2M07*V3~D;{$H|`e62dl5j?T z6QEc*#VlLrCU;~_#CJ*QWn!(CLpHGFfrt6`fzri!#J{Fzr){Iww7lqGj$Gi6XIxQh z7PI>0;k=JiFySbLt8Z-u!Tolyx9y_HD$!*OsKX%wygBOXPXsf6wIN2m=W{*~^YDf~m!a*sz8x$L_N z8T|CZ?_wL6z}eN04sTBYR=51f0q;C;m~T7%W~S-I z<6d}}ceFJV$avy9jqu__NuVsN83QT!fC$ZiheHP7&bC{A9p5bHPrO1Z6d=bB(hPS1 zPoPOzH)^5hU))qSf6VwGk{`2yC}Y9^O35cKel!7`!s;U2R0kM)A2mZ(Ow)jYt19A| zRQ&18`*bOpjDH!kpyRWlhqk4gsmky{W3ES^AZI47~j5E1Xk#^m7o;{y)u z@l9b=sWQs-ZRyHifpn>OT8101gprmL{=9Dl+k~FYT+(&kRTG_4E6BNvf=;Jg`x*NE z4h=ZsoW;5p+P&5`58Q7PTlpdc9Ml8M^~_(u*)WWJkK~eIaqWL%MEhrM$nqx4pcO}2 zp9Ba~YP44722eP7XlrS=Or8dSo1d^+D9{6oG4_&K_9zWIN<4T&AMWWS9Rd1V%`AuG8s)F$TBbf6>#nkW6!XS=K z)GW`+AI7wRxP1K7TPb*>kxT;<6J~`Frn%)7eC~p6JSiI|!$LDsY7u$XGI^~oz}4pP z`ke{?G69jyn=6*rd_HJE{5M*}lco6|+yUSYkHX^y!Xpk>N$_udaC_L;RhGxWq==Ze znf4E-nEimeU1lDiO5L5m&7n+`TpaARAxz~|dba-va<|>+a(d={1Uva-QG(89fPv>O z9$PLK(laigH0+iyB^jCS^mz;SYdP7U>^t<$o66NskD5aHTMn@~X(W*HSzY6sr98wR ztq=;-O){8123S3Mh!RvsyL7drrTxtsY5?8rPI8+`L?+Bm_>4x5kG^X@7M^3}pf8hu zRd()CcvKJ!58n4ec5r6q32ejMQZHBh&akRvT+nL9aaGv2f@7KgWT~H}uV?0^8R)ZW zSkz<%2hJ)|$VrMPf-S*g*UE0l9ucx8O4B=^lV@Er^o@L}eBmNnex&SnWMV026A80yQ@A`QUL0jzR6u$PJfD7&dg zwh43RG9`=o`7_-sigX`D*7nL)?yUwrNGOFzDnxQ+P6zZFM=J`AszKiyA^KsML|53}X& zqR@_*@&j5)uT;edOwUCVcQ8FK`ef|@POqh?vG9Q3u=}2M6tfNNDY`^% zX!Qpg0mm~K&$>Q1;5q1Du6iqCUSvVv3_lmr_+#V^3^K+7&gRwkXdf8uqSw5-aj;+b zsz#ou2E~zOT}Cs-yw*aZoYG#SPU0Ko#}j&@scbJrOr>E4DLjn}KIDjCGalta~Rvn2-=sfPFD%>~kLbFF zo%}4qyUM7#*ZfKlv#C9T*>=C?0-~N5>0PRB>wj(@`{K#*>lQx~#4kUM|1DNEr*ypd z66Mrvao~veI4?TMQDM@Ky(8*>-EX45x# z(E#}9vBjAp3E_R&L}>eq#7T{+uhCM(&bs?Ajn4EF1I~}9cd_#kP8m)u8V4SLQ-(%5 z|M!UDqIW*I@BNh$?OLjleE)lB?&Yf?jLgTV$eoIcgHL^l;(~FWvb`HT zABj|4;EtkmQ3&5W_(S(}mIEnC8t0qh8cZkwKg07^(Z21#KLP)=J@%+l8GriGK6dPS zz%F@g%r%0*1`LdzB0*DHqlyu~qU3~r210H*^Qb3wByG@>Z#L%a{0_HTvlvCNe{k9M z+m2x=!vTc6jq>M_K3wvJ+HBaJ-n-m%52@_dyqGu9L!Hpp+>@%eHtG|R>Mh!nUy@Jp z5?$%SZLP&KUqw9j`Q9?Vp%9lm6Vgu+NTZV|?KUtEFiEj#Sv6s;{|WAYzmh+BLeH~l zM#cIiMbrSPU7UXHmVz)TsA~URz-bhPfF_)etT5O zT!krlF-qj~kjhsbA3Qv4n54bpD1nk-9F70CjD5_Az=Tk)xsxKArU#8(Jw4Z?M$B>H zVQh5c8L2T3qG)Zt6r7oT#7wkr-P=L3 zEO)vlihg7p*~l*yq5bPu)+|+JHn<^rT^`w}^iz3Amv6k!`oRn3Iv$`A`kQhDui&gZ z*?p$f_)f6g;xwg)y314t!;10{JHJ(AyHx(-guc`G!iW5V4rvV3tS;D<9YEWom0lXb z*nOEJ0Cz|q6AhW{oJR?E+X|jtTvR%?XV3fumptj`CH@;OGjGRDy?z8B1j5v%6bIee z-pl1r?6yCIlOEX$=Xg9d;YL{MB~nFR{E!vIZi%gRZ{Sj7Gfk|sN0oMbG5tlKjSmd$ z@$_GRqbJCbtUuQuR&zpa{%h(gcS5$^RjW0Q>12%~#P6{1p}1E&NS={;y;I0)Qo*lY zMHhJu(z@0xuxgmmG+b$Ac=?iw3mCR+D*p|?C&J$og;O9@jbVO3&9n<3B-XMy(wt-? zibwa%KbiZp5@BC`bCd7!^sMA%c-j^9*kOpBp)m@-KkE{`5L2f()X%7+drBWaNdS~< z!pd>bhzk$XbtsGjENBYz1$imeL{ndJRLxfm#VPoR<2dxDj`GfjI7!T})_wx4GPYfC z>l^&d@l-K5xsP>O_D8rQacwbw9J~EVp7E#Nh_%wIo2>rcJ#-V2de8d1ReXjkrtYGM zf);j@?5j7=VXtOi48H{snaURkaU_6la{M0+v(nZPt|ReY&~h7)pzVOIwB?*WqVhPD z;1KF3tZ(PYcrNaU2qMt*1&cme3K_+Obg*>rEY=S=S#Tdoq~!GUrYU1(rUJd>#Zz;I z+q~E_dfRqiWb^&ep^Ko%%x_o3PpRyiKUr*>T0@SHs8=&-m9!IVf9xn$KiukzcM&J)QFKHl_TKa2bet8C3iKk5?$e$6af6n$kJ5derX0s9GSAP)m zdpN;pDoaUA;{7PJ&E4+fm0+M9fD`xPWxL0cZml+d<9L<2)}XrTU9G$%Y5Za-oNK+E z>D*oEgsa$+K<|hjfEg!#Hpzl@g#Y;Xg?Xjto3#r9&W1Z%1A?_V|2uE)KOL=6>S7luaezqwb* z*6gO#Wj6Agjtw`CzXW*l=b=F%e#c!p5rDe2gvoLZYq%?jrb-8 zjBx7jG%hy>N>Oxz6<+uw`vo6Xs-Dl%q5`kB|MF^mVgiEAZ_1vqw>$KA{)!)%KevcJ z94FA_u6#@eZ@Hj41BlZ|;COk30#fJPi?v2sD$*TLnbaeat z#Zqg>um1gJs(Q3MU^guN2gQ}GgUXjgam|eM^`Ip2)-zQqGBn?d)zF7Y_WRGDLNku~ zjAun%tI;<-P>E<~Mc!C69`|Zq;X4m**q`XhH!;2;jK|08zS&sFLIun{$?c$UOQ zVmTQ_Ng{{z75v!!XG!8u>>QD%T7({P5~B$Yn2Y0}llO6JP20sG^4p_&4xPeZ=x5O( zf+Kej>Cv#K7deC@85NuudT`>F)z~$Ln=tcQRN-oHwOd6r~VT)&FA^>fnMbTXw@6xO9z4mm0Cp@LlARLeBb_@+4K4+S3BE)6WflW0&dU;%duE z^T}iX7CJhw+S|XNJf8jXbNEbcq1a&Pgt3E{GSAj&Rixg3RzgD`EOLo|6c|LJB{KM) zGzH~!Fke?1NG&0hr(gX!qtNO0A4(j(Aoo-;yd;KLcI+$D)Tgc%a{hZtckQHgzNHky zO)sj!i4+C%IGvxL6^t%+|5WdX%p)_Om|$r$c%yw#6naeZzpo4bMEB=OY{Wj)DE%vn zQUK3L(&dd2{!5T!Y@uZ!gg&l4(O`j)CD#U4J#!^*DLz}A8^^2lj(>l>_RzI$QnGbw z0di+B8M`s=OMQRuSqtzGJ^!1Kf)+eemQ$|sHhg&etY73joN=Bx6IaN0eeM{O2zD;< z0y4Sz$Zx*zH-k1)&+I|E=&?Demndn8(o>AvJPCW>Xq zrWaRgx_(AS8q@jsP2i@R?G+sn&Nd@PQr%%=fGamo%v$?{L&s*>rgNJ**@6OQ=6CFb z*p8e1fy!(;S3Q1`yU#YX+%P$5oGvfH$~UoJD7(|eL)RO-l5K*X+tTvyq%WiZZ}GwjlImgQZaGjm%zI31;wJlV+JjrHUG^AQ)P&*lC1 z4zJvIc%d}XtEOgrQ5_->ynPJsZ9 zBhv78pwi!il7Eko#^iLFWj}w>`jK`!(4!&gj+rUK2G0Xf$or;_0HRzPe<@>$USU{` z+&y?~KHcDvy&Cc?+Vv2Ra5C3`#=hmur>7LZLrt%ZA6iu`LJ=col#{#oiC9Ec(<~cc zj*pF37Mzr&?ctIc!A@F#)BrP6?G+&id74r3ggkv zs#_g1Pj}Tr_PJ!6Yp$MG{uLP8C_$cn2IiY?@&`~4pE|O@lwCrQnjcV9sv1f6c;zH31 zs#O0#qlFvlE&TT)7+I`;`k`( zW9XYb=u7@1a?)c?e*X#N_u)EH+qV;BEx@vwrbZYf_>R_-*&#KDfSMW4I4DPKg? zX|uAL39;o*m18Xqb%ZR8J?L{4C(0rTok#k`mQ{sKGEbttZULDRl{Ge@+CIrT? zDkU*{T07Zb)$Q_5QKo*EjfjZ($-sj>bA&HF%2ZOXjf(y4~&}${4nXb^9+s4C$Mx5=n1oO5eUDk1TZsV&50O`_Eo>)(9$_&ihT;{S^82BHwxjOkcX z8mr~JZ#|y$qQCxaE-hEE1mj>!3y~!Z0qrin8c?sPK`s#n#<@o@_Hk-u9#vy?H~oddk143@vxIx??ISHDNAAdFVy zxc_`s%|2vHly1m<9yagasFTWj=RBgO3MznT$^q&e;ogdX%ATARJC7l>xtYuh;OSdt zL@10xgqBxaA9r#F9~rkV*nglL)iEms1)Cj)d&I+2f&-J)#m9nlxR|(I$9g`A4}Q=~=$Lf;_x4-)eh9_05k>vx!**g*#TbKw zeYS(p)TkA_54NlsSXQrwPH6FRC1S!nN&zvV7A+9n=b9_V2QZ@0Qj1IFsnTwGk;!#G zeENKPo#~S&jKWGU*xsPM)vf9df4puHyhumXV7ihX(S|!zxo~~8ug>);DrjtUD@(=q zqx{=H6}pKw97rlrgPI@SKfZhCDGKnx7hUsnK~#;}V0LzMo@AMCHzI6o`Wz)GzlSq* z?5^Mc))&l4i|`N91nts#Fvc@6SwbN0e}De^L-vD_%!ba%`QN#wJbZHR$(Xv{xPDc% zVgacqRFCl++2l7Qd8Bj-`R<3{8?42+%Cncx5$jLjnAeSQ5;yNcf2uFJBBL1C0V^3GkXcblF-MpLFvn{=_V|AVMR>q*bwaH7yV(W3_c()OpsVDc25nokeC*H zjy9*8w?Sqr*t72H53w1V=q_5%KWmX%qRG0+FGbYbfO7kTgWOYfP2rnem|20w@+EhE>^OIc0UZnAolNQ)0ou z?33%@`dcSO75vWc`nREz$Nfyy-B*k&%+$_2h&tx!TaSXC&a)f`(y@aBwkh@ONqyhJ zSEz{Oj?CpoO&q^>Map8>=-U_TqIi>*nMKT?pJ?}t&tPH@DV1r96s52o?FozWb9h`>UI48E_R2Xt*d2rRK6cv zhRxm)c06VK*V?la0X)&*7?aU^zr)*52AkJ2FebkGMXZLzOVBjq-nE?aPV+c3OX<#%yfJdB7KXb`Z0p-I zDVbDl{@sb2Ma^`zU=Rg<8hja+q+@{7@}+gHZuJVG1dYsw5#Zxc94$jt<%!&{XF3h( zbY8)rxMwxWmjfR`0kx-{P1G9sdWJkz6rE{vl-lS&e;fl&Rvp%;(2V7*Hki%bMY;K# zor-$9LiOI+&=2QQW{tJZPE|b7oLtN}BqFDxc3kE9 z91;jLzX+0C&8Nx+n%3jCVY)(ey~j&SSYX4vDSHLGM!zpohsSbbU3!_qtL!oKs1Pa0 z|HhaYmtp-wK1(FPGbxNgOY+Gq#bpaLH{|MM7>(VDk&Gw;;u`GypAc8Om!A}5B<#DC zDFcs>3iUogT-sd06kPBqze_VqnJ-^9)ap@e+t^*%u_1^A9u?MMm}n%^mRt{VZ_QhX z#oiQNSX}lN;(-N)Oik7C>Y-fa}tZ_&v*vztz@4t@;+N` zEnULi#-nOL`BDs_yY0ZZQrvJ>gg>fq3hh~_Q_$b8te83~wM1?Cbh}PWxFX%P? z|AJoEp)UhyKbcA+f{ud+RHfA`GD`~A)5LP*4N}{b({FBVO%q| zTW13`K@Mb?NK3=^S1GJ0^(MnR`s5e;%p zb`woV(k_a}O`F4AmM5B^56Rb!JNZ-|t8*)mPwNx}cBu6=JQhGw? zH~n*qHP)mchtg;SCxXL`kos-W=|N0Zx1{%`=wtCb1tDOvS!Kdi1v3phTpOEmJk4;8 z`m8gOj08m@Jer6weCZ92eo8UWkk?eaM0{Iqtw`M^O=_iZTf$?l*7Ab9JtIFu(-555 zhIrPXVtm>!a11DAolV3hpero|jSKf-F*|@6=$gdIJ6nkkD2A2bhd+4Bx?A67Q0`O_ ztl%m46TzC_1L>j0D3YUXXHLPppjeoajm_I~-OuHQpdBkQEvgw-@EsRzs5j2R?4Rt0 znYbewX*_VF$280qo=8ZKZz8qA2-Gx=Qph^>pqgdN-QoupuH>)iQ0cyr0gHH0AIxU# z=`7D9%?2ra5l+D(_NRy7a~3XtiSKvkB4(?rqqBPFF5 z4Bp{2qMKj^L=7qz-De;nm`3Qc>QFdTN^UB1F87}%VJ=WTbFm{f!q-m4|7ikB(KlpG2z8Z(J;CKONrB3O20<;l-s=pR+`C07w#rr$w1>>`HC3o?8H zdSyq@j6z}rX|411j#9$q$U8+L;RbkT5VC*WA7WnBt&uDRH%)_a6Wl - - - - + + + + \ No newline at end of file diff --git a/src/ui/AddProjectWizard.ts b/src/ui/AddProjectWizard.ts index 8e4d84e..b86345f 100644 --- a/src/ui/AddProjectWizard.ts +++ b/src/ui/AddProjectWizard.ts @@ -47,8 +47,30 @@ export async function addProjectWizard(): Promise { - const label = await window.showInputBox({ - placeHolder: "Attribute label", - prompt: "Attribute internal display name", - validateInput: (value) => { - if (value === "") { - return "Label cannot be empty."; - } - }, - }); - if (label === undefined) { - return; - } - const key = await window.showInputBox({ - placeHolder: "Attribute key name", - prompt: "Attribute key name. Used as the document JSON key in the Database API.", - ignoreFocusOut: true, - validateInput: (value) => { - if (value === "") { - return "Key name cannot be empty."; - } - }, - }); - if (key === undefined) { - return; - } - const ruleTypeItems: QuickPickItem[] = Object.entries(ruleTypes).map(([label, description]) => ({ - label, - detail: description, - })); - - const typeItem = await window.showQuickPick(ruleTypeItems, { placeHolder: "Rule value type." }); - const type: RuleType | undefined = (typeItem?.label as RuleType) ?? undefined; - - if (typeItem === undefined || type === undefined) { - return; - } - - let list: string[] | undefined = undefined; - - if (type === "document") { - const databaseSdk = new AppwriteSDK.Database(client); - const collectionsList = await AppwriteCall(databaseSdk.listCollections()); - - if (collectionsList === undefined) { - window.showErrorMessage("Could not get collections list."); - return; - } - - if (collectionsList) { - const collections = collectionsList.collections.filter((c) => c.$id !== collection.$id); - const qpItems: QuickPickItem[] = collections.map((collection) => ({ - label: collection.name, - description: collection.$id, - })); - - const listInput = await window.showQuickPick(qpItems, { - canPickMany: true, - placeHolder: "Collections which contain valid child documents for this document attribute.", - ignoreFocusOut: true, - }); - list = listInput?.map((item) => item.description as string) ?? []; - } - } - - if (label === "document" && list === undefined) { - return; - } - - const array = await window.showQuickPick(["Primitive", "Array"], { - placeHolder: "Decide if this rule is a primitive or an array of values.", - ignoreFocusOut: true, - }); - - if (array === undefined) { - return; - } - - const required = await window.showQuickPick(["Required", "Optional"], { - placeHolder: "Decide if this rule value is required in order to pass document validation.", - ignoreFocusOut: true, - }); - - if (required === undefined) { - return; - } - - const defaultValue = await window.showInputBox({ - placeHolder: "Default value (press Enter to skip)", - prompt: "Default value for this rule type. Make sure that the default value is able to pass validation in order to avoid errors when skipping optional values.", - ignoreFocusOut: true, - }); - - if (defaultValue === undefined) { - return; - } - - if (label && key && type) { - return { - label, - key, - type, - default: defaultValue, - array: array === "Array", - required: required === "Required", - list, - }; - } - - return undefined; -} diff --git a/webpack.config.js b/webpack.config.js index 538f0ac..8d7a612 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -6,22 +6,31 @@ const path = require('path'); /**@type {import('webpack').Configuration}*/ const config = { - target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ - mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') + target: 'node', // vscode extensions run in a Node.js-context + mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') - entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ + entry: './src/extension.ts', // the entry point of this extension output: { - // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ + // the bundle is stored in the 'dist' folder (check package.json) path: path.resolve(__dirname, 'dist'), filename: 'extension.js', libraryTarget: 'commonjs2' }, devtool: 'nosources-source-map', - externals: { - vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ - }, + externals: [ + { vscode: 'commonjs vscode' }, + // Externalize node-appwrite SDK (uses modern JS features) + /^node-appwrite/, + // Handle node: protocol imports + ({ request }, callback) => { + if (request && request.startsWith('node:')) { + return callback(null, 'commonjs ' + request.slice(5)); + } + callback(); + } + ], resolve: { - // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader + // support reading TypeScript and JavaScript files extensions: ['.ts', '.js'] }, module: {