0.12.1 • Published 8 months ago

@canvas-js/core v0.12.1

Weekly downloads
-
License
-
Repository
-
Last release
8 months ago

@canvas-js/core

A Canvas app replicates and executes a log of signed actions, sourced from GossipLog, with read/write access to a ModelDB database.

Use this package directly if you want fine-grained control over when an application is started/stopped. Otherwise, you can use useCanvas in @canvas-js/hooks, which has the same API, but handles initialization inside React for you.

Table of Contents

Installation

$ npm i @canvas-js/core

Usage

import { Canvas } from "@canvas-js/core"

const app = await Canvas.initialize({
  contract: {
    topic: "com.example.my-app",
    models: {
      posts: {
        id: "primary",
        user: "string",
        content: "string",
        updated_at: "integer",
      },
    },
    actions: {
      async createPost(db, { content }, { id, chain, address, timestamp }) {
        const user = [chain, address].join(":")
        await db.posts.set({ id, user, content, updated_at: timestamp })
      },
      async deletePost(db, { postId }, { chain, address }) {
        const post = await db.posts.get(postId)
        if (post === null) {
          return
        }

        const user = [chain, address].join(":")
        if (post.user !== user) {
          throw new Error("not authorized")
        }

        await db.posts.delete(postId)
      },
    },
  },
})

await app.actions.createPost({ content: "hello world!" })
const results = await app.db.query("posts", {})
// [
//   {
//     id: '09p5qn7affkhtbflscr663tet8ddeu41',
//     user: 'did:pkh:eip155:1:0x79c5158f81ebb0c2bcF877E9e1813aed2Eb652B7',
//     content: 'hello world!',
//     updated_at: 1698339861041
//   }
// ]

API

Contract types

import type { ModelSchema, ModelValue } from "@canvas-js/modeldb"
import type { Awaitable } from "@canvas-js/interfaces"

export type Contract = {
  topic: string
  models: ModelSchema
  actions: Record<string, ActionImplementationFunction | ActionImplementationObject>
}

export type ActionImplementationObject = {
  argsType?: { schema: string; name: string }
  apply: ActionImplementationFunction
}

export type ActionImplementationFunction = (
  db: Record<string, ModelAPI>,
  args: Args,
  context: ActionContext,
) => Awaitable<Result>

export type ModelAPI = {
  get: (key: string) => Promise<T | null>
  set: (value: ModelValue) => Promise<void>
  delete: (key: string) => Promise<void>
}

export type ActionContext = {
  id: string
  chain: string
  address: string
  blockhash: string | null
  timestamp: number
}

Canvas class

import { Signature, Action, Session, SessionSigner } from "@canvas-js/interfaces"
import { AbstractModelDB } from "@canvas-js/modeldb"

export interface NetworkConfig {
  offline?: boolean
  disablePing?: boolean
  /** array of local WebSocket multiaddrs, e.g. "/ip4/127.0.0.1/tcp/3000/ws" */
  listen?: string[]
  /** array of public WebSocket multiaddrs, e.g. "/dns4/myapp.com/tcp/443/wss" */
  announce?: string[]
  bootstrapList?: string[]
  minConnections?: number
  maxConnections?: number
  discoveryTopic?: string
  discoveryInterval?: number
  trackAllPeers?: boolean
  enableWebRTC?: boolean
}
export interface CanvasConfig<T extends Contract = Contract> extends NetworkConfig {
  contract: string | T
  signers?: SessionSigner[]
  /** data directory path (NodeJS only) */
  path?: string | null
  /** provide an existing libp2p instance instead of creating a new one */
  libp2p?: Libp2p<ServiceMap>
  runtimeMemoryLimit?: number
}

export interface CanvasEvents extends GossipLogEvents<Action | Session, unknown> {
  close: Event
  connect: CustomEvent<{
    peer: PeerId
  }>
  disconnect: CustomEvent<{
    peer: PeerId
  }>
  "connections:updated": CustomEvent<ConnectionsInfo>
  "presence:join": CustomEvent<PresenceInfo>
  "presence:leave": CustomEvent<PresenceInfo>
}

export declare class Canvas extends EventEmitter<CanvasEvents> {
  public static initialize(config: CanvasConfig): Promise<Canvas>

  public readonly topic: string
  public readonly signers: SessionSigner[]
  public readonly peerId: PeerId
  public readonly libp2p: Libp2p<ServiceMap> | null
  public readonly db: AbstractModelDB

  public readonly actions: Record<
    string,
    (
      args: any,
      options: { chain?: string; signer?: SessionSigner },
    ) => Promise<{ id: string; recipients: Promise<PeerId[]> }>
  >

  public close(): Promise<void>
  public start(): Promise<void>
  public stop(): Promise<void>

  public getMessage(id: string): Promise<[signature: Signature, message: Message<Action | Session>] | [null, null]>
  public getMessageStream(
    lowerBound?: { id: string; inclusive: boolean } | null,
    upperBound?: { id: string; inclusive: boolean } | null,
    options?: { reverse?: boolean },
  ): AsyncIterable<[id: string, signature: Signature, message: Message<Action | Session>]>
}
0.13.0-next.16

8 months ago

0.13.0-next.15

8 months ago

0.13.0-next.14

8 months ago

0.13.0-next.13

8 months ago

0.12.1

8 months ago

0.13.0-next.12

8 months ago

0.13.0-next.11

8 months ago

0.13.0-next.10

8 months ago

0.13.0-next.9

8 months ago

0.13.0-next.8

8 months ago

0.13.0-next.1

8 months ago

0.13.0-next.3

8 months ago

0.13.0-next.2

8 months ago

0.13.0-next.5

8 months ago

0.13.0-next.4

8 months ago

0.13.0-next.7

8 months ago

0.13.0-next.6

8 months ago

0.11.0

9 months ago

0.12.0

8 months ago

0.10.10

10 months ago

0.10.9

10 months ago

0.10.1

11 months ago

0.10.2

11 months ago

0.10.3

11 months ago

0.10.4

10 months ago

0.10.5

10 months ago

0.10.6

10 months ago

0.10.7

10 months ago

0.10.8

10 months ago

0.10.0

11 months ago

0.10.0-alpha.1

1 year ago

0.8.29

1 year ago

0.10.0-beta.2

1 year ago

0.10.0-beta.3

12 months ago

0.10.0-beta.1

1 year ago

0.10.0-beta.4

12 months ago

0.8.28

1 year ago

0.8.27-patch.21

1 year ago

0.8.27-patch.14

1 year ago

0.8.27-patch.13

1 year ago

0.8.27-patch.16

1 year ago

0.8.27-patch.15

1 year ago

0.8.27-patch.10

1 year ago

0.8.27-patch.6

1 year ago

0.8.27-patch.7

1 year ago

0.8.27-patch.12

1 year ago

0.8.27-patch.8

1 year ago

0.8.27-patch.11

1 year ago

0.8.27-patch.9

1 year ago

0.8.27-patch.20

1 year ago

0.9.1

1 year ago

0.8.27-patch.18

1 year ago

0.8.27-patch.17

1 year ago

0.8.27-patch.19

1 year ago

0.8.27-patch.2

1 year ago

0.8.27-patch.3

1 year ago

0.8.27-patch.4

1 year ago

0.8.27-patch.5

1 year ago

0.8.27-patch.1

1 year ago

0.9.0

1 year ago

0.9.0-next.1

1 year ago

0.8.26-alpha.4

1 year ago

0.8.26-alpha.3

1 year ago

0.8.26-alpha.2

1 year ago

0.8.26

1 year ago

0.8.26-alpha.1

1 year ago

0.8.25

1 year ago

0.8.24

1 year ago

0.8.23

1 year ago

0.8.22

1 year ago

0.8.21

1 year ago

0.8.20

1 year ago

0.8.19

1 year ago

0.8.18

1 year ago

0.8.17

1 year ago

0.8.16

1 year ago

0.8.15

1 year ago

0.8.14-alpha.1

2 years ago

0.8.14

2 years ago

0.8.13

2 years ago

0.8.12

2 years ago

0.8.11

2 years ago

0.8.10

2 years ago

0.8.9

2 years ago

0.8.8

2 years ago

0.8.5

2 years ago

0.8.4

2 years ago

0.8.7

2 years ago

0.8.6

2 years ago

0.8.2-alpha.1

2 years ago

0.8.3

2 years ago

0.8.2

2 years ago

0.8.2-patch.1

2 years ago

0.7.2-alpha.1

2 years ago

0.7.2-alpha.2

2 years ago

0.7.2-alpha.3

2 years ago

0.7.2-alpha.4

2 years ago

0.7.2-alpha.5

2 years ago

0.7.2-alpha.6

2 years ago

0.7.2-alpha.7

2 years ago

0.7.2

2 years ago

0.7.1

2 years ago

0.7.3

2 years ago

0.7.0

2 years ago

0.8.1

2 years ago

0.8.0

2 years ago

0.6.0-alpha2

2 years ago

0.6.0-alpha1

2 years ago

0.6.0-alpha4

2 years ago

0.6.0-alpha3

2 years ago

0.6.0-alpha6

2 years ago

0.6.0-alpha5

2 years ago

0.6.0-alpha7

2 years ago

0.5.0

2 years ago

0.5.1

2 years ago

0.6.1

2 years ago

0.6.0

2 years ago

0.4.9

2 years ago

0.5.0-alpha

2 years ago

0.5.0-alpha4

2 years ago

0.5.0-alpha3

2 years ago

0.5.0-alpha2

2 years ago

0.4.10

2 years ago

0.4.11

2 years ago

0.4.8

2 years ago

0.4.5

2 years ago

0.4.4

2 years ago

0.4.7

2 years ago

0.4.6

2 years ago

0.4.1

2 years ago

0.4.0

2 years ago

0.4.3

2 years ago

0.4.2

2 years ago

0.3.0

2 years ago

0.3.2

2 years ago

0.3.1

2 years ago

0.3.3

2 years ago

0.2.1

2 years ago

0.2.0

2 years ago

0.2.2

2 years ago

0.1.2

2 years ago

0.1.3

2 years ago

0.1.0

2 years ago

0.1.1

2 years ago

0.0.53

2 years ago

0.0.52

2 years ago

0.0.40

2 years ago

0.0.41

2 years ago

0.0.42

2 years ago

0.0.43

2 years ago

0.0.44

2 years ago

0.0.45

2 years ago

0.0.46

2 years ago

0.0.47

2 years ago

0.0.37

2 years ago

0.0.38

2 years ago

0.0.39

2 years ago

0.0.48-pre

2 years ago

0.0.50-pre4

2 years ago

0.0.50-pre3

2 years ago

0.0.50-pre2

2 years ago

0.0.50-pre

2 years ago

0.0.51

2 years ago

0.0.50

2 years ago

0.0.48

2 years ago

0.0.49

2 years ago

0.0.20

3 years ago

0.0.22

3 years ago

0.0.23

3 years ago

0.0.24

3 years ago

0.0.25

3 years ago

0.0.19

3 years ago

0.0.30

3 years ago

0.0.31

3 years ago

0.0.34-alpha6

2 years ago

0.0.32

3 years ago

0.0.33

3 years ago

0.0.34

2 years ago

0.0.35

2 years ago

0.0.36

2 years ago

0.0.34-alpha5

2 years ago

0.0.34-alpha4

3 years ago

0.0.34-alpha3

3 years ago

0.0.34-alpha2

3 years ago

0.0.26

3 years ago

0.0.27

3 years ago

0.0.28

3 years ago

0.0.29

3 years ago

0.0.34-alpha

3 years ago

0.0.17-alpha2

3 years ago

0.0.17-alpha

3 years ago

0.0.17

3 years ago

0.0.10

3 years ago

0.0.11

3 years ago

0.0.16

3 years ago

0.0.2

3 years ago

0.0.3-alpha

3 years ago

0.0.9

3 years ago

0.0.8

3 years ago

0.0.4

3 years ago

0.0.1

3 years ago