diff --git a/docs/keyring-core.md b/docs/keyring-core.md index 473f0274..4c182db3 100644 --- a/docs/keyring-core.md +++ b/docs/keyring-core.md @@ -5,7 +5,6 @@ ```sh npm install @w3ui/keyring-core ``` - ## Usage ```js @@ -14,138 +13,161 @@ import * as KeyringCore from '@w3ui/keyring-core' ## Exports -* [`loadDefaultIdentity`](#loaddefaultidentity) -* [`loadIdentity`](#loadidentity) -* [`createIdentity`](#createidentity) -* [`sendVerificationEmail`](#sendverificationemail) -* [`waitIdentityVerification`](#waitidentityverification) -* [`registerIdentity`](#registeridentity) -* [`removeIdentity`](#removeidentity) -* [`storeIdentity`](#storeidentity) +**Interfaces** ---- +- [`KeyringContextState`](#keyringcontextstate) +- [`KeyringContextActions`](#keyringcontextactions) -### `loadDefaultIdentity` +**Classes** -```ts -loadDefaultIdentity (): Promise -``` +- [`Space`](#space) + - [`name`](#name) + - [`did`](#did) + - [`registered`](#registered) + - [`meta`](#meta) -Load the default identity on this device, returning `undefined` if none exist. +**Functions** -Example: +- [`createAgent`](#createagent) +- [`getCurrentSpace`](#getcurrentspace) +- [`getSpaces`](#getspaces) -```js -const identity = await loadDefaultIdentity() -if (identity) { - console.log(`DID: ${identity.signingPrincipal.did()}`) -} else { - console.log('No identity registered') -} -``` +--- + +### `KeyringContextState` -### `loadIdentity` +Interface for keyring state. Implementations are framework-specific and found in each framework's `-keyring` module (e.g. `@w3ui/react-keyring`). ```ts -loadIdentity ({ email: string }): Promise +export interface KeyringContextState { + /** + * The current space. + */ + space?: Space + /** + * Spaces available to this agent. + */ + spaces: Space[] + /** + * The current user agent (this device). + */ + agent?: Signer +} ``` -Load an identity matching the passed argument from secure storage, returning `undefined` if not found. +### `KeyringContextActions` -Example: +Interface for keyring actions. Implementations are framework-specific and found in each framework's `-keyring` module (e.g. `@w3ui/react-keyring`). -```js -const identity = await loadIdentity('test@example.com') -if (identity) { - console.log(`DID: ${identity.signingPrincipal.did()}`) -} else { - console.log('Not found') +```ts +export interface KeyringContextActions { + /** + * Load the user agent and all stored data from secure storage. + */ + loadAgent: () => Promise + /** + * Unload the user agent and all stored data from secure storage. Note: this + * does not remove data, use `resetAgent` if that is desired. + */ + unloadAgent: () => Promise + /** + * Unload the current space and agent from memory and remove from secure + * storage. Note: this removes all data and is unrecoverable. + */ + resetAgent: () => Promise + /** + * Create a new space with the passed name and set it as the current space. + */ + createSpace: (name?: string) => Promise + /** + * Use a specific space. + */ + setCurrentSpace: (did: DID) => Promise + /** + * Register the current space, verify the email address and store in secure + * storage. Use cancelRegisterSpace to abort. Automatically sets the + * newly registered space as the current space. + */ + registerSpace: (email: string) => Promise + /** + * Abort an ongoing account registration. + */ + cancelRegisterSpace: () => void, + /** + * Get all the proofs matching the capabilities. Proofs are delegations with + * an audience matching the agent DID. + */ + getProofs: (caps: Capability[]) => Promise } ``` -### `createIdentity` +### `Space` -```ts -createIdentity ({ email: string }): Promise -``` +A subclass of ucanto's `Principal` type that represents a storage location uniquely identified by its DID. -Create a new identity. +A `Space` has the following methods: -Example: +#### `name` -```js -const unverifiedIdentity = await createIdentity('test@example.com') -console.log(`DID: ${unverifiedIdentity.signingPrincipal.did()}`) +```ts +name(): String ``` -### `sendVerificationEmail` +Returns the "friendly" name for the space, or the space DID if no name is set. + +#### `did` ```ts -function sendVerificationEmail (identity: UnverifiedIdentity): Promise +did(): DID ``` -Example: +Returns the DID string for the space. -```js -const unverifiedIdentity = await createIdentity('test@example.com') -console.log(`DID: ${unverifiedIdentity.signingPrincipal.did()}`) -await sendVerificationEmail(unverifiedIdentity) -``` - -### `waitIdentityVerification` +#### `registered` ```ts -function waitIdentityVerification (identity: UnverifiedIdentity, options?: { signal: AbortSignal }): Promise<{ identity: VerifiedIdentity, proof: Delegation<[IdentityRegister]> }> +registered(): Boolean ``` -Wait for identity verification to complete (user must click link in email). +Returns `true` if the space has been registered with the service. -Example: +#### `meta` -```js -const unverifiedIdentity = await createIdentity('test@example.com') -console.log(`DID: ${unverifiedIdentity.signingPrincipal.did()}`) -await sendVerificationEmail(unverifiedIdentity) -const controller = new AbortController() -const { identity, proof } = await waitIdentityVerification(unverifiedIdentity, { - signal: controller.signal -}) +```ts +meta(): Record ``` -### `registerIdentity` +Returns user-defined metadata attached to the space. + +### `createAgent` ```ts -registerIdentity (identity: VerifiedIdentity, proof: Delegation<[IdentityRegister]>): Promise +createAgent (options: CreateAgentOptions = {}): Promise ``` -Register a verified identity with the service, passing the proof of verification (a delegation allowing registration). +Create the user agent and load account information from secure storage. -Example: +`CreateAgentOptions` accepts the following fields: -```js -const unverifiedIdentity = await createIdentity('test@example.com') -console.log(`DID: ${unverifiedIdentity.signingPrincipal.did()}`) -await sendVerificationEmail(unverifiedIdentity) -const controller = new AbortController() -const { identity, proof } = await waitIdentityVerification(unverifiedIdentity, { - signal: controller.signal -}) -await registerIdentity(identity, proof) -``` +| field | type | description | +| ------------------ | ----------------------- | ---------------------------------------------------- | +| `servicePrincipal` | ucanto `Principal` | contains the DID & public key for the access service | +| `connection` | ucanto `ConnectionView` | a connection to the access service | + +If `servicePrincipal` or `connection` are not provided, defaults to the production service. -### `removeIdentity` +### `getCurrentSpace` ```ts -removeIdentity (identity: Identity): Promise +getCurrentSpace(agent: Agent): Space | undefined ``` -Remove the passed identity from secure storage. - +Returns the given `agent`'s current space, or `undefined` if the agent has no current space set. -# `storeIdentity` +### `getSpaces` ```ts -storeIdentity (identity: Identity): Promise +getSpaces(agent: Agent): Space[] ``` -Store identity locally in secure storage and set the default. +Returns an array of all spaces that the agent has access to. diff --git a/docs/react-keyring.md b/docs/react-keyring.md index 80fdb3e5..f14762a8 100644 --- a/docs/react-keyring.md +++ b/docs/react-keyring.md @@ -14,67 +14,44 @@ import * as ReactKeyring from '@w3ui/react-keyring' ## Exports -* [`AuthProvider`](#authprovider) -* [`useAuth`](#useauth) +* [`KeyringProvider`](#keyringprovider) +* [`useKeyring`](#usekeyring) --- -### `AuthProvider` +### `KeyringProvider` -Provider for authentication with the service. +Provider for managing agent creation, key management, and space registration with the service. Example: ```jsx -import { AuthProvider } from '@w3ui/react-keyring' +import { KeyringProvider } from '@w3ui/react-keyring' function App () { return ( - + {/* Application pages/components */} - + ) } ``` -### `useAuth` +You can optionally target a non-production instance of the access service by setting the `servicePrincipal` and `connection` props on `KeyringProvider`. The `servicePrincipal` should be set to the service's DID, and `connection` should be a ucanto `ConnectionView` to the service instance. + +### `useKeyring` ```ts -const auth = useAuth() +const [keyringState, keyringActions] = useKeyring() ``` -Hook to allow use of the [`AuthProvider`](#authprovider) value. The value returned is an `AuthContextValue`: +Hook to allow use of the [`KeyringProvider`](#keyringprovider) value. The value returned is a `KeyringContextValue`: ```ts -interface AuthContextValue { - /** - * The current identity - */ - identity?: Identity - /** - * Load the default identity from secure storage. - */ - loadDefaultIdentity: () => Promise - /** - * Unload the current identity from memory. - */ - unloadIdentity: () => Promise - /** - * Unload the current identity from memory and remove from secure storage. - */ - unloadAndRemoveIdentity: () => Promise - /** - * Register a new identity, verify the email address and store in secure - * storage. Use cancelRegisterAndStoreIdentity to abort. - */ - registerAndStoreIdentity: (email: string) => Promise - /** - * Abort an ongoing identity registration. - */ - cancelRegisterAndStoreIdentity: () => void - /** - * Authentication status of the current identity. - */ - authStatus: AuthStatus -} +export type KeyringContextValue = [ + state: KeyringContextState, + actions: KeyringContextActions +] ``` + +See [keyring-core.md](./keyring-core.md) for the definitions for [`KeyringContextState`](./keyring-core.md#keyringcontextstate) and [`KeyringContextActions`](./keyring-core.md#keyringcontextactions). diff --git a/docs/react-uploader.md b/docs/react-uploader.md index 05b8347d..8ea40638 100644 --- a/docs/react-uploader.md +++ b/docs/react-uploader.md @@ -21,7 +21,7 @@ import * as ReactUploader from '@w3ui/react-uploader' ### `UploaderProvider` -Provider for an `Uploader` which allows uploads to the service. Note that this provider uses [`useAuth`](./react-keyring#useauth) and provides an `uploader` only when a current identity is loaded. +Provider for an `Uploader` which allows uploads to the service. Note that this provider uses [`useKeyring`](./react-keyring#usekeyring) and provides an `uploader` only when an Agent with a registered space is loaded. Example: @@ -37,10 +37,12 @@ function App () { } ``` +You can optionally target a non-production instance of the upload service by setting the `servicePrincipal` and `connection` props on `UploaderProvider`. The `servicePrincipal` should be set to the service's DID, and `connection` should be a ucanto `ConnectionView` to the service instance. + ### `useUploader` ```ts -const [progress, uploader] = useUploader() +const [uploaderState, uploaderActions] = useUploader() ``` Hook to allow use of the [`UploaderProvider`](#uploaderprovider) value. The value returned is an `UploaderContextValue`: @@ -50,24 +52,6 @@ type UploaderContextValue = [ state: UploaderContextState, actions: UploaderContextActions ] - -interface UploaderContextState { - uploadedCarChunks: CarChunkMeta[] -} - -interface UploaderContextActions { - /** - * Upload a single file to the service. - */ - uploadFile: (file: Blob) => Promise - /** - * Upload a directory of files to the service. - */ - uploadDirectory: (files: File[]) => Promise - /** - * Upload CAR bytes to the service. - */ - uploadCarChunks: (chunks: AsyncIterable) => Promise -} ``` +See [uploader-core.md](./uploader-core.md) for the definitions for [`UploaderContextState`](./uploader-core.md#uploadercontextstate) and [`UploaderContextActions`](./uploader-core.md#uploadercontextactions). \ No newline at end of file diff --git a/docs/react-uploads-list.md b/docs/react-uploads-list.md index bfde90db..57ac793b 100644 --- a/docs/react-uploads-list.md +++ b/docs/react-uploads-list.md @@ -21,7 +21,7 @@ import * as ReactUploadsList from '@w3ui/react-uploads-list' ### `UploadsListProvider` -Provider for a list of items uploaded by the current identity. Note that this provider uses [`useAuth`](./react-keyring#useauth) to obtain the current identity. +Provider for a list of items uploaded by the current agent. Note that this provider uses [`useKeyring`](./react-keyring#usekeyring) to obtain the current agent's identity. Example: @@ -37,44 +37,21 @@ function App () { } ``` +You can optionally target a non-production instance of the upload service by setting the `servicePrincipal` and `connection` props on `UploadsListProvider`. The `servicePrincipal` should be set to the service's DID, and `connection` should be a ucanto `ConnectionView` to the service instance. + ### `useUploadsList` ```ts -const { data, loading, error, reload } = useUploadsList() +const [uploadsListState, uploadsListActions] = useUploadsList() ``` Hook to allow use of the [`UploadsListProvider`](#uploadslistprovider) value. The value returned is an `UploaderContextValue`: ```ts -interface UploadsListContextValue { - /** - * True if the uploads list is currentky being retrieved from the service. - */ - loading: boolean - /** - * Set if an error occurred retrieving the uploads list. - */ - error?: Error - /** - * The content of the uploads list. - */ - data?: ListPage - /** - * Call to reload the uploads list. - */ - reload: () => Promise -} - -interface ListPage { - page: number; - pageSize: number; - results: ListResult[]; -} - -interface ListResult { - dataCid: CID; - carCids: CID[]; - uploadedAt: Date; -} +export type UploadsListContextValue = [ + state: UploadsListContextState, + actions: UploadsListContextActions +] ``` +See [uploads-list-core.md](./uploads-list-core.md) for the definitions for [`UploadsListContextState`](./uploads-list-core.md#uploadslistcontextstate) and [`UploadsListContextActions`](./uploads-list-core.md#uploadslistcontextactions). diff --git a/docs/solid-keyring.md b/docs/solid-keyring.md index 3d2f9eb8..09faad62 100644 --- a/docs/solid-keyring.md +++ b/docs/solid-keyring.md @@ -14,74 +14,44 @@ import * as SolidKeyring from '@w3ui/solid-keyring' ## Exports -* [`AuthProvider`](#authprovider) -* [`useAuth`](#useauth) +* [`KeyringProvider`](#keyringprovider) +* [`useKeyring`](#usekeyring) --- -### `AuthProvider` +### `KeyringProvider` -Provider for authentication with the service. +Provider for managing agent creation, key management, and space registration with the service. Example: ```jsx -import { AuthProvider } from '@w3ui/solid-keyring' +import { KeyringProvider } from '@w3ui/solid-keyring' function App () { return ( - + {/* Application pages/components */} - + ) } ``` -### `useAuth` +You can optionally target a non-production instance of the access service by setting the `servicePrincipal` and `connection` props on `KeyringProvider`. The `servicePrincipal` should be set to the service's DID, and `connection` should be a ucanto `ConnectionView` to the service instance. + +### `useKeyring` ```ts -const [state, actions] = useAuth() +const [state, actions] = useKeyring() ``` -Hook to allow use of the [`AuthProvider`](#authprovider) value. The value returned is an `AuthContextValue`: +Hook to allow use of the [`KeyringProvider`](#keyringprovider) value. The value returned is a `KeyringContextValue`: ```ts -interface AuthContextState { - /** - * The current identity - */ - readonly identity?: Identity - /** - * Authentication status of the current identity. - */ - readonly status: AuthStatus -} - -type AuthContextValue = [ - state: AuthContextState, - actions: { - /** - * Load the default identity from secure storage. If the identity is not - * verified, the registration flow will be automatically resumed. - */ - loadDefaultIdentity: () => Promise - /** - * Unload the current identity from memory. - */ - unloadIdentity: () => Promise - /** - * Unload the current identity from memory and remove from secure storage. - */ - unloadAndRemoveIdentity: () => Promise - /** - * Register a new identity, verify the email address and store in secure - * storage. Use cancelRegisterAndStoreIdentity to abort. - */ - registerAndStoreIdentity: (email: string) => Promise - /** - * Abort an ongoing identity registration. - */ - cancelRegisterAndStoreIdentity: () => void - } +export type KeyringContextValue = [ + state: KeyringContextState, + actions: KeyringContextActions ] ``` + +See [keyring-core.md](./keyring-core.md) for the definitions for [`KeyringContextState`](./keyring-core.md#keyringcontextstate) and [`KeyringContextActions`](./keyring-core.md#keyringcontextactions). diff --git a/docs/solid-uploader.md b/docs/solid-uploader.md index 6312b4b8..d8fb89b5 100644 --- a/docs/solid-uploader.md +++ b/docs/solid-uploader.md @@ -21,7 +21,7 @@ import * as SolidUploader from '@w3ui/solid-uploader' ### `UploaderProvider` -Provider for an `Uploader` which allows uploads to the service. Note that this provider uses [`useAuth`](./solid-keyring#useauth) and provides an `uploader` that allows uploads only when a current identity is loaded. +Provider for an `Uploader` which allows uploads to the service. Note that this provider uses [`useKeyring`](./solid-keyring#usekeyring) and provides an `uploader` that allows uploads only when an Agent with a registered space is loaded. Example: @@ -37,36 +37,21 @@ function App () { } ``` +You can optionally target a non-production instance of the upload service by setting the `servicePrincipal` and `connection` props on `UploaderProvider`. The `servicePrincipal` should be set to the service's DID, and `connection` should be a ucanto `ConnectionView` to the service instance. + ### `useUploader` ```ts -const [progress, uploader] = useUploader() +const [state, actions] = useUploader() ``` Hook to allow use of the [`UploaderProvider`](#uploaderprovider) value. The value returned is an `UploaderContextValue`: ```ts -export type UploaderContextValue = [ +type UploaderContextValue = [ state: UploaderContextState, actions: UploaderContextActions ] - -export interface UploaderContextState { - uploadedCarChunks: CarChunkMeta[] -} - -export interface UploaderContextActions { - /** - * Upload a single file to the service. - */ - uploadFile: (file: Blob) => Promise - /** - * Upload a directory of files to the service. - */ - uploadDirectory: (files: File[]) => Promise - /** - * Upload CAR bytes to the service. - */ - uploadCarChunks: (chunks: AsyncIterable) => Promise -} ``` + +See [uploader-core.md](./uploader-core.md) for the definitions for [`UploaderContextState`](./uploader-core.md#uploadercontextstate) and [`UploaderContextActions`](./uploader-core.md#uploadercontextactions). \ No newline at end of file diff --git a/docs/solid-uploads-list.md b/docs/solid-uploads-list.md index a6a34eb7..e25ecde7 100644 --- a/docs/solid-uploads-list.md +++ b/docs/solid-uploads-list.md @@ -21,32 +21,50 @@ import * as SolidUploadsList from '@w3ui/solid-uploads-list' ### `createUploadsListResource` ```ts -function createUploadsListResource (source: ResourceSource, options?: ResourceOptions): ResourceReturn +function createUploadsListResource (source: ResourceSource, options?: ResourceOptions, UploadsListSource>): ResourceReturn> ``` Create a solid resource configured to fetch data from the service. Please see the docs for [`createResource`](https://www.solidjs.com/docs/latest/api#createresource) for parameter and return type descriptions. +`createUploadsListResource` takes an `UploadsListSource`: + +```ts +interface UploadsListSource extends ServiceConfig { + cursor?: string + size?: number + space: Space, + agent: Signer, + getProofs: (caps: Capability[]) => Promise +} +``` + +The `space`, `agent`, and `getProofs` fields can be obtained from the `useKeyring` hook. + +The `size` field sets the number of results returned in each page. + +The `ListResponse` returned by the list resource includes a `cursor` field that can be supplied to set the "starting point" of the next page of results. + Example: ```jsx -import { AuthProvider } from '@w3ui/solid-keyring' +import { KeyringProvider, useKeyring } from '@w3ui/solid-keyring' import { createUploadsListResource } from '@w3ui/solid-uploads-list' function App () { return ( - + - + ) } function List () { - const [auth] = useAuth() - const [data] = createUploadsListResource(() => auth.identity) + const [{ agent, space }, { getProofs }] = useKeyring() + const [data] = createUploadsListResource({ agent, space, getProofs }) return ( - {data() && data().results.map(({ dataCid }) => ( - + {data() && data().results.map(({ dataCID }) => ( + ))}
{dataCid}
{dataCID}
) diff --git a/docs/uploader-core.md b/docs/uploader-core.md index 7f4f79ed..0cfe7673 100644 --- a/docs/uploader-core.md +++ b/docs/uploader-core.md @@ -14,96 +14,36 @@ import * as UploaderCore from '@w3ui/uploader-core' ## Exports -* [`encodeDirectory`](#encodedirectory) -* [`encodeFile`](#encodefile) -* [`uploadCarChunks`](#uploadcarchunks) -* [`uploadCarBytes`](#uploadcarbytes) +**Interfaces** +- [`UploaderContextState`](#uploadercontextstate) +- [`UploaderContextActions`](#uploadercontextactions) ---- +**Functions** +- [`uploadFile`](#uploadfile) +- [`uploadDirectory`](#uploaddirectory) -### `chunkBlocks` +--- -```ts -chunkBlocks (stream: ReadableStream, options?: ChunkerOptions): AsyncIterable -``` +### `UploaderContextState` -Split a stream of blocks into chunks of CAR files. +Interface containing uploader state. Implementations are framework-specific and found in each framework's `-uploader` module (e.g. `@w3ui/react-uploader`). ```ts -interface ChunkerOptions { - /** - * The target chunk size. Actual size of CAR output may be bigger due to - * CAR header and block encoding data. - */ - chunkSize?: number +export interface UploaderContextState { + storedDAGShards: CARMetadata[] } ``` -### `encodeDirectory` - -```ts -encodeDirectory (files: Iterable): { cid: Promise, blocks: ReadableStream } -``` - -Create a UnixFS DAG from the passed file data. All files are added to a container directory, with paths in file names preserved. +The [`CARMetadata` type](https://github.com/web3-storage/w3protocol/tree/main/packages/upload-client#carmetadata) is defined by the `@web3-storage/upload-client` package and re-exported by `@w3ui/uploader-core`. -Example: +### `UploaderContextActions` -```js -const { cid, blocks } = encodeDirectory([ - new File(['doc0'], 'doc0.txt'), - new File(['doc1'], 'dir/doc1.txt'), -]) -// DAG structure will be: -// bafybei.../doc0.txt -// bafybei.../dir/doc1.txt -``` - -### `encodeFile` - -```ts -encodeFile (file: Blob): { cid: Promise, blocks: AsyncIterable } -``` +Interface containing upload actions. Implementations are framework-specific and found in each framework's `-uploader` module (e.g. `@w3ui/react-uploader`). -Create a UnixFS DAG from the passed file data. +### `uploadFile` -Example: +Re-exported [`uploadFile` function](https://github.com/web3-storage/w3protocol/tree/main/packages/upload-client#uploadfile) from `@web3-storage/upload-client`. -```js -const { cid, blocks } = await encodeFile(new File(['data'], 'doc.txt')) -// Note: file name is not preserved - use encodeDirectory if required. -``` - -### `uploadCarChunks` - -```ts -uploadCarChunks (principal: SigningPrincipal, chunks: AsyncIterable, options?: UploadCarChunksOptions): Promise -``` - -Upload multiple CAR chunks to the service, linking them together after successful completion. Returns an array of CIDs of the CARs that were uploaded. - -```ts -interface UploadCarChunksOptions { - retries?: number - onChunkUploaded?: (event: { meta: CarChunkMeta }) => void -} - -interface CarChunkMeta { - /** - * CID of the CAR file (not the data it contains). - */ - cid: CID - /** - * Size of the CAR file in bytes. - */ - size: number -} -``` - -### `uploadCarBytes` - -```ts -uploadCarBytes (principal: SigningPrincipal, bytes: Uint8Array): Promise -``` +### `uploadDirectory` -Upload CAR bytes to the service. The principal can be obtained from [`createIdentity`](./keyring-core#createidentity). +Re-exported [`uploadDirectory` function](https://github.com/web3-storage/w3protocol/tree/main/packages/upload-client#uploaddirectory) from `@web3-storage/upload-client`. diff --git a/docs/uploads-list-core.md b/docs/uploads-list-core.md index df305231..6023762c 100644 --- a/docs/uploads-list-core.md +++ b/docs/uploads-list-core.md @@ -14,21 +14,64 @@ import * as UploadsListCore from '@w3ui/uploads-list-core' ## Exports -* [`listUploads`](#listuploads) +**Interfaces** +- [`UploadsListContextState`](#uploadslistcontextstate) +- [`UploadsListContextActions`](#uploadslistcontextactions) + +**Functions** +* [`list`](#list) --- -### `listUploads` +### `UploadsListContextState` + +Interface containing uploads list state. Implementations are framework-specific and found in each framework's `-uploads-list` module (e.g. `@w3ui/react-uploads-list`). ```ts -listUploads (principal: SigningPrincipal, options: { signal?: AbortSignal } = {}): Promise +export interface UploadsListContextState { + /** + * True if the uploads list is currently being retrieved from the service. + */ + loading: boolean + /** + * Set if an error occurred retrieving the uploads list. + */ + error?: Error + /** + * The content of the uploads list. + */ + data?: UploadListResult[] +} ``` -List CIDs of uploaded CAR files. +The `UploadListResult` type is re-exported from `@web3-storage/upload-client` and has the following shape: -Example: +```ts +export interface UploadListResult { + uploaderDID: string + dataCID: string + carCID: string + uploadedAt: string +} +``` -```js -const controller = new AbortController() -const cids = await listUploads(identity.signingPrincipal, { signal: controller.signal }) +### `UploadsListContextActions` + +Interface containing upload listing actions. Implementations are framework-specific and found in each framework's `-uploads-list` module (e.g. `@w3ui/react-uploads-list`). + +```ts +export interface UploadsListContextActions { + /** + * Load the next page of results. + */ + next: () => Promise + /** + * Call to reload the uploads list (discarding the current page). + */ + reload: () => Promise +} ``` + +### `list` + +Re-exported [`Upload.list` function](https://github.com/web3-storage/w3protocol/tree/main/packages/upload-client#uploadlist) from `@web3-storage/upload-client`. diff --git a/docs/vue-keyring.md b/docs/vue-keyring.md index c3b77bfb..666aaf67 100644 --- a/docs/vue-keyring.md +++ b/docs/vue-keyring.md @@ -14,11 +14,11 @@ import * as VueKeyring from '@w3ui/vue-keyring' ## Exports -* [`AuthProvider`](#authprovider) +* [`KeyringProvider`](#keyringprovider) --- -### `AuthProvider` +### `KeyringProvider` [Provider](https://vuejs.org/guide/components/provide-inject.html) for authentication with the service. @@ -26,84 +26,54 @@ Example: ```vue ``` -Once mounted, the `AuthProvider` provides the following injection keys: +Once mounted, the `KeyringProvider` provides the following injection keys: ```ts -type AuthProviderInjectionKey = { - identity: InjectionKey> - status: InjectionKey> - loadDefaultIdentity: InjectionKey - cancelRegisterAndStoreIdentity: InjectionKey - registerAndStoreIdentity: InjectionKey - unloadIdentity: InjectionKey - unloadAndRemoveIdentity: InjectionKey -} - -interface AuthContextState { - /** - * The current identity - */ - identity?: Identity - /** - * Authentication status of the current identity. - */ - status: AuthStatus -} - -interface AuthContextActions { - /** - * Load the default identity from secure storage. If the identity is not - * verified, the registration flow will be automatically resumed. - */ - loadDefaultIdentity: () => Promise - /** - * Unload the current identity from memory. - */ - unloadIdentity: () => Promise - /** - * Unload the current identity from memory and remove from secure storage. - */ - unloadAndRemoveIdentity: () => Promise - /** - * Register a new identity, verify the email address and store in secure - * storage. Use cancelRegisterAndStoreIdentity to abort. - */ - registerAndStoreIdentity: (email: string) => Promise - /** - * Abort an ongoing identity registration. - */ - cancelRegisterAndStoreIdentity: () => void +type KeyringProviderInjectionKey = { + space: InjectionKey>, + spaces: InjectionKey>, + agent: InjectionKey>, + loadAgent: InjectionKey, + unloadAgent: InjectionKey, + resetAgent: InjectionKey, + createSpace: InjectionKey, + setCurrentSpace: InjectionKey, + registerSpace: InjectionKey, + cancelRegisterSpace: InjectionKey, + getProofs: InjectionKey } ``` +See [keyring-core.md](./keyring-core.md) for the definitions for [`KeyringContextState`](./keyring-core.md#keyringcontextstate) and [`KeyringContextActions`](./keyring-core.md#keyringcontextactions). + These keys may be used in child components e.g. ```vue ``` diff --git a/docs/vue-uploader.md b/docs/vue-uploader.md index df3700cd..6aa4b2fc 100644 --- a/docs/vue-uploader.md +++ b/docs/vue-uploader.md @@ -20,59 +20,41 @@ import * as VueUploader from '@w3ui/vue-uploader' ### `UploaderProvider` -[Provider](https://vuejs.org/guide/components/provide-inject.html) for an `Uploader` which allows uploads to the service. Note that _this_ provider injects values from [`AuthProvider`](./vue-keyring#authprovider). +[Provider](https://vuejs.org/guide/components/provide-inject.html) for an `Uploader` which allows uploads to the service. Note that _this_ provider injects values from [`KeyringProvider`](./vue-keyring#keyringprovider). Example: ```vue ``` Once mounted, the `UploaderProvider` provides the following injection keys: ```ts -const UploaderProviderInjectionKey = { +type UploaderProviderInjectionKey = { uploadFile: InjectionKey, uploadDirectory: InjectionKey, - uploadCarChunks: InjectionKey, - uploadedCarChunks: InjectionKey> -} - -interface UploaderContextActions { - /** - * Upload a single file to the service. - */ - uploadFile: (file: Blob) => Promise - /** - * Upload a directory of files to the service. - */ - uploadDirectory: (files: File[]) => Promise - /** - * Upload CAR bytes to the service. - */ - uploadCarChunks: (chunks: AsyncIterable) => Promise -} - -interface UploaderContextState { - uploadedCarChunks: CarChunkMeta[] + storedDAGShards: InjectionKey> } ``` +See [uploader-core.md](./uploader-core.md) for the definitions for [`UploaderContextState`](./uploader-core.md#uploadercontextstate) and [`UploaderContextActions`](./uploader-core.md#uploadercontextactions). + These keys may be used in child components e.g. ```vue diff --git a/docs/vue-uploads-list.md b/docs/vue-uploads-list.md index 0617bc89..522272d3 100644 --- a/docs/vue-uploads-list.md +++ b/docs/vue-uploads-list.md @@ -20,13 +20,14 @@ import * as VueUploadsList from '@w3ui/vue-uploads-list' ### `UploadsListProvider` -[Provider](https://vuejs.org/guide/components/provide-inject.html) for a list of items uploaded by the current identity. Note that _this_ provider injects values from [`AuthProvider`](./vue-keyring#authprovider). +[Provider](https://vuejs.org/guide/components/provide-inject.html) for a list of items uploaded by the current identity. Note that _this_ provider injects values from [`KeyringProvider`](./vue-keyring#keyringprovider). Example: ```vue ``` @@ -47,32 +50,13 @@ type UploadsListProviderInjectionKey = { loading: InjectionKey>, error: InjectionKey>, data: InjectionKey>, + next: InjectionKey, reload: InjectionKey } - -interface UploadsListContextState { - /** - * True if the uploads list is currently being retrieved from the service. - */ - loading: boolean - /** - * Set if an error occurred retrieving the uploads list. - */ - error?: Error - /** - * The content of the uploads list. - */ - data?: ListPage -} - -interface UploadsListContextActions { - /** - * Call to reload the uploads list. - */ - reload: () => Promise -} ``` +See [uploads-list-core.md](./uploads-list-core.md) for the definitions for [`UploadsListContextState`](./uploads-list-core.md#uploadslistcontextstate) and [`UploadsListContextActions`](./uploads-list-core.md#uploadslistcontextactions). + These keys may be used in child components e.g. ```vue @@ -88,7 +72,7 @@ export default { ``` diff --git a/examples/react/file-upload/src/App.js b/examples/react/file-upload/src/App.js index 55fab12c..754fe3f8 100644 --- a/examples/react/file-upload/src/App.js +++ b/examples/react/file-upload/src/App.js @@ -1,14 +1,14 @@ import React, { useEffect } from 'react' -import { AuthProvider, useAuth } from '@w3ui/react-keyring' +import { KeyringProvider, useKeyring } from '@w3ui/react-keyring' import { UploaderProvider } from '@w3ui/react-uploader' import ContentPage from './ContentPage' import logo from './logo.png' function App () { return ( - + - +
logo @@ -17,16 +17,16 @@ function App () {
-
+
-
+ ) } -function IdentityLoader ({ children }) { - const { loadDefaultIdentity } = useAuth() +function AgentLoader ({ children }) { + const [, { loadAgent }] = useKeyring() // eslint-disable-next-line - useEffect(() => { loadDefaultIdentity() }, []) // try load default identity - once. + useEffect(() => { loadAgent() }, []) // load agent - once. return children } diff --git a/examples/react/file-upload/src/ContentPage.js b/examples/react/file-upload/src/ContentPage.js index c3e310ce..4246436a 100644 --- a/examples/react/file-upload/src/ContentPage.js +++ b/examples/react/file-upload/src/ContentPage.js @@ -4,7 +4,7 @@ import { withIdentity } from './components/Authenticator' import './spinner.css' export function ContentPage () { - const [{ uploadedCarChunks }, uploader] = useUploader() + const [{ storedDAGShards }, uploader] = useUploader() const [file, setFile] = useState(null) const [dataCid, setDataCid] = useState('') const [status, setStatus] = useState('') @@ -27,11 +27,11 @@ export function ContentPage () { } if (status === 'uploading') { - return + return } if (status === 'done') { - return error ? : + return error ? : } return ( @@ -45,12 +45,12 @@ export function ContentPage () { ) } -const Uploading = ({ file, uploadedCarChunks }) => ( +const Uploading = ({ file, storedDAGShards }) => (

Uploading DAG for {file.name}

- {uploadedCarChunks.map(({ cid, size }) => ( + {storedDAGShards.map(({ cid, size }) => (

{cid.toString()} ({size} bytes)

@@ -66,13 +66,13 @@ const Errored = ({ error }) => (
) -const Done = ({ file, dataCid, uploadedCarChunks }) => ( +const Done = ({ file, dataCid, storedDAGShards }) => (

Done!

{dataCid.toString()}

View {file.name} on IPFS Gateway.

-

Chunks ({uploadedCarChunks.length}):

- {uploadedCarChunks.map(({ cid, size }) => ( +

Chunks ({storedDAGShards.length}):

+ {storedDAGShards.map(({ cid, size }) => (

{cid.toString()} ({size} bytes)

diff --git a/examples/react/file-upload/src/components/Authenticator.js b/examples/react/file-upload/src/components/Authenticator.js index db595c34..7478e01c 100644 --- a/examples/react/file-upload/src/components/Authenticator.js +++ b/examples/react/file-upload/src/components/Authenticator.js @@ -1,20 +1,21 @@ import React, { useState } from 'react' -import { useAuth, AuthStatus } from '@w3ui/react-keyring' +import { useKeyring } from '@w3ui/react-keyring' export default function Authenticator ({ children }) { - const { authStatus, identity, registerAndStoreIdentity, cancelRegisterAndStoreIdentity } = useAuth() + const [{ space }, { createSpace, registerSpace, cancelRegisterSpace }] = useKeyring() const [email, setEmail] = useState('') + const [submitted, setSubmitted] = useState(false) - if (authStatus === AuthStatus.SignedIn) { + if (space?.registered()) { return children } - if (authStatus === AuthStatus.EmailVerification) { + if (submitted) { return (

Verify your email address!

-

Click the link in the email we sent to {identity && identity.email} to sign in.

-
{ e.preventDefault(); cancelRegisterAndStoreIdentity() }}> +

Click the link in the email we sent to {email} to sign in.

+ { e.preventDefault(); cancelRegisterSpace() }}>
@@ -23,10 +24,14 @@ export default function Authenticator ({ children }) { const handleRegisterSubmit = async e => { e.preventDefault() + setSubmitted(true) try { - await registerAndStoreIdentity(email) + await createSpace() + await registerSpace(email) } catch (err) { throw new Error('failed to register', { cause: err }) + } finally { + setSubmitted(false) } } @@ -36,7 +41,7 @@ export default function Authenticator ({ children }) { setEmail(e.target.value)} required />
- + ) } diff --git a/examples/react/sign-up-in/src/App.js b/examples/react/sign-up-in/src/App.js index 4febce16..3b40a294 100644 --- a/examples/react/sign-up-in/src/App.js +++ b/examples/react/sign-up-in/src/App.js @@ -1,11 +1,11 @@ import React from 'react' -import { AuthProvider } from '@w3ui/react-keyring' +import { KeyringProvider } from '@w3ui/react-keyring' import ContentPage from './ContentPage' import logo from './logo.png' function App () { return ( - +
logo @@ -14,7 +14,7 @@ function App () {
- + ) } diff --git a/examples/react/sign-up-in/src/ContentPage.js b/examples/react/sign-up-in/src/ContentPage.js index 89b8c128..4dc06c22 100644 --- a/examples/react/sign-up-in/src/ContentPage.js +++ b/examples/react/sign-up-in/src/ContentPage.js @@ -1,32 +1,32 @@ import React, { useEffect, useState } from 'react' -import { useAuth, AuthStatus } from '@w3ui/react-keyring' +import { useKeyring } from '@w3ui/react-keyring' export default function ContentPage () { - const { authStatus, identity, loadDefaultIdentity, registerAndStoreIdentity, unloadIdentity, cancelRegisterAndStoreIdentity } = useAuth() + const [{ space }, { loadAgent, unloadAgent, createSpace, registerSpace, cancelRegisterSpace }] = useKeyring() const [email, setEmail] = useState('') const [submitted, setSubmitted] = useState(false) // eslint-disable-next-line - useEffect(() => { loadDefaultIdentity() }, []) // try load default identity - once. + useEffect(() => { loadAgent() }, []) // load the agent - once. - if (authStatus === AuthStatus.SignedIn) { + if (space?.registered()) { return (
-

Welcome {identity.email}!

+

Welcome!

You are logged in!!

-
{ e.preventDefault(); unloadIdentity() }}> + { e.preventDefault(); unloadAgent() }}>
) } - if (authStatus === AuthStatus.EmailVerification) { + if (submitted) { return (

Verify your email address!

-

Click the link in the email we sent to {identity.email} to sign in.

-
{ e.preventDefault(); cancelRegisterAndStoreIdentity() }}> +

Click the link in the email we sent to {email} to sign in.

+ { e.preventDefault(); cancelRegisterSpace() }}>
@@ -37,7 +37,8 @@ export default function ContentPage () { e.preventDefault() setSubmitted(true) try { - await registerAndStoreIdentity(email) + await createSpace() + await registerSpace(email) } catch (err) { throw new Error('failed to register', { cause: err }) } finally { diff --git a/examples/solid/file-upload/src/App.jsx b/examples/solid/file-upload/src/App.jsx index 1f892adb..7222595a 100644 --- a/examples/solid/file-upload/src/App.jsx +++ b/examples/solid/file-upload/src/App.jsx @@ -1,11 +1,11 @@ import logo from './logo.png' -import { AuthProvider, useAuth } from '@w3ui/solid-keyring' +import { KeyringProvider, useKeyring } from '@w3ui/solid-keyring' import { UploaderProvider } from '@w3ui/solid-uploader' import ContentPage from './ContentPage' function App () { return ( - +
@@ -18,13 +18,13 @@ function App () {
-
+ ) } function IdentityLoader ({ children }) { - const [, { loadDefaultIdentity }] = useAuth() - loadDefaultIdentity() // try load default identity - once. + const [, { loadAgent }] = useKeyring() + loadAgent() // try load default identity - once. return children } diff --git a/examples/solid/file-upload/src/ContentPage.jsx b/examples/solid/file-upload/src/ContentPage.jsx index 397ac2dd..fa47b157 100644 --- a/examples/solid/file-upload/src/ContentPage.jsx +++ b/examples/solid/file-upload/src/ContentPage.jsx @@ -36,10 +36,10 @@ export function ContentPage () { - + - {error() ? : } + {error() ? : } ) @@ -50,7 +50,7 @@ const Uploading = props => (

Uploading DAG for {props.file.name}

- {props.uploadedCarChunks.map(({ cid, size }) => ( + {props.storedDAGShards.map(({ cid, size }) => (

{cid.toString()} ({size} bytes)

@@ -71,8 +71,8 @@ const Done = props => (

Done!

{props.dataCid.toString()}

View {props.file.name} on IPFS Gateway.

-

Chunks ({props.uploadedCarChunks.length}):

- {props.uploadedCarChunks.map(({ cid, size }) => ( +

Chunks ({props.storedDAGShards.length}):

+ {props.storedDAGShards.map(({ cid, size }) => (

{cid.toString()} ({size} bytes)

diff --git a/examples/solid/file-upload/src/components/Authenticator.jsx b/examples/solid/file-upload/src/components/Authenticator.jsx index 84e2461a..9c53bde7 100644 --- a/examples/solid/file-upload/src/components/Authenticator.jsx +++ b/examples/solid/file-upload/src/components/Authenticator.jsx @@ -1,8 +1,8 @@ import { createSignal, Switch, Match } from 'solid-js' -import { useAuth, AuthStatus } from '@w3ui/solid-keyring' +import { useKeyring } from '@w3ui/solid-keyring' function Authenticator ({ children }) { - const [auth, { registerAndStoreIdentity, cancelRegisterAndStoreIdentity }] = useAuth() + const [keyring, { createSpace, registerSpace, cancelRegisterSpace }] = useKeyring() const [email, setEmail] = createSignal('') const [submitted, setSubmitted] = createSignal(false) @@ -10,7 +10,8 @@ function Authenticator ({ children }) { e.preventDefault() setSubmitted(true) try { - await registerAndStoreIdentity(email()) + await createSpace() + await registerSpace(email()) } catch (err) { throw new Error('failed to register', { cause: err }) } finally { @@ -20,19 +21,19 @@ function Authenticator ({ children }) { return ( - + {children} - +

Verify your email address!

-

Click the link in the email we sent to {auth.identity.email} to sign in.

-
{ e.preventDefault(); cancelRegisterAndStoreIdentity() }}> +

Click the link in the email we sent to {keyring.agent?.email} to sign in.

+ { e.preventDefault(); cancelRegisterSpace() }}>
- +
diff --git a/examples/solid/multi-file-upload/src/App.jsx b/examples/solid/multi-file-upload/src/App.jsx index 1f892adb..7222595a 100644 --- a/examples/solid/multi-file-upload/src/App.jsx +++ b/examples/solid/multi-file-upload/src/App.jsx @@ -1,11 +1,11 @@ import logo from './logo.png' -import { AuthProvider, useAuth } from '@w3ui/solid-keyring' +import { KeyringProvider, useKeyring } from '@w3ui/solid-keyring' import { UploaderProvider } from '@w3ui/solid-uploader' import ContentPage from './ContentPage' function App () { return ( - +
@@ -18,13 +18,13 @@ function App () {
-
+ ) } function IdentityLoader ({ children }) { - const [, { loadDefaultIdentity }] = useAuth() - loadDefaultIdentity() // try load default identity - once. + const [, { loadAgent }] = useKeyring() + loadAgent() // try load default identity - once. return children } diff --git a/examples/solid/multi-file-upload/src/ContentPage.jsx b/examples/solid/multi-file-upload/src/ContentPage.jsx index a1188b73..976b8afe 100644 --- a/examples/solid/multi-file-upload/src/ContentPage.jsx +++ b/examples/solid/multi-file-upload/src/ContentPage.jsx @@ -58,10 +58,10 @@ export function ContentPage () { - + - {error() ? : } + {error() ? : } ) @@ -72,7 +72,7 @@ const Uploading = props => (

Uploading DAG for {props.files.length > 1 ? `${props.files.length} files` : props.files[0].name}

- {props.uploadedCarChunks.map(({ cid, size }) => ( + {props.storedDAGShards.map(({ cid, size }) => (

{cid.toString()} ({size} bytes)

@@ -93,8 +93,8 @@ const Done = props => (

Done!

{props.dataCid.toString()}

View {props.files.length > 1 ? 'files' : props.files[0].name} on IPFS Gateway.

-

Chunks ({props.uploadedCarChunks.length}):

- {props.uploadedCarChunks.map(({ cid, size }) => ( +

Chunks ({props.storedDAGShards.length}):

+ {props.storedDAGShards.map(({ cid, size }) => (

{cid.toString()} ({size} bytes)

diff --git a/examples/solid/multi-file-upload/src/components/Authenticator.jsx b/examples/solid/multi-file-upload/src/components/Authenticator.jsx index 84e2461a..9c53bde7 100644 --- a/examples/solid/multi-file-upload/src/components/Authenticator.jsx +++ b/examples/solid/multi-file-upload/src/components/Authenticator.jsx @@ -1,8 +1,8 @@ import { createSignal, Switch, Match } from 'solid-js' -import { useAuth, AuthStatus } from '@w3ui/solid-keyring' +import { useKeyring } from '@w3ui/solid-keyring' function Authenticator ({ children }) { - const [auth, { registerAndStoreIdentity, cancelRegisterAndStoreIdentity }] = useAuth() + const [keyring, { createSpace, registerSpace, cancelRegisterSpace }] = useKeyring() const [email, setEmail] = createSignal('') const [submitted, setSubmitted] = createSignal(false) @@ -10,7 +10,8 @@ function Authenticator ({ children }) { e.preventDefault() setSubmitted(true) try { - await registerAndStoreIdentity(email()) + await createSpace() + await registerSpace(email()) } catch (err) { throw new Error('failed to register', { cause: err }) } finally { @@ -20,19 +21,19 @@ function Authenticator ({ children }) { return ( - + {children} - +

Verify your email address!

-

Click the link in the email we sent to {auth.identity.email} to sign in.

-
{ e.preventDefault(); cancelRegisterAndStoreIdentity() }}> +

Click the link in the email we sent to {keyring.agent?.email} to sign in.

+ { e.preventDefault(); cancelRegisterSpace() }}>
- +
diff --git a/examples/solid/sign-up-in/src/App.jsx b/examples/solid/sign-up-in/src/App.jsx index f38234f0..1159ec1f 100644 --- a/examples/solid/sign-up-in/src/App.jsx +++ b/examples/solid/sign-up-in/src/App.jsx @@ -1,10 +1,10 @@ -import logo from './logo.png' -import { AuthProvider } from '@w3ui/solid-keyring' +import { KeyringProvider } from '@w3ui/solid-keyring' import ContentPage from './ContentPage' +import logo from './logo.png' function App () { return ( - +
logo @@ -13,7 +13,7 @@ function App () {
- + ) } diff --git a/examples/solid/sign-up-in/src/ContentPage.jsx b/examples/solid/sign-up-in/src/ContentPage.jsx index fd5dad9a..7eb078f3 100644 --- a/examples/solid/sign-up-in/src/ContentPage.jsx +++ b/examples/solid/sign-up-in/src/ContentPage.jsx @@ -1,46 +1,46 @@ import { createSignal, Switch, Match } from 'solid-js' -import { useAuth, AuthStatus } from '@w3ui/solid-keyring' +import { useKeyring } from '@w3ui/solid-keyring' export default function ContentPage () { - const [auth, { loadDefaultIdentity, registerAndStoreIdentity, unloadIdentity, cancelRegisterAndStoreIdentity }] = useAuth() + const [keyring, { createSpace, registerSpace, cancelRegisterSpace, loadAgent, unloadAgent }] = useKeyring() const [email, setEmail] = createSignal('') const [submitted, setSubmitted] = createSignal(false) - loadDefaultIdentity() // try load default identity - once. + loadAgent() // try load agent - once. const handleRegisterSubmit = async e => { e.preventDefault() setSubmitted(true) try { - await registerAndStoreIdentity(email()) + await createSpace() + await registerSpace(email()) } catch (err) { throw new Error('failed to register', { cause: err }) } finally { setSubmitted(false) } } - return ( - +
-

Welcome {auth.identity.email}!

+

Welcome {keyring.agent?.email}!

You are logged in!!

- { e.preventDefault(); unloadIdentity() }}> + { e.preventDefault(); unloadAgent() }}>
- +

Verify your email address!

-

Click the link in the email we sent to {auth.identity.email} to sign in.

-
{ e.preventDefault(); cancelRegisterAndStoreIdentity() }}> +

Click the link in the email we sent to {keyring.agent?.email} to sign in.

+ { e.preventDefault(); cancelRegisterSpace() }}>
- +
diff --git a/examples/solid/uploads-list/src/App.jsx b/examples/solid/uploads-list/src/App.jsx index 4f4fe1a9..a9d1dde4 100644 --- a/examples/solid/uploads-list/src/App.jsx +++ b/examples/solid/uploads-list/src/App.jsx @@ -1,10 +1,10 @@ import logo from './logo.png' -import { AuthProvider, useAuth } from '@w3ui/solid-keyring' +import { KeyringProvider, useKeyring } from '@w3ui/solid-keyring' import ContentPage from './ContentPage' function App () { return ( - +
@@ -13,13 +13,13 @@ function App () {
-
+ ) } function IdentityLoader ({ children }) { - const [, { loadDefaultIdentity }] = useAuth() - loadDefaultIdentity() // try load default identity - once. + const [, { loadAgent }] = useKeyring() + loadAgent() // try load default identity - once. return children } diff --git a/examples/solid/uploads-list/src/ContentPage.jsx b/examples/solid/uploads-list/src/ContentPage.jsx index 1d7fd277..52a09d96 100644 --- a/examples/solid/uploads-list/src/ContentPage.jsx +++ b/examples/solid/uploads-list/src/ContentPage.jsx @@ -1,12 +1,12 @@ import { Switch, Match } from 'solid-js' -import { useAuth } from '@w3ui/solid-keyring' +import { useKeyring } from '@w3ui/solid-keyring' import { createUploadsListResource } from '@w3ui/solid-uploads-list' import { withIdentity } from './components/Authenticator' import './spinner.css' export function ContentPage () { - const [auth] = useAuth() - const [data, { refetch }] = createUploadsListResource(() => auth.identity, { initialValue: { results: [] } }) + const [keyringState, keyringActions] = useKeyring() + const [data, { refetch }] = createUploadsListResource(() => ({ ...keyringState, ...keyringActions }), { initialValue: { results: [] } }) return (
diff --git a/examples/solid/uploads-list/src/components/Authenticator.jsx b/examples/solid/uploads-list/src/components/Authenticator.jsx index 59f9384b..66cbefe9 100644 --- a/examples/solid/uploads-list/src/components/Authenticator.jsx +++ b/examples/solid/uploads-list/src/components/Authenticator.jsx @@ -1,8 +1,8 @@ import { createSignal, Switch, Match } from 'solid-js' -import { useAuth, AuthStatus } from '@w3ui/solid-keyring' +import { useKeyring } from '@w3ui/solid-keyring' function Authenticator ({ children }) { - const [auth, { registerAndStoreIdentity, cancelRegisterAndStoreIdentity }] = useAuth() + const [keyring, { createSpace, registerSpace, cancelRegisterSpace }] = useKeyring() const [email, setEmail] = createSignal('') const [submitted, setSubmitted] = createSignal(false) @@ -10,7 +10,8 @@ function Authenticator ({ children }) { e.preventDefault() setSubmitted(true) try { - await registerAndStoreIdentity(email()) + await createSpace() + await registerSpace(email()) } catch (err) { throw new Error('failed to register', { cause: err }) } finally { @@ -20,20 +21,20 @@ function Authenticator ({ children }) { return ( - + {children} - +

Verify your email address!

-

Click the link in the email we sent to {auth.identity.email} to sign in.

- { e.preventDefault(); cancelRegisterAndStoreIdentity() }}> +

Click the link in the email we sent to {keyring.agent?.email} to sign in.

+ { e.preventDefault(); cancelRegisterSpace() }}>
- -
+ +
setEmail(e.target.value)} required /> diff --git a/examples/vanilla/sign-up-in/src/main.js b/examples/vanilla/sign-up-in/src/main.js index d9d5ecdb..3a4a2fb4 100644 --- a/examples/vanilla/sign-up-in/src/main.js +++ b/examples/vanilla/sign-up-in/src/main.js @@ -1,15 +1,16 @@ import './assets/tachyons.min.css' import { - createIdentity, - registerIdentity, - sendVerificationEmail, - waitIdentityVerification, - removeIdentity, - storeIdentity, - loadDefaultIdentity + createAgent, + getCurrentSpace } from '@w3ui/keyring-core' +// FIXME: remove this once we no longer need to target staging +import { + accessServicePrincipal, + accessServiceConnection +} from './staging-service.js' + const SELECTORS = { authForm: '#sign-up-in-form', cancelRegistrationButton: '#cancel-registration', @@ -26,7 +27,7 @@ export const EVENTS = { export class RegisterForm extends window.HTMLElement { constructor () { super() - this.identity = null + this.agent = null this.email = null this.form$ = document.querySelector(SELECTORS.authForm) this.confirmationTemplate$ = document.querySelector(SELECTORS.confirmationTemplate) @@ -37,18 +38,28 @@ export class RegisterForm extends window.HTMLElement { this.formatTemplateContent = this.formatTemplateContent.bind(this) } + async getAgent () { + if (this.agent == null) { + this.agent = await createAgent({ + servicePrincipal: accessServicePrincipal, + connection: accessServiceConnection + }) + } + return this.agent + } + async connectedCallback () { this.form$.addEventListener('submit', this.submitHandler) - const identity = await loadDefaultIdentity() + const agent = await this.getAgent() + console.log(`Agent DID: ${agent.did()}`) - if (identity) { - this.identity = identity - this.email = identity.email + const space = getCurrentSpace(agent) + if (space?.registered()) { this.toggleConfirmation() - console.log(`DID: ${identity.signingPrincipal.did()}`) + console.log(`Space DID: ${space.did()}`) } else { - console.log('No identity registered') + console.log('No registered spaces') } } @@ -82,9 +93,8 @@ export class RegisterForm extends window.HTMLElement { async signOutHandler (e) { e.preventDefault() - if (this.identity) { - await removeIdentity(this.identity) - } + this.agent = null + window.location.reload() } @@ -94,26 +104,26 @@ export class RegisterForm extends window.HTMLElement { // log in a user by their email const email = fd.get('email') this.email = email - let identity - let proof if (email) { - const unverifiedIdentity = await createIdentity({ email }) - console.log(`DID: ${unverifiedIdentity.signingPrincipal.did()}`) - await sendVerificationEmail(unverifiedIdentity) + const agent = await this.getAgent() + const { did } = await agent.createSpace() + await agent.setCurrentSpace(did) + console.log(`Created new Space with DID: ${did}`) + const controller = new AbortController() try { - this.toggleVerification(true); - ({ identity, proof } = await waitIdentityVerification( - unverifiedIdentity, - { - signal: controller.signal - } - )) - await registerIdentity(identity, proof) - await storeIdentity(identity) - this.identity = identity + // Fire registration start event + const startEvent = window.CustomEvent(EVENTS.registrationStart, { bubbles: true }) + this.dispatchEvent(startEvent) + + this.toggleVerification(true) + await agent.registerSpace(email, { signal: controller.signal }) + + // Fire sign in success event + const successEvent = new window.CustomEvent(EVENTS.registrationSuccess, { bubbles: true }) + this.dispatchEvent(successEvent) } catch (err) { console.error('Registration failed:', err) this.email = null diff --git a/examples/vanilla/sign-up-in/src/staging-service.js b/examples/vanilla/sign-up-in/src/staging-service.js new file mode 100644 index 00000000..e4ad83ea --- /dev/null +++ b/examples/vanilla/sign-up-in/src/staging-service.js @@ -0,0 +1,29 @@ +import { connect } from '@ucanto/client' +import { CAR, CBOR, HTTP } from '@ucanto/transport' +import * as DID from '@ipld/dag-ucan/did' + +export const accessServiceURL = new URL('https://w3access-staging.protocol-labs.workers.dev') +export const accessServicePrincipal = DID.parse('did:key:z6MkwTYX2JHHd8bmaEuDdS1LJjrpFspirjDcQ4DvAiDP49Gm') + +export const accessServiceConnection = connect({ + id: accessServicePrincipal, + encoder: CAR, + decoder: CBOR, + channel: HTTP.open({ + url: accessServiceURL, + method: 'POST' + }) +}) + +export const uploadServiceURL = new URL('https://staging.up.web3.storage') +export const uploadServicePrincipal = DID.parse('did:key:z6MkhcbEpJpEvNVDd3n5RurquVdqs5dPU16JDU5VZTDtFgnn') + +export const uploadServiceConnection = connect({ + id: uploadServicePrincipal, + encoder: CAR, + decoder: CBOR, + channel: HTTP.open({ + url: uploadServiceURL, + method: 'POST' + }) +}) diff --git a/examples/vue/file-upload/src/App.vue b/examples/vue/file-upload/src/App.vue index dc9302cc..0b3e2364 100644 --- a/examples/vue/file-upload/src/App.vue +++ b/examples/vue/file-upload/src/App.vue @@ -1,16 +1,16 @@ diff --git a/examples/vue/file-upload/src/ContentPage.vue b/examples/vue/file-upload/src/ContentPage.vue index b87166b3..a8e96878 100644 --- a/examples/vue/file-upload/src/ContentPage.vue +++ b/examples/vue/file-upload/src/ContentPage.vue @@ -4,7 +4,7 @@ import { UploaderProviderInjectionKey } from '@w3ui/vue-uploader' export default { inject: { uploadFile: { from: UploaderProviderInjectionKey.uploadFile }, - uploadedCarChunks: { from: UploaderProviderInjectionKey.uploadedCarChunks } + storedDAGShards: { from: UploaderProviderInjectionKey.storedDAGShards } }, data () { return { @@ -42,7 +42,7 @@ export default {

Uploading DAG for {{file.name}}

{{dataCid}}

-

+

{{chunk.cid.toString()}} ({{chunk.size}} bytes)

@@ -57,8 +57,8 @@ export default {

Done!

{{dataCid}}

View {{file.name}} on IPFS Gateway.

-

Chunks ({{uploadedCarChunks.length}}):

-

+

Chunks ({{storedDAGShards.length}}):

+

{{chunk.cid.toString()}} ({{chunk.size}} bytes)

@@ -71,4 +71,3 @@ export default { - \ No newline at end of file diff --git a/examples/vue/file-upload/src/components/Authenticator.vue b/examples/vue/file-upload/src/components/Authenticator.vue index 94812f79..acb88570 100644 --- a/examples/vue/file-upload/src/components/Authenticator.vue +++ b/examples/vue/file-upload/src/components/Authenticator.vue @@ -1,16 +1,17 @@