Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/dashnote-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@ on:
branches: [main]
paths:
- 'example-apps/dashnote/**'
- 'example-apps/token-ops/src/dash/loginWithPrivateKey.ts'
- 'example-apps/token-ops/src/lib/detectSecretShape.ts'
- 'example-apps/token-ops/src/session/keyManagerFromKey.ts'
- 'scripts/check-shared-auth-parity.sh'
- '.github/workflows/dashnote-e2e.yml'
pull_request:
branches: [main]
paths:
- 'example-apps/dashnote/**'
- 'example-apps/token-ops/src/dash/loginWithPrivateKey.ts'
- 'example-apps/token-ops/src/lib/detectSecretShape.ts'
- 'example-apps/token-ops/src/session/keyManagerFromKey.ts'
- 'scripts/check-shared-auth-parity.sh'
- '.github/workflows/dashnote-e2e.yml'
workflow_dispatch:
inputs:
Expand All @@ -30,6 +38,17 @@ concurrency:
cancel-in-progress: true

jobs:
auth-parity:
name: shared auth parity
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Check shared authentication parity
run: bash scripts/check-shared-auth-parity.sh

e2e-read-only:
name: e2e (read-only — smoke + settings)
runs-on: ubuntu-latest
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/token-ops-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@ on:
branches: [main]
paths:
- 'example-apps/token-ops/**'
- 'example-apps/dashnote/src/dash/loginWithPrivateKey.ts'
- 'example-apps/dashnote/src/lib/detectSecretShape.ts'
- 'example-apps/dashnote/src/session/keyManagerFromKey.ts'
- 'scripts/check-shared-auth-parity.sh'
- '.github/workflows/token-ops-ci.yml'
pull_request:
branches: [main]
paths:
- 'example-apps/token-ops/**'
- 'example-apps/dashnote/src/dash/loginWithPrivateKey.ts'
- 'example-apps/dashnote/src/lib/detectSecretShape.ts'
- 'example-apps/dashnote/src/session/keyManagerFromKey.ts'
- 'scripts/check-shared-auth-parity.sh'
- '.github/workflows/token-ops-ci.yml'
workflow_dispatch:

Expand All @@ -33,6 +41,9 @@ jobs:
with:
persist-credentials: false

- name: Check shared authentication parity
run: bash ../../scripts/check-shared-auth-parity.sh

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ the normal lifecycle: info, mint, transfer, and burn.
Some client configuration options are included as comments in
[`setupDashClient.mjs`](./setupDashClient.mjs) if more advanced configuration is required.

## Example Apps

The [`example-apps`](./example-apps/README.md) directory contains independently runnable React +
TypeScript npm projects that demonstrate Dash Platform concepts in complete browser workflows,
including identities, documents, queries, tokens, and multi-signer groups. The apps have their own
setup instructions and dependencies but share repository-level SDK client helpers.

## Testing

Tests run each tutorial as a subprocess and validate its output. No test framework dependencies are
Expand Down
15 changes: 8 additions & 7 deletions example-apps/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Example Apps
# 🚀 Example Apps

Stand-alone applications built on top of the same `@dashevo/evo-sdk` used by the Node tutorials in the parent repo. Each example is an independent npm project — `cd` into its directory and run `npm install` there for the Vite app itself.
Independently runnable applications built on the same `@dashevo/evo-sdk` used by the Node tutorials in the parent repo. Each example has its own npm project — `cd` into its directory and run `npm install` there for the Vite app itself — while sharing the repository-root `setupDashClient-core.mjs` helper for browser SDK setup and key management.

Some app scripts still depend on the **repository-root** install. TokenOps `npm run bootstrap:identities` imports the root `setupDashClient.mjs` helper and the root `@dashevo/evo-sdk` copy (to keep a single module instance for SDK `instanceof` checks). For that path, run `npm install` at the repo root as well — see [token-ops/README.md](./token-ops/README.md#group-members).

## Apps
## 🧭 Apps

- [dashmint-lab/](./dashmint-lab/) — React + TypeScript + Vite SPA for minting, viewing, transferring, and trading NFT-style collectible cards on Dash Platform testnet. Shares the browser-safe SDK core (`setupDashClient-core.mjs`) with the Node tutorials at the repo root.
- [dashproof-lab/](./dashproof-lab/) — React + TypeScript + Vite proof-of-existence tutorial app that hashes files locally in the browser, anchors SHA-256 proofs on Dash Platform testnet, verifies files by hash, and reviews proof history by owner or chain ID. Also uses the shared browser-safe SDK core from the parent repo.
- [dashnote/](./dashnote/) — React + TypeScript + Vite notes app for Dash Platform testnet. Create, edit, and delete notes against a small `note` data contract; supports a "Remember Me" read-only browse mode, optimistic localStorage cache, and ships a single-file zero-build read-only companion at `dashnote-lite.html`. Also uses the shared browser-safe SDK core from the parent repo.
- [dashrate/](./dashrate/) — React + TypeScript + Vite app for rating Platform tutorial resources on Dash Platform testnet, built to showcase Platform 4.0's relational document queries: provable `count`, grouped `count` (`GROUP BY`) for the per-star distribution, range counts, and `where` filtering. One review per identity per resource (editable, with document history); read-only browsing works without signing in. Also uses the shared browser-safe SDK core from the parent repo.
- 🃏 [dashmint-lab/](./dashmint-lab/) — React + TypeScript + Vite SPA for minting, viewing, transferring, and trading NFT-style collectible cards on Dash Platform testnet. Shares the browser-safe SDK core (`setupDashClient-core.mjs`) with the Node tutorials at the repo root.
- 🔐 [dashproof-lab/](./dashproof-lab/) — React + TypeScript + Vite proof-of-existence tutorial app that hashes files locally in the browser, anchors SHA-256 proofs on Dash Platform testnet, verifies files by hash, and reviews proof history by owner or chain ID. Also uses the shared browser-safe SDK core from the parent repo.
- 📝 [dashnote/](./dashnote/) — React + TypeScript + Vite notes app for Dash Platform testnet. Create, edit, and delete notes against a small `note` data contract; supports a "Remember Me" read-only browse mode, optimistic localStorage cache, and ships a single-file zero-build read-only companion at `dashnote-lite.html`. Also uses the shared browser-safe SDK core from the parent repo.
- ⭐ [dashrate/](./dashrate/) — React + TypeScript + Vite app for rating Platform tutorial resources on Dash Platform testnet, built to showcase Platform 4.0's relational document queries: provable `count`, grouped `count` (`GROUP BY`) for the per-star distribution, range counts, and `where` filtering. One review per identity per resource (editable, with document history); read-only browsing works without signing in. Also uses the shared browser-safe SDK core from the parent repo.
- 👥 [token-ops/](./token-ops/) — React + TypeScript + Vite app that demonstrates Dash Platform groups and multi-signer governance on testnet, using token operations as the example workflow. Create groups, propose and co-sign group-authorized actions, monitor signing progress, and inspect or reassign operator and admin authorities. Browse-only mode works without signing in.
2 changes: 1 addition & 1 deletion example-apps/dashmint-lab/src/components/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export function AppShell({
<div className="mx-auto max-w-[1310px]">{children}</div>
<footer className="mx-auto mt-10 flex max-w-[1310px] justify-center border-t border-line pt-4 text-[12px] text-ink-3">
<a
href="https://github.com/dashpay/platform-tutorials"
href="https://github.com/dashpay/platform-tutorials/tree/main/example-apps/dashmint-lab"
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1.5 text-ink-3 hover:text-accent"
Expand Down
3 changes: 2 additions & 1 deletion example-apps/dashnote/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ React + TypeScript + Vite app for personal notes on Dash Platform testnet. Notes

- **[src/dash/](src/dash/)** — one file per Platform SDK operation: [createNote.ts](src/dash/createNote.ts), [updateNote.ts](src/dash/updateNote.ts), [deleteNote.ts](src/dash/deleteNote.ts), [queries.ts](src/dash/queries.ts), [contract.ts](src/dash/contract.ts), [loginWithPrivateKey.ts](src/dash/loginWithPrivateKey.ts), [resolveDpnsName.ts](src/dash/resolveDpnsName.ts). Each exports an async function with a leading JSDoc block naming the SDK method it wraps. No hooks, no UI wrappers — the SDK call is the function. Files in this folder always reference `@dashevo/evo-sdk` (or shared core re-exports / SDK-shape types). App-shell utilities that don't touch the SDK live in [src/lib/](src/lib/) instead. Two deferred-import loaders live alongside the operations: [sdkModule.ts](src/dash/sdkModule.ts) caches a `import("@dashevo/evo-sdk")` so value imports (`Document`, `DataContract`, `Identifier`) stay out of the entry chunk, and [types.ts](src/dash/types.ts) holds the shared SDK type aliases used everywhere.
- **Shared SDK core** — [src/dash/client.ts](src/dash/client.ts) and [src/dash/keyManager.ts](src/dash/keyManager.ts) re-export `createClient` and `IdentityKeyManager` from `../../../../setupDashClient-core.mjs` (the canonical browser-safe core at the host repo root). No vendoring. The `@dashevo/evo-sdk` bare specifier is aliased in [vite.config.ts](vite.config.ts) to this app's locally installed browser bundle so the shared core resolves the SDK from here.
- **[src/session/](src/session/)** — `SessionContext.tsx` provides the context (`status`, `error`, `sdk`, `keyManager`, `identityId`, `contractId`, `rememberedIdentityId`, `dpnsName`, `setContractId`, `log`, `login`, `enterReadOnly`, `viewAsRemembered`, `forgetIdentity`, `logout`) and `useSession.ts` is the consumer hook. `login(secret, options)` auto-detects mnemonic vs WIF via [detectSecretShape](src/lib/detectSecretShape.ts): mnemonics use `IdentityKeyManager` (DIP-13 derivation with optional `identityIndex`); WIF dispatches to `loginWithPrivateKey` (dynamic-imported to keep its SDK dependency off the app shell), which produces a single-key manager via [keyManagerFromKey.ts](src/session/keyManagerFromKey.ts). Mnemonic + WIF live only in the keyManager closure — never in state, never in localStorage. `SessionContext` has its own small loader for the shared core (`createClient`, `IdentityKeyManager`); the `@dashevo/evo-sdk` value-import loader is the separate [sdkModule.ts](src/dash/sdkModule.ts) used by `createNote` / `updateNote` / `deleteNote` / `contract.ts`. Both are dynamically imported on first use so the ~8MB WASM bundle doesn't block initial paint. After a successful login the context also resolves the identity's DPNS name via [resolveDpnsName.ts](src/dash/resolveDpnsName.ts) and persists it alongside the remembered identity ID.
- **[src/session/](src/session/)** — `SessionContext.tsx` provides the context (`status`, `error`, `sdk`, `keyManager`, `identityId`, `contractId`, `rememberedIdentityId`, `dpnsName`, `setContractId`, `log`, `login`, `enterReadOnly`, `viewAsRemembered`, `forgetIdentity`, `logout`) and `useSession.ts` is the consumer hook. `login(secret, options)` auto-detects mnemonic vs WIF via [detectSecretShape](src/lib/detectSecretShape.ts): mnemonics use `IdentityKeyManager` (DIP-13 derivation with optional `identityIndex`); WIF dispatches to `loginWithPrivateKey` (dynamic-imported to keep its SDK dependency off the app shell), which produces a single-key manager via [keyManagerFromKey.ts](src/session/keyManagerFromKey.ts). WIF resolution falls back to paginated `byNonUniquePublicKeyHash`; ambiguous keys require an exact `expectedIdentityId`, which is fetched directly and verified rather than resolved by result order. Mnemonic + WIF live only in the keyManager closure — never in state, never in localStorage. `SessionContext` has its own small loader for the shared core (`createClient`, `IdentityKeyManager`); the `@dashevo/evo-sdk` value-import loader is the separate [sdkModule.ts](src/dash/sdkModule.ts) used by `createNote` / `updateNote` / `deleteNote` / `contract.ts`. Both are dynamically imported on first use so the ~8MB WASM bundle doesn't block initial paint. After a successful login the context also resolves the identity's DPNS name via [resolveDpnsName.ts](src/dash/resolveDpnsName.ts) and persists it alongside the remembered identity ID only when the remember checkbox is enabled.
- **[src/components/](src/components/)** — standard React. Modals/panels call `src/dash/` functions directly. Shell: [AppShell.tsx](src/components/AppShell.tsx), [Tabs.tsx](src/components/Tabs.tsx), [NavButton.tsx](src/components/NavButton.tsx), [HowItWorks.tsx](src/components/HowItWorks.tsx). Workspace: [NotesWorkspace.tsx](src/components/NotesWorkspace.tsx) (two-pane list + editor with optimistic cache + background revalidation), [NoteList.tsx](src/components/NoteList.tsx), [NoteEditor.tsx](src/components/NoteEditor.tsx) (fused title/body editor with byte-budget progress bar), [DeleteNoteModal.tsx](src/components/DeleteNoteModal.tsx) (confirmation modal for deletes). Auth + settings: [LoginModal.tsx](src/components/LoginModal.tsx) (mnemonic-or-WIF paste flow with remembered-identity panel), [SettingsPanel.tsx](src/components/SettingsPanel.tsx) (settings tab — contract paste / register, identity card, local-data controls), [IdentityCard.tsx](src/components/IdentityCard.tsx). Shared primitives: [Modal.tsx](src/components/Modal.tsx), [OperationResultNotice.tsx](src/components/OperationResultNotice.tsx).
- **[src/hooks/](src/hooks/)** — app-specific hooks: [useTheme.ts](src/hooks/useTheme.ts) (dark mode toggle), [useMediaQuery.ts](src/hooks/useMediaQuery.ts) (`window.matchMedia` via `useSyncExternalStore`), [useContractRegistration.ts](src/hooks/useContractRegistration.ts) (Settings flow for paste-or-register), [useWifPreview.ts](src/hooks/useWifPreview.ts) (eager identity + key-fitness preview on WIF paste in the login modal).
- **Shared auth parity:** `src/dash/loginWithPrivateKey.ts`, `src/lib/detectSecretShape.ts`, `src/session/keyManagerFromKey.ts`, and the core resolver suite `test/loginWithPrivateKey.test.ts` must remain byte-identical to their TokenOps counterparts. Keep app-specific preview, session, and modal behavior outside these files; CI enforces parity with `scripts/check-shared-auth-parity.sh`.
- **[src/lib/](src/lib/)** — pure utilities, no SDK references: [logger.ts](src/lib/logger.ts) (`Logger` type + `errorMessage(err)`), [notesCache.ts](src/lib/notesCache.ts) (localStorage-backed note list keyed by identity + contract + network), [rememberedIdentity.ts](src/lib/rememberedIdentity.ts) (last-logged-in identity ID + DPNS name for read-only browse), [fieldLimits.ts](src/lib/fieldLimits.ts) (UTF-8 byte counters for title/message), [format.ts](src/lib/format.ts), [detectSecretShape.ts](src/lib/detectSecretShape.ts) (mnemonic-vs-WIF classifier used by `login` and the login modal preview).
- **[src/dash/types.ts](src/dash/types.ts)** — shared SDK types (`DashSdk`, `DashKeyManager`, query result shapes) used across every dash helper.
- **[public/dashnote-lite.html](public/dashnote-lite.html)** — single-file zero-build companion. Read-only Recent notes (with optional owner filter) + Get-by-ID only, loads `@dashevo/evo-sdk` from `esm.sh`, and ships alongside the React app at `<...>/dashnote/dashnote-lite.html` (Vite copies `public/*` into `dist/`). Intentionally self-contained as a learning reference — don't import app code into it.
Expand Down
Loading