Base Command
The BaseCommand
class serves as the foundational building block for all operations within the DID Spaces SDK. It establishes a common structure and provides essential functionalities that all specific SDK commands inherit, ensuring consistency, security, and ease of use. Understanding BaseCommand
is crucial for grasping how the SDK interacts with DID Spaces.
This section delves into the architecture and core methods of BaseCommand
. For a broader understanding of the SDK's foundational elements, refer to the Client and Security sections.
Class Structure#
The BaseCommand
class extends Node.js's EventEmitter
and implements the CommandProtocol
interface. This design allows commands to emit events for progress or status updates, and ensures they adhere to a predefined contract for input, context, and request execution.
Constructor#
Each BaseCommand
instance is initialized with input
and context
objects. The input
object contains parameters specific to the command being executed, while the context
object provides global client-level configurations such as the wallet
, DID Spaces endpoint
, and an abortController
for request cancellation.
constructor(input: BaseCommandInput, context: SpaceClientOptions = {} as SpaceClientOptions) {
super();
Object.assign(this.input, input);
Object.assign(this.context, context);
// Auto-configures componentDid if running within a Blocklet component environment
if (isValid(process.env.BLOCKLET_COMPONENT_DID!)) {
this.context.componentDid = process.env.BLOCKLET_COMPONENT_DID;
}
// Initializes abortController if not already provided
this.context.abortController = this.context.abortController ?? this.input.abortController ?? new AbortController();
}
Core Methods#
BaseCommand
defines several key methods that underpin the SDK's functionality:
getAxiosRequestConfig()
#
This is an abstract method that must be implemented by concrete command classes. Its purpose is to define the AxiosRequestConfig
required to make the HTTP request for the specific command. This separation allows each command to specify its unique API path, method, headers, and data.
getKey(key: string, options?: GetKeyOptions)
#
This utility method constructs a properly formatted key for objects within DID Spaces. It's particularly useful when dealing with componentDid
to ensure keys are correctly prefixed for component-specific storage.
Parameters
Name | Type | Description |
---|---|---|
|
| The base key or path for the object. |
|
| Optional. Configuration for key processing. |
GetKeyOptions
Properties
Name | Type | Description |
---|---|---|
|
| Whether to URL-encode the path. Defaults to |
Returns
Name | Type | Description |
---|---|---|
| The formatted and optionally encoded key. |
Example
// Assuming 'this.context.componentDid' is 'zNKabhhwdvVmXjtRTtSHk2YQz4pdDPStV289'
// and APP.COMPONENT.FOLDER_PREFIX is 'apps'
const encodedKey = this.getKey('my-file.txt');
// encodedKey will be 'apps/zNKabhhwdvVmXjtRTtSHk2YQz4pdDPStV289/my-file.txt' (URL-encoded if necessary)
const rawKey = this.getKey('my-folder/image.png', { encode: false });
// rawKey will be 'apps/zNKabhhwdvVmXjtRTtSHk2YQz4pdDPStV289/my-folder/image.png'
// If componentDid is empty, it returns just the key:
// If this.context.componentDid is empty or undefined:
// this.getKey('global-file.json') will return 'global-file.json'
This example demonstrates how getKey
prefixes the provided key with the component DID path and optionally encodes it, which is essential for correctly addressing objects within DID Spaces, especially for Blocklet components.
request()
#
This is the core method responsible for executing the API call. It asynchronously retrieves the AxiosRequestConfig
from getAxiosRequestConfig()
, performs the HTTP request using the internal api
client, and then processes the response through resolveMiddleware()
.
Returns
Name | Type | Description |
---|---|---|
| A promise that resolves to the command's output, containing the status code and data. |
Example
// Inside a concrete command class extending BaseCommand
class MyGetObjectCommand extends BaseCommand<GetObjectInput, GetObjectOutput> {
async getAxiosRequestConfig() {
// ... logic to prepare config for fetching an object
return { method: 'GET', url: `/objects/${this.getKey(this.input.objectKey)}` };
}
async execute() {
const response = await this.request();
console.log('Object data:', response.data);
return response;
}
}
// Usage example (simplified)
// const client = new SpacesClient(...);
// const command = new MyGetObjectCommand({ objectKey: 'my-document.pdf' }, client.context);
// const result = await command.execute();
This illustrates the request
method being called by a concrete command, abstracting away the HTTP request details.
resolveMiddleware(res?: AxiosResponse<BaseCommandOutput['data'], any>)
#
This method processes the raw Axios response and transforms it into the standardized CommandOutput
format. It ensures that all command executions return a consistent data structure, regardless of the underlying HTTP response details.
Parameters
Name | Type | Description |
---|---|---|
|
| Optional. The Axios HTTP response object. |
Returns
Name | Type | Description |
---|---|---|
| A promise that resolves to the standardized command output. |
abort()
#
This method allows for the cancellation of an ongoing command execution. It leverages the AbortController
instance associated with the command's context.
Example
// In an environment where a command is running
const controller = new AbortController();
const command = new MyLongRunningCommand({ /* input */, abortController: controller }, client.context);
// Start the command
const promise = command.execute();
// Later, if you need to cancel
controller.abort(); // This will trigger the abort signal
try {
await promise;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Command was aborted.');
} else {
console.error('Command failed:', error);
}
}
This example shows how abort()
can be used to cancel a command, which is useful for long-running operations or when a user decides to stop an action.
Interfaces#
BaseCommand
relies on several key interfaces to define its behavior and data structures:
CommandInput
#
Defines the common input properties for any command.
Name | Type | Description |
---|---|---|
|
| Optional. An |
CommandOutput<D = any>
#
Defines the standardized output structure for any command.
Name | Type | Description |
---|---|---|
|
| The HTTP status code of the operation. |
|
| Optional. A message describing the status, usually present on error. |
|
| Optional. The error stack trace, usually present on error. |
|
| The primary data returned by the command. Type |
|
| Optional. The raw response object from the underlying HTTP client (e.g., |
SpaceClientOptions
#
Defines the configuration options for the DID Spaces client, which are accessible to all commands via the context
property.
Name | Type | Description |
---|---|---|
|
| The Blocklet wallet object used for signing requests. |
|
| The DID Spaces API endpoint URL. Example: |
|
| Optional. A JWT token certifying authorization to access the space. |
|
| Optional. The DID of the Blocklet component, used for isolating component-specific data. |
|
| Optional. An |
CommandProtocol<Input extends CommandInput, Output extends CommandOutput>
#
This interface serves as the contract that BaseCommand
(and all other commands) must adhere to. It specifies the input
, context
, and request
method, ensuring a uniform API across all commands.
Conclusion#
The BaseCommand
class provides a robust and consistent foundation for all operations within the DID Spaces SDK. By centralizing common logic and enforcing a clear protocol, it simplifies the development of new commands and ensures predictable behavior across the SDK.
To see how specific commands leverage BaseCommand
to interact with DID Spaces, proceed to the Commands Reference section.