Repository: amark/gun
Branch: master
Commit: ed27b48569ef
Files: 571
Total size: 3.6 MB
Directory structure:
gitextract_sxejevxy/
├── .dockerignore
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── .npmignore
├── .prettierignore
├── .travis.yml
├── CHANGELOG.md
├── Dockerfile
├── LICENSE.md
├── Procfile
├── README.md
├── RELEASE.md
├── SECURITY.md
├── app.json
├── as.js
├── axe.js
├── bower.json
├── browser.js
├── examples/
│ ├── .gitignore
│ ├── Main.js
│ ├── angular/
│ │ ├── .angular-cli.json
│ │ ├── .editorconfig
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── e2e/
│ │ │ ├── app.e2e-spec.ts
│ │ │ ├── app.po.ts
│ │ │ └── tsconfig.e2e.json
│ │ ├── example_package.json
│ │ ├── karma.conf.js
│ │ ├── protractor.conf.js
│ │ ├── server.js
│ │ ├── src/
│ │ │ ├── app/
│ │ │ │ ├── app.component.css
│ │ │ │ ├── app.component.html
│ │ │ │ ├── app.component.spec.ts
│ │ │ │ ├── app.component.ts
│ │ │ │ ├── app.module.ts
│ │ │ │ ├── gun.helper.ts
│ │ │ │ └── gun.service.ts
│ │ │ ├── assets/
│ │ │ │ └── .gitkeep
│ │ │ ├── environments/
│ │ │ │ ├── environment.prod.ts
│ │ │ │ └── environment.ts
│ │ │ ├── index.html
│ │ │ ├── main.ts
│ │ │ ├── polyfills.ts
│ │ │ ├── styles.css
│ │ │ ├── test.ts
│ │ │ ├── tsconfig.app.json
│ │ │ ├── tsconfig.spec.json
│ │ │ └── typings.d.ts
│ │ ├── tsconfig.json
│ │ └── tslint.json
│ ├── axe.html
│ ├── basic/
│ │ ├── chat.html
│ │ ├── emoji.html
│ │ ├── meet.html
│ │ ├── note.html
│ │ ├── paste.html
│ │ ├── poll.html
│ │ ├── post.html
│ │ ├── private.html
│ │ ├── schedule.html
│ │ ├── screen.html
│ │ ├── stream.html
│ │ ├── tables.html
│ │ ├── upload.html
│ │ ├── user.html
│ │ └── video.html
│ ├── chat/
│ │ ├── index.html
│ │ └── user.html
│ ├── contact/
│ │ └── index.html
│ ├── docs.html
│ ├── express.js
│ ├── game/
│ │ ├── furball.html
│ │ ├── nts.html
│ │ ├── space.html
│ │ └── win.html
│ ├── hapi.js
│ ├── http.js
│ ├── https.sh
│ ├── index.html
│ ├── infinite-scroll/
│ │ ├── ScrollWindow.js
│ │ ├── index.html
│ │ ├── index.js
│ │ └── style.css
│ ├── install.sh
│ ├── jquery.js
│ ├── json/
│ │ └── index.html
│ ├── move/
│ │ └── index.html
│ ├── party.html
│ ├── react/
│ │ ├── README.md
│ │ ├── public/
│ │ │ └── index.html
│ │ ├── src/
│ │ │ ├── App.js
│ │ │ ├── App.test.js
│ │ │ ├── Chat.js
│ │ │ ├── Json.js
│ │ │ ├── Todos.js
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ └── style.css
│ │ └── todo.html
│ ├── react-native/
│ │ ├── .babelrc
│ │ ├── .buckconfig
│ │ ├── .flowconfig
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── .watchmanconfig
│ │ ├── README.md
│ │ ├── android/
│ │ │ ├── app/
│ │ │ │ ├── BUCK
│ │ │ │ ├── build.gradle
│ │ │ │ ├── proguard-rules.pro
│ │ │ │ └── src/
│ │ │ │ └── main/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── assets/
│ │ │ │ │ └── html/
│ │ │ │ │ └── blank.html
│ │ │ │ ├── java/
│ │ │ │ │ └── com/
│ │ │ │ │ └── gundemo/
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ └── MainApplication.java
│ │ │ │ └── res/
│ │ │ │ └── values/
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ ├── build.gradle
│ │ │ ├── gradle/
│ │ │ │ └── wrapper/
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ │ ├── gradle.properties
│ │ │ ├── gradlew
│ │ │ ├── gradlew.bat
│ │ │ ├── keystores/
│ │ │ │ ├── BUCK
│ │ │ │ └── debug.keystore.properties
│ │ │ └── settings.gradle
│ │ ├── app.json
│ │ ├── index.js
│ │ ├── ios/
│ │ │ ├── GunDemo/
│ │ │ │ ├── AppDelegate.h
│ │ │ │ ├── AppDelegate.m
│ │ │ │ ├── Base.lproj/
│ │ │ │ │ └── LaunchScreen.xib
│ │ │ │ ├── Images.xcassets/
│ │ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Info.plist
│ │ │ │ └── main.m
│ │ │ ├── GunDemo-tvOS/
│ │ │ │ └── Info.plist
│ │ │ ├── GunDemo-tvOSTests/
│ │ │ │ └── Info.plist
│ │ │ ├── GunDemo.xcodeproj/
│ │ │ │ └── project.pbxproj
│ │ │ └── GunDemoTests/
│ │ │ ├── GunDemoTests.m
│ │ │ └── Info.plist
│ │ ├── package.json
│ │ ├── shim.js
│ │ └── src/
│ │ ├── App/
│ │ │ ├── Demo.js
│ │ │ ├── PolyFillCrypto.js
│ │ │ ├── app.js
│ │ │ └── index.js
│ │ ├── extensions/
│ │ │ ├── asyncStorageAdapter.js
│ │ │ └── sea.js
│ │ └── webview-crypto/
│ │ ├── MainWorker.d.ts
│ │ ├── MainWorker.js
│ │ ├── WebViewWorker.d.ts
│ │ ├── WebViewWorker.js
│ │ ├── asyncSerialize.d.ts
│ │ ├── asyncSerialize.js
│ │ ├── compat.d.ts
│ │ ├── compat.js
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ ├── serializeBinary.d.ts
│ │ ├── serializeBinary.js
│ │ ├── webViewWorkerString.d.ts
│ │ └── webViewWorkerString.js
│ ├── relay-sqlite-example/
│ │ ├── README.md
│ │ ├── capacitor.config.ts
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── components/
│ │ │ │ └── RelayMode.vue
│ │ │ ├── composables/
│ │ │ │ ├── GunStorageAdapter.ts
│ │ │ │ ├── useNetwork.ts
│ │ │ │ ├── useNetworkStatus.ts
│ │ │ │ └── useToast.ts
│ │ │ ├── main.ts
│ │ │ ├── pages/
│ │ │ │ └── index.vue
│ │ │ ├── router/
│ │ │ │ └── index.ts
│ │ │ ├── services/
│ │ │ │ ├── dbVersionService.ts
│ │ │ │ ├── globalServices.ts
│ │ │ │ ├── initializeAppService.ts
│ │ │ │ ├── sqliteService.ts
│ │ │ │ └── storageService.ts
│ │ │ └── theme/
│ │ │ └── variables.css
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── relay.service
│ ├── smoothie.js
│ ├── start.js.html
│ ├── stats.html
│ ├── style.css
│ ├── todo/
│ │ └── index.html
│ ├── vanilla/
│ │ ├── screen.html
│ │ ├── todo.html
│ │ ├── user.html
│ │ └── video.html
│ ├── vue/
│ │ ├── index.html
│ │ └── todo.html
│ ├── wave.html
│ ├── webpack/
│ │ ├── .gitignore
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── app.js
│ │ │ └── index.html
│ │ └── webpack.config.js
│ └── where/
│ └── index.html
├── gun.d.ts
├── gun.js
├── hooks/
│ ├── build
│ └── post_push
├── index.d.ts
├── index.js
├── kit/
│ ├── web.css
│ └── web.js
├── lib/
│ ├── afore.js
│ ├── aws.js
│ ├── axe.js
│ ├── book.js
│ ├── bye.js
│ ├── crashed.js
│ ├── cryptomodules.js
│ ├── debug.js
│ ├── dom.js
│ ├── email.js
│ ├── erase.js
│ ├── evict.js
│ ├── file.js
│ ├── forget.js
│ ├── fork.js
│ ├── fsrm.js
│ ├── fun.js
│ ├── hot.js
│ ├── http.js
│ ├── hub.js
│ ├── ipfs.js
│ ├── ison.js
│ ├── jsonp.js
│ ├── later.d.ts
│ ├── later.js
│ ├── les.js
│ ├── level.js
│ ├── lex.js
│ ├── list.js
│ ├── load.d.ts
│ ├── load.js
│ ├── match.js
│ ├── memdisk.js
│ ├── meta.js
│ ├── mix.js
│ ├── mobile.js
│ ├── monotype.js
│ ├── multicast.js
│ ├── nomem.js
│ ├── normalize.js
│ ├── not.d.ts
│ ├── not.js
│ ├── open.d.ts
│ ├── open.js
│ ├── path.d.ts
│ ├── path.js
│ ├── promise.d.ts
│ ├── promise.js
│ ├── radisk.d.ts
│ ├── radisk.js
│ ├── radisk2.js
│ ├── radix.d.ts
│ ├── radix.js
│ ├── radix2.js
│ ├── radmigtmp.js
│ ├── ras.js
│ ├── reboot.js
│ ├── rfs.js
│ ├── rfsmix.js
│ ├── rindexed.d.ts
│ ├── rindexed.js
│ ├── rls.js
│ ├── rmem.js
│ ├── role.js
│ ├── rs3.js
│ ├── serve.js
│ ├── server.js
│ ├── service.js
│ ├── shim.js
│ ├── space.js
│ ├── stats.js
│ ├── store.d.ts
│ ├── store.js
│ ├── super.js
│ ├── text-encoding/
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── encoding-indexes.js
│ │ │ └── encoding.js
│ │ └── package.json
│ ├── then.d.ts
│ ├── then.js
│ ├── time.js
│ ├── unbuild.js
│ ├── unset.d.ts
│ ├── unset.js
│ ├── untitled.js
│ ├── upload.js
│ ├── utils.js
│ ├── uws.js
│ ├── verify.js
│ ├── wave.js
│ ├── webrtc.d.ts
│ ├── webrtc.js
│ ├── wire.js
│ ├── ws.js
│ ├── wsp.js
│ ├── wsproto.js
│ └── yson.js
├── nts.js
├── package.json
├── rad.js
├── sea/
│ ├── aeskey.js
│ ├── array.js
│ ├── auth.js
│ ├── base64.js
│ ├── buffer.js
│ ├── certify.js
│ ├── create.js
│ ├── decrypt.js
│ ├── encrypt.js
│ ├── https.js
│ ├── index.js
│ ├── pair.js
│ ├── recall.js
│ ├── root.js
│ ├── sea.js
│ ├── secret.js
│ ├── settings.js
│ ├── sha1.js
│ ├── sha256.js
│ ├── share.js
│ ├── shim.js
│ ├── sign.js
│ ├── then.js
│ ├── user.js
│ ├── verify.js
│ └── work.js
├── sea.d.ts
├── sea.js
├── src/
│ ├── ask.js
│ ├── back.js
│ ├── book.js
│ ├── chain.js
│ ├── core.js
│ ├── dup.js
│ ├── get.js
│ ├── index.js
│ ├── localStorage.js
│ ├── map.js
│ ├── mesh.js
│ ├── on.js
│ ├── onto.js
│ ├── polyfill/
│ │ └── unbuild.js
│ ├── put.js
│ ├── root.js
│ ├── set.js
│ ├── shim.js
│ ├── state.js
│ ├── valid.js
│ └── websocket.js
├── test/
│ ├── abc.js
│ ├── bug/
│ │ ├── 121.js
│ │ ├── 1243.js
│ │ ├── 322.js
│ │ ├── 686.js
│ │ └── 783.js
│ ├── common.js
│ ├── debug/
│ │ └── deep-set.html
│ ├── download-log.html
│ ├── expect.js
│ ├── gun.html
│ ├── https/
│ │ ├── ca.crt
│ │ ├── ca.csr
│ │ ├── ca.key
│ │ ├── server.crt
│ │ ├── server.csr
│ │ ├── server.key
│ │ ├── server.key.passphrase
│ │ └── test.js
│ ├── hub/
│ │ ├── .hubignore
│ │ ├── hub-test.js
│ │ ├── index.html
│ │ └── whatever/
│ │ └── aws-key.txt
│ ├── index.js
│ ├── json2.js
│ ├── mocha.css
│ ├── mocha.html
│ ├── mocha.js
│ ├── normalize/
│ │ └── normalize.html
│ ├── old/
│ │ ├── all.js
│ │ ├── interface.js
│ │ ├── performance.js
│ │ ├── s3pricing.html
│ │ ├── server.js
│ │ ├── set.js
│ │ ├── shoot.html
│ │ ├── shoot.js
│ │ ├── shotgun.js
│ │ ├── timelines.txt
│ │ └── tmp.js
│ ├── panic/
│ │ ├── 1putackget.js
│ │ ├── 2getget.js
│ │ ├── 3puts.js
│ │ ├── 4putackdedup.js
│ │ ├── axe/
│ │ │ ├── 1no_self.js
│ │ │ ├── 2no_dup.js
│ │ │ ├── 3get_turns.js
│ │ │ ├── 4get_subs.js
│ │ │ ├── 5mob.js
│ │ │ ├── index.html
│ │ │ └── load_balance.js
│ │ ├── b2s2s2b.js
│ │ ├── bulkimport.js
│ │ ├── chat-user.js
│ │ ├── chat.js
│ │ ├── curl-server.js
│ │ ├── e2e/
│ │ │ ├── distributed.js
│ │ │ ├── holy/
│ │ │ │ ├── grail.js
│ │ │ │ ├── gun-server.js
│ │ │ │ ├── index.html
│ │ │ │ └── ports.json
│ │ │ └── package.json
│ │ ├── holy-grail.js
│ │ ├── index.html
│ │ ├── infinite-scroll/
│ │ │ ├── index.html
│ │ │ └── index.js
│ │ ├── large-nodes.js
│ │ ├── latency.js
│ │ ├── level.js
│ │ ├── lexical.js
│ │ ├── livestream.js
│ │ ├── load.js
│ │ ├── no-override.js
│ │ ├── on-recovery.js
│ │ ├── radisk.js
│ │ ├── radisk_split_failure.js
│ │ ├── s2s-all-delayed-peer-add.js
│ │ ├── s2s-all.js
│ │ ├── scale.js
│ │ ├── set.js
│ │ ├── shocknet.js
│ │ ├── speak.js
│ │ ├── thread.js
│ │ ├── user-paste.js
│ │ ├── users.js
│ │ ├── util/
│ │ │ ├── load-browser-scripts.js
│ │ │ └── open.js
│ │ └── who.js
│ ├── panic.html
│ ├── ptsd/
│ │ ├── benchmark.js
│ │ ├── memdisk.html
│ │ ├── memdisk.js
│ │ ├── memory.html
│ │ ├── perf.js
│ │ ├── ptsd.html
│ │ ├── ptsd.js
│ │ ├── radix.html
│ │ ├── radix.js
│ │ ├── spam.js
│ │ ├── stool.css
│ │ └── streampipe.js
│ ├── rad/
│ │ ├── 2020and2021.js
│ │ ├── bench.js
│ │ ├── book.html
│ │ ├── book.js
│ │ ├── browser.html
│ │ ├── crash.js
│ │ ├── mocha.html
│ │ ├── old2020json/
│ │ │ ├── !
│ │ │ └── %1C
│ │ ├── parse.rad
│ │ ├── rad.book.spec.js
│ │ ├── rad.js
│ │ └── recover.js
│ ├── radix.js
│ ├── sea/
│ │ ├── nodeauth.js
│ │ ├── sea-tmp.html
│ │ ├── sea.html
│ │ ├── sea.js
│ │ └── sea_old.js
│ ├── server/
│ │ ├── http.js
│ │ ├── node-client.js
│ │ └── node-write.js
│ ├── tmp/
│ │ ├── bigsync.js
│ │ ├── contact.html
│ │ ├── contacts.html
│ │ ├── indexedDB.html
│ │ ├── mitra/
│ │ │ ├── client_to_server.js
│ │ │ └── gun_https2.js
│ │ ├── radisk.html
│ │ ├── say.html
│ │ ├── seanode.js
│ │ ├── space.html
│ │ ├── time.html
│ │ └── tmp.html
│ ├── trace.html
│ ├── trace.js
│ └── wire.txt
├── tsconfig.json
└── types/
├── gun/
│ ├── GunCallbackGet.d.ts
│ ├── GunCallbackMap.d.ts
│ ├── GunCallbackOn.d.ts
│ ├── GunCallbackOnce.d.ts
│ ├── GunCallbackPut.d.ts
│ ├── GunDataNode.d.ts
│ ├── GunHookCallbackBye.d.ts
│ ├── GunHookCallbackCreate.d.ts
│ ├── GunHookCallbackGet.d.ts
│ ├── GunHookCallbackHi.d.ts
│ ├── GunHookCallbackIn.d.ts
│ ├── GunHookCallbackOpt.d.ts
│ ├── GunHookCallbackOut.d.ts
│ ├── GunHookCallbackPut.d.ts
│ ├── GunNodeGet.d.ts
│ ├── GunNodePut.d.ts
│ ├── GunOptions.d.ts
│ ├── GunOptionsOn.d.ts
│ ├── GunOptionsOnce.d.ts
│ ├── GunOptionsPut.d.ts
│ ├── GunPeer.d.ts
│ ├── GunSchema.d.ts
│ ├── GunSoul.d.ts
│ ├── GunValueSimple.d.ts
│ ├── IGun.d.ts
│ ├── IGunChain.d.ts
│ ├── IGunHookContext.d.ts
│ ├── IGunInstance.d.ts
│ ├── IGunInstanceHookHandler.d.ts
│ ├── IGunInstanceRoot.d.ts
│ ├── IGunMeta.d.ts
│ ├── IGunOnEvent.d.ts
│ ├── LEX.d.ts
│ ├── LEXQuery.d.ts
│ ├── _GunRoot.d.ts
│ ├── index.d.ts
│ └── pany.d.ts
├── index.d.ts
├── sea/
│ ├── GunCallbackUserAuth.d.ts
│ ├── GunCallbackUserCreate.d.ts
│ ├── GunHookCallbackAuth.d.ts
│ ├── GunUser.d.ts
│ ├── IGun.d.ts
│ ├── IGunInstance.d.ts
│ ├── IGunInstanceHookHandler.d.ts
│ ├── IGunInstanceRoot.d.ts
│ ├── IGunUserInstance.d.ts
│ ├── IPolicy.d.ts
│ ├── ISEA.d.ts
│ ├── ISEAPair.d.ts
│ ├── OptionsUserAuth.d.ts
│ ├── OptionsUserRecall.d.ts
│ ├── Policy.d.ts
│ └── index.d.ts
├── test/
│ ├── gun-back.test-d.ts
│ ├── gun-get.test-d.ts
│ ├── gun-instance.test-d.ts
│ ├── gun-map.test-d.ts
│ ├── gun-on.test-d.ts
│ ├── gun-once.test-d.ts
│ ├── gun-opt.test-d.ts
│ ├── gun-put.test-d.ts
│ ├── gun-set.test-d.ts
│ ├── gun-user-auth.test-d.ts
│ ├── gun-user-leave.test-d.ts
│ ├── gun-user-recall.test-d.ts
│ ├── gun-user.test-d.ts
│ ├── sea-certify.test-d.ts
│ └── sea.test-d.ts
└── utils.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
node_modules
radata
stats.radata
.git
.gitignore
*.md
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: amark
patreon: gunDB
open_collective: gun
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
================================================
FILE: .github/workflows/ci.yml
================================================
name: ci
on:
push:
pull_request:
jobs:
test:
strategy:
matrix:
node-version: [14.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
# checkout the code
- name: Checkout
uses: actions/checkout@v4 # Updated to v4 (latest as of 2025)
# verify the version in package.json matches the release tag
- name: Version
uses: tcurdt/action-verify-version-npm@master # No version update as it's using @master
# setup the node version
- name: Setup Node ${{ matrix.node-version }}
uses: actions/setup-node@v4 # Updated to v4 (latest as of 2025)
with:
node-version: ${{ matrix.node-version }}
# cache node_modules if we can
- name: Cache
id: cache-modules
uses: actions/cache@v4 # Updated to v4 (latest as of 2025)
with:
path: node_modules
key: ${{ matrix.node-version }}-${{ runner.os }}-build-${{ hashFiles('package.json') }}
# otherwise run install
- name: Install
if: steps.cache-modules.outputs.cache-hit != 'true'
run: npm install
# run tests
- name: Test
run: npm test
# create github release
release:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
needs: [test]
runs-on: ubuntu-latest
steps:
# create github release (which triggers the release workflows)
- name: Release
uses: softprops/action-gh-release@v2 # Updated to v2 (latest stable version as of 2025)
# env:
# GITHUB_TOKEN: ${{ secrets.PAT }}
# # publish latest master or release to dockerhub
# dockerhub:
# if: github.event_name == 'push'
# needs: [test]
# runs-on: ubuntu-latest
# env:
# image: ${{ secrets.DOCKERHUB_USERNAME }}/gun
# steps:
#
# - name: Checkout
# uses: actions/checkout@v4 # Updated to v4
#
# - name: Login
# env:
# DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
# DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
# run: echo -n ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
#
# - name: Build
# run: |
# echo "SHA=$GITHUB_SHA"
# docker build --build-arg SHA=$GITHUB_SHA \
# BUILD_DATE=$(date +'%Y-%m-%dT%H:%M:%S') \
# VCS_REF=${GITHUB_REF} \
# VCS_URL=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} \
# VERSION=${GITHUB_REF##*/} \
# SHA=$GITHUB_SHA \
# --label "SHA=$GITHUB_SHA" \
# --tag ${{ env.image }}:${GITHUB_REF##*/} \
# --tag ${{ env.image }}:latest \
# .
#
# - name: Push
# run: docker push ${{ env.image }}
# publish release to npm
npm:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
needs: [test]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4 # Updated to v4
- name: Publish
env:
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
run: |
npm config set //registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN
npm install
npm publish --access=public
================================================
FILE: .gitignore
================================================
node_modules
npm-debug.log
yarn.lock
*data.json
*data*
*.db
.idea/
*.bak
*.new
*.log
v8.json
*.DS_store
isolate*.log
.esm-cache
.sessionStorage
.localStorage
/types/**/*.ts
!/types/**/*.d.ts
!/types/**/*.test-d.ts
/gun.ts
/temp/
================================================
FILE: .npmignore
================================================
*.ts
/temp/
!*.d.ts
*.radata
isolate-*
================================================
FILE: .prettierignore
================================================
*
================================================
FILE: .travis.yml
================================================
language: node_js
branches:
except:
- debug
- manhattan
node_js:
- 10
cache:
directories:
- node_modules
================================================
FILE: CHANGELOG.md
================================================
# CHANGELOG
## 0.2020.x
`>0.2020.520` may break in-process `gun1` `gun2` message passing. Check `test/common.js` "Check multi instance message passing" for a hint and/or complain on community chat.
- No breaking changes to core API.
- Storage adapter `put` event breaking change (temporary?), RAD is official now and storage adapters should be RAD plugins instead of GUN adapters.
- GUN soul format changed from being a random UUID to being a more predictable graph path (of where initially created) to support even better offline behavior. This means `null`ing & replacing an object will not create a new but re-merge.
- Pretty much all internal GUN utility will be deleted, these are mostly undocumented but will affect some people - they will still be available as a separate file but deprecated.
- As the DHT gets implemented, your relay peers may automatically connect to it, so do not assume your peer is standalone. `Gun({axe: false` should help prevent this but loses you most scaling properties.
- The 2019 -> 2020 "changes" are happening gradually, based on experimental in-production tests.
- As always, **most important** is to ask in the [community chat](http://chat.gun.eco) if you have any issues, and to keep up to date with changes.
## 0.2019.x
Some RAD & SEA data format changes, but with as much backward compatibility as possible, tho ideally should be dropped.
## 0.9.x
No breaking changes, but the new Radix Storage Engine (RSE) has been finally integrated and works with S3 as a backup.
// Edit: commentary removed.
## 0.8.x
Adapter interfaces have changed from `Gun.on('event', cb)` to `gun.on('event', cb)`, this will force adapters to be instance specific.
`.path()` and `.not()` have been officially removed from the core bundle, you can bundle them yourself at `lib/path.js` and `lib/not.js` if you still need them.
## 0.7.x
Small breaking change to `.val(cb)`:
Previously `.val(cb)` would ONLY be called when data exists, like `.on(cb)`.
However, due to popular demand, people wanted `.val(cb)` to also get called for `.not(cb)` rather than (before) it would "wait" until data arrived.
NOTE: For dynamic paths, `.val(cb)` will still wait, like:
`gun.get('users').map().val(cb)` because the behavior of the `map()` is simply to not fire anything down the chain unless items are found.
## 0.6.x
Introduced experimental features, chaining `.val()` (no callback) and `.map(cb)` behaving as a map/reduce function.
It also upgraded the socket adapters and did end-to-end load testing and correctness testing.
## 0.5.9
GUN 0.3 -> 0.4 -> 0.5 Migration Guide:
`gun.back` -> `gun.back()`;
`gun.get(key, cb)` -> cb(err, data) -> cb(at) at.err, at.put;
`gun.map(cb)` -> `gun.map().on(cb)`;
`gun.init` -> deprecated;
`gun.put(data, cb)` -> cb(err, ok) -> cb(ack) ack.err, ack.ok;
`gun.get(key)` global/absolute -> `gun.back(-1).get(key)`;
`gun.key(key)` -> temporarily broken;
## 0.3.7
- Catch localStorage errors.
## 0.3.6
- Fixed S3 typo.
## 0.3.5
- Fixed server push.
## 0.3.4
- Breaking Change! `list.set(item)` returns the item's chain now, not the list chain.
- Client and Server GUN servers are now more up to spec, trimmed excess HTTP/REST header data.
- Gun.is.lex added.
## 0.3.3
- You can now link nodes natively, `gun.get('mark').path('owner').put(gun.get('cat'))`!
- Sets (or tables, collections, lists) are now easily done with `gun.get('users').set(gun.get('person/mark'))`.
## 0.3.2
Bug fixes.
## 0.3.1
Bug fixes.
## 0.3
Migration Guide! Migrate by changing `.attach(` to `.wsp(` on your server if you have one with gun. Remove `.set()` (delete it), and change `.set($DATA)` (where you call set with something) to `.path('I' + Date.now() + 'R' + Gun.text.random(5)).put($DATA)`. If you have NodeJS style callbacks in your `.get` (which documentation previously recommended that you shouldn't) they previous took `err, graph` and now they take `err, node` (which means now using callback style is fine to use). Inside of `.not()` no longer use `return` or `this`, instead (probably) use `gun` and no `return`. If you are a module developer, use `opt.wire` now instead of `opt.hooks` and message Mark since he needs to talk to you since the wire protocol has changed.
- Server side default `.wsp()` renamed from `.attach()`.
- `.set()` deprecated because it did a bunch of random inconsistent things. Its useful behavior has now become implicit (see below) or can be done explicitly.
- `.not()` it was previously common to `return` the chain inside of .not, beware that if you have code like `gun.get(key).not(function(){ return this.put({}).key(key) }).val()` cause `.val()` to be triggered twice (this is intentional, because it funnels two separate chains together) which previously didn't happen. To fix this, just don't return the chain.
- `.put()` and `.path()` do implicit `.init()` by default, turn on explicit behavior with `Gun({init: true})`.
- `.get(soul, cb)` cb is called back with `err, node` rather than `err, graph`.
- Options `opt.wire` renamed from `opt.hooks`.
- `.val()` when called empty automatically cleanly logs for convenience purposes.
- `.init()` added.
- `Gun.is.val` renamed from `Gun.is.value`.
- `Gun.is.rel` renamed from `Gun.is.soul`.
- `Gun.is.node.soul` renamed from `Gun.is.soul.on`.
- `Gun.union.ify` renamed from `Gun.union.pseudo`.
- `Gun.union.HAM` renamed from `Gun.HAM`.
- `Gun.HAM` is now the actual HAM function for conflict resolution.
- `Gun._.state` renamed from `Gun._.HAM`.
- Maximum Callstack Exceeded is less problematic now, unless you intentionally choke the thread. #95
- Putting a regex or Date or NaN is actually detected and causes an error now while before it was silent. #122 #123
- `.on()` gets called when a key is later newly made while before it did not. #116
- `.val()` should not ever get called with a relation alone (internals should resolve it), this is fixed. #132
================================================
FILE: Dockerfile
================================================
# install packages
FROM node:lts-alpine as builder
RUN mkdir /work
WORKDIR /work
RUN apk add --no-cache alpine-sdk python3
COPY package*.json ./
RUN mkdir -p node_modules
RUN npm ci --only=production
# fresh image without dev packages
FROM node:lts-alpine
# build-time metadata as defined at http://label-schema.org
ARG BUILD_DATE
ARG VCS_REF
ARG VCS_URL
ARG VERSION
LABEL org.label-schema.build-date=$BUILD_DATE \
org.label-schema.name="Gun - Offline First, Javascript Graph Database" \
org.label-schema.url="http://gun.js.org" \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.vcs-url=$VCS_URL \
org.label-schema.vendor="The Gun Database Team" \
org.label-schema.version=$VERSION \
org.label-schema.schema-version="1.0"
ARG SHA
RUN mkdir /work
WORKDIR /work
COPY --from=builder /work/node_modules ./node_modules
RUN npm rebuild -q
ADD . .
RUN echo "{ \"sha\": \"$SHA\" }" > version.json
RUN cat version.json
EXPOSE 8080
EXPOSE 8765
CMD ["npm","start"]
================================================
FILE: LICENSE.md
================================================
Copyright (c) 2015 Mark Nadal
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
Copyright (c) 2015 Mark Nadal
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgement in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
---
Copyright 2015 Mark Nadal
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Procfile
================================================
web: node --inspect examples/http.js
================================================
FILE: README.md
================================================
[](https://www.jsdelivr.com/package/npm/gun)

[](http://chat.gun.eco)
**GUN** is an [ecosystem](https://gun.eco/docs/Ecosystem) of **tools** that let you build [community run](https://www.nbcnews.com/tech/tech-news/these-technologists-think-internet-broken-so-they-re-building-another-n1030136) and [encrypted applications](https://gun.eco/docs/Cartoon-Cryptography) - like an Open Source Firebase or a Decentralized Dropbox.
The [Internet Archive](https://news.ycombinator.com/item?id=17685682) and [100s of other apps](https://github.com/amark/gun/wiki/awesome-gun) run GUN in-production.
+ Multiplayer by default with realtime p2p state synchronization!
+ Graph data lets you use key/value, tables, documents, videos, & more!
+ Local-first, offline, and decentralized with end-to-end encryption.
Decentralized alternatives to [Zoom](https://www.zdnet.com/article/era-hatches-meething-an-open-source-browser-based-video-conferencing-system/), [Reddit](https://notabug.io/t/whatever/comments/36588a16b9008da4e3f15663c2225e949eca4a15/gpu-bot-test), [Instagram](https://iris.to/), [Slack](https://iris.to/), [YouTube](https://d.tube/), [Stripe](https://twitter.com/marknadal/status/1422717427427647489), [Wikipedia](https://news.ycombinator.com/item?id=17685682), Facebook [Horizon](https://twitter.com/marknadal/status/1424476179189305347) and more have already pushed terabytes of daily P2P traffic on GUN. We are a [friendly community](http://chat.gun.eco/) creating a [free fun future for freedom](https://youtu.be/1HJdrBk3BlE):
## Quickstart
GUN is *super easy* to get started with:
- Try the [interactive tutorial](https://gun.eco/docs/Todo-Dapp) in the browser (**5min** ~ average developer).
- Or `npm install gun` and run the examples with `cd node_modules/gun && npm start` (**5min** ~ average developer).
> **Note:** If you don't have [node](http://nodejs.org/) or [npm](https://www.npmjs.com/), read [this](https://github.com/amark/gun/blob/master/examples/install.sh) first.
> If the `npm` command line didn't work, you may need to `mkdir node_modules` first or use `sudo`.
- An online demo of the examples are available here: http://try.axe.eco/
- Or write a quick app: ([try now in a playground](https://jsbin.com/kadobamevo/edit?js,console))
```html
```
- Or try something **mind blowing**, like saving circular references to a table of documents! ([play](http://jsbin.com/wefozepume/edit?js,console))
```javascript
cat = {name: "Fluffy", species: "kitty"};
mark = {boss: cat};
cat.slave = mark;
// partial updates merge with existing data!
gun.get('mark').put(mark);
// access the data as if it is a document.
gun.get('mark').get('boss').get('name').once(function(data, key){
// `once` grabs the data once, no subscriptions.
console.log("Mark's boss is", data);
});
// traverse a graph of circular references!
gun.get('mark').get('boss').get('slave').once(function(data, key){
console.log("Mark is the cat's slave!", data);
});
// add both of them to a table!
gun.get('list').set(gun.get('mark').get('boss'));
gun.get('list').set(gun.get('mark'));
// grab each item once from the table, continuously:
gun.get('list').map().once(function(data, key){
console.log("Item:", data);
});
// live update the table!
gun.get('list').set({type: "cucumber", goal: "jumping cat"});
```
Want to keep building more? **Jump to [THE DOCUMENTATION](#documentation)!**
# About
First & foremost, GUN is **a community of the nicest and most helpful people** out there. So [I want to invite you](http://chat.gun.eco) to come tell us about what **you** are working on & wanting to build (new or old school alike! Just be nice as well.) and ask us your questions directly. :)
The GUN ecosystem stack is a collection of independent and modular tools covering everything from [CRDT](https://crdt.tech/) [conflict resolution](https://gun.eco/distributed/matters.html), [cryptographic security](https://gun.eco/docs/Cartoon-Cryptography) & [encryption](https://gun.eco/docs/SEA), [radix storage serialization](https://gun.eco/docs/RAD), [mesh networking](https://gun.eco/docs/DAM) & [routing algorithms](https://gun.eco/docs/Routing), to distributed systems [correctness & load testing](https://github.com/gundb/panic-server), CPU scheduled [JSON parser](https://github.com/amark/gun/blob/master/lib/yson.js) to prevent UI lag, and more!
On that note, let's get some official shout outs covered first:
### Support
Thanks to:
Robert Heessels,
Lorenzo Mangani,
NLnet Foundation,
Sam Liu,
Daniel Dombrowsky,
Vincent Woo,
AJ ONeal,
Bill Ottman,
Mike Lange,
Sean Matheson,
Alan Mimms,
Dário Freire,
John Williamson,
Robin Bron,
Elie Makhoul,
Mike Staub,
Bradley Matusiak,
Jeff Cook,
Nico,
Aaron Artille,
Tim Robinson,
Fabian Stamm,
Mike Staub,
Hunter Owens,
Jacob Millner,
Gerrit Balindt,
Gabriel Lemon,
Murage Martin,
Jason Stallings
- Join others in sponsoring code: https://www.patreon.com/gunDB !
- Ask questions: http://stackoverflow.com/questions/tagged/gun ?
- Found a bug? Report at: https://github.com/amark/gun/issues ;
- **Need help**? Chat with us: http://chat.gun.eco .
### History
[GUN](https://gun.eco) was created by [Mark Nadal](https://twitter.com/marknadal) in 2014 after he had spent 4 years trying to get his collaborative web app to scale up with traditional databases.
After he realized [Master-Slave database architecture causes one big bottleneck](https://gun.eco/distributed/matters.html), he (as a complete newbie outsider) naively decided **to question the status quo** and shake things up with controversial, heretical, and contrarian experiments:
**The NoDB** - no master, no servers, no "single source of truth", not built with a real programming language or real hardware, no DevOps, no locking, not *just* SQL or NoSQL but both (**all** - graphs, documents, tables, key/value).
The goal was to build a P2P database that could survive living inside **any** browser, and could correctly sync data between **any** device after assuming **any** offline-first activity.
Technically, **GUN is a graph synchronization protocol** with a *lightweight embedded engine*, capable of doing *[20M+ API ops/sec](https://gun.eco/docs/Performance)* in **just ~9KB gzipped size**.
## Documentation
This would not be possible without **community contributors**, big shout out to:
**[ajmeyghani](https://github.com/ajmeyghani) ([Learn GUN Basics with Diagrams](https://medium.com/@ajmeyghani/gundb-a-graph-database-in-javascript-3860a08d873c))**; **[anywhichway](https://github.com/anywhichway) ([Block Storage](https://github.com/anywhichway/gun-block))**; **[beebase](https://github.com/beebase) ([Quasar](https://github.com/beebase/gun-vuex-quasar))**; **[BrockAtkinson](https://github.com/BrockAtkinson) ([brunch config](https://github.com/BrockAtkinson/brunch-gun))**; **[Brysgo](https://github.com/brysgo) ([GraphQL](https://github.com/brysgo/graphql-gun))**; **[d3x0r](https://github.com/d3x0r) ([SQLite](https://github.com/d3x0r/gun-db))**; **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; **[hillct](https://github.com/hillct) (Docker)**; **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[JuniperChicago](https://github.com/JuniperChicago) ([cycle.js bindings](https://github.com/JuniperChicago/cycle-gun))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; **[kristianmandrup](https://github.com/kristianmandrup) ([edge](https://github.com/kristianmandrup/gun-edge))**; **[Lightnet](https://github.com/Lightnet)** ([Awesome Vue User Examples](https://glitch.com/edit/#!/jsvuegunui?path=README.md:1:0) & [User Kitchen Sink Playground](https://gdb-auth-vue-node.glitch.me/)); **[lmangani](https://github.com/lmangani) ([Cytoscape Visualizer](https://github.com/lmangani/gun-scape), [Cassandra](https://github.com/lmangani/gun-cassandra), [Fastify](https://github.com/lmangani/fastify-gundb), [LetsEncrypt](https://github.com/lmangani/polyGun-letsencrypt))**; **[mhelander](https://github.com/mhelander) ([SEA](https://github.com/amark/gun/blob/master/sea.js))**; [omarzion](https://github.com/omarzion) ([Sticky Note App](https://github.com/omarzion/stickies)); [PsychoLlama](https://github.com/PsychoLlama) ([LevelDB](https://github.com/PsychoLlama/gun-level)); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; **[robertheessels](https://github.com/swifty) ([gun-p2p-auth](https://github.com/swifty/gun-p2p-auth))**; **[rogowski](https://github.com/rogowski) (AXE)**; [sbeleidy](https://github.com/sbeleidy); **[sbiaudet](https://github.com/sbiaudet) ([C# Port](https://github.com/sbiaudet/cs-gun))**; **[Sean Matheson](https://github.com/ctrlplusb) ([Observable/RxJS/Most.js bindings](https://github.com/ctrlplusb/gun-most))**; **[Shadyzpop](https://github.com/Shadyzpop) ([React Native example](https://github.com/amark/gun/tree/master/examples/react-native))**; **[sjones6](https://github.com/sjones6) ([Flint](https://github.com/sjones6/gun-flint))**; RIP **[Stefdv](https://github.com/stefdv) (Polymer/web components)**; **[zrrrzzt](https://github.com/zrrrzzt) ([JWT Auth](https://gist.github.com/zrrrzzt/6f88dc3cedee4ee18588236756d2cfce))**; **[xmonader](https://github.com/xmonader) ([Python Port](https://github.com/xmonader/pygundb))**;
I am missing many others, apologies, will be adding them soon! This list is infinitely old & way out of date, if you want to be listed in it please make a PR! :)
## Testing
You will need to `npm install -g mocha` first. Then in the gun root folder run `npm test`. Tests will trigger persistent writes to the DB, so subsequent runs of the test will fail. You must clear the DB before running the tests again. This can be done by running `rm -rf *data*` command in the project directory.
## Shims
> These are only needed for NodeJS & React Native, they shim the native Browser WebCrypto API.
If you want to use [SEA](https://gun.eco/docs/SEA) for `User` auth and security, you will need to install:
`npm install @peculiar/webcrypto --save`
Please see [our React Native docs](https://gun.eco/docs/React-Native) for installation instructions!
Then you can require [SEA](https://gun.eco/docs/SEA) without an error:
```javascript
GUN = require('gun/gun');
SEA = require('gun/sea');
```
## Deploy
> Note: The default examples that get auto-deployed on `npm start` CDN-ify all GUN files, modules, & storage.
> Note: Moving forward, AXE will start to automatically cluster your peer into a shared DHT. You may want to disable this to run an isolated network.
> Note: When deploying a web application using GUN on a cloud provider, you may have to set `CI=false` in your `.env`. This prevents GUN-specific warnings from being treated as errors when deploying your app. You may also resolve this by modifying your webpack config to not try to build the GUN dependencies.
To quickly spin up a GUN relay peer for your development team, utilize [Heroku](http://heroku.com), [Docker](http://docker.com), or any others listed below. Or some variant thereof [Dokku](http://dokku.viewdocs.io/dokku/), K8s, etc. ! Or use all of them so your relays are decentralized too!
### Linux
`SSH` into the home directory of a clean OS install with `sudo` ability. Set any environment variables you need (see below), then do:
```bash
curl -o- https://raw.githubusercontent.com/amark/gun/master/examples/install.sh | bash
```
> Read [install.sh](https://github.com/amark/gun/blob/master/examples/install.sh) first!
> If `curl` is not found, *copy&paste* the contents of install.sh into your ssh.
You can now safely `CTRL+A+D` to escape without stopping the peer. To stop everything `killall screen` or `killall node`.
Environment variables may need to be set like `export HTTPS_CERT=~/cert.pem HTTPS_KEY=~/key.pem PORT=443`. You can also look at a sample [nginx](https://gun.eco/docs/nginx) config. For production deployments, you probably will want to use something like `pm2` or better to keep the peer alive after machine reboots.
### [Dome](https://www.trydome.io/)
[Deploy GUN in one-click](https://app.trydome.io/signup?package=gun) with [Dome](https://trydome.io) and receive a free trial:
[](https://app.trydome.io/signup?package=gun)
### [Heroku](https://www.heroku.com/)
[](https://heroku.com/deploy?template=https://github.com/amark/gun)
> Heroku deletes your data every 15 minutes, one way to fix this is by adding [cheap storage](https://gun.eco/docs/Using-Amazon-S3-for-Storage).
Or:
```bash
git clone https://github.com/amark/gun.git
cd gun
heroku create
git push -f heroku HEAD:master
```
Then visit the URL in the output of the 'heroku create' step, in a browser. Make sure to set any environment config vars in the settings tab.
### [Zeet.co](https://www.zeet.co/)
[](https://deploy.zeet.co/?url=https://github.com/amark/gun)
Then visit the URL in the output of the 'now --npm' step, in your browser.
### [Docker](https://www.docker.com/)
> Warning: Docker image is community contributed and may be old with missing security updates, please check version numbers to compare.
[](https://hub.docker.com/r/gundb/gun/) [](https://microbadger.com/images/gundb/gun "Get your own image badge on microbadger.com") [](https://hub.docker.com/r/gundb/gun/) [](https://hub.docker.com/r/gundb/gun/)
Pull from the [Docker Hub](https://hub.docker.com/r/gundb/gun/) [](https://microbadger.com/images/gundb/gun). Or:
```bash
docker run -p 8765:8765 gundb/gun
```
Or build the [Docker](https://docs.docker.com/engine/installation/) image locally:
```bash
git clone https://github.com/amark/gun.git
cd gun
docker build -t myrepo/gundb:v1 .
docker run -p 8765:8765 myrepo/gundb:v1
```
Or, if you prefer your Docker image with metadata labels (Linux/Mac only):
```bash
npm run docker
docker run -p 8765:8765 username/gun:git
```
Then visit [http://localhost:8765](http://localhost:8765) in your browser.
## License
Designed with ♥ by Mark Nadal, the GUN team, and many amazing contributors.
Openly licensed under [Zlib / MIT / Apache 2.0](https://github.com/amark/gun/blob/master/LICENSE.md).
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Famark%2Fgun?ref=badge_large)
[YouTube](https://www.youtube.com/channel/UCQAtpf-zi9Pp4__2nToOM8g) . [Twitter](https://twitter.com/marknadal)
================================================
FILE: RELEASE.md
================================================
Every push or pull request will
- run the tests
Every push to master will
- run the tests
- publish the latest docker image to dockerhub
Creating a tag that starts with `v` will
- create a new github release
- publish the release to npm
- publish the release to dockerhub
Creating a release from the github web interface will
- publish the release to npm
- publish the release to dockerhub
Creating the release for version `0.2021.001` from the command line works as follows
git tag v0.2021.001
git push --tags
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Introduction
Security is our top priority. We are committed to ensuring that our project is as secure as possible for everyone who uses it. This document outlines our security policy and procedures for dealing with security issues.
## Supported Versions
We provide security updates for the following versions of our project:
| Version | Supported |
| ------- | ------------------ |
| 0.2020.x| :white_check_mark: |
| < 0.2020| :x: |
## Reporting a Vulnerability
If you discover a vulnerability, we would like to know about it so we can take steps to address it as quickly as possible.
### Report Format
When reporting vulnerabilities, please include the following details:
- Description of the vulnerability
- Steps to reproduce the issue
- Potential impact if left unaddressed
- Suggested mitigation or resolution if any
### Response Time
We aim to confirm the receipt of your vulnerability report within 48 hours. Depending on the severity and complexity of the issue, we strive to investigate the issue and provide an initial response within a week.
### Disclosure Policy
If the vulnerability is confirmed, we will work on a fix and plan a release. We ask that you do not publicly disclose the issue until it has been addressed by us.
## Security Practices
We follow industry-standard security practices, including regular audits of the services and features we provide, to maintain the trust of our users.
## Security Updates
We will communicate any security updates through our standard communication channels, including our project's release notes and official website.
## Conclusion
We greatly value the work of security researchers and believe that responsible disclosure of vulnerabilities is a valuable contribution to the security of the Internet. We encourage users to contribute to the security of our project by reporting any security-related issues to us.
================================================
FILE: app.json
================================================
{
"name": "gun-server",
"website": "http://gun.eco/",
"repository": "https://github.com/amark/gun",
"logo": "https://avatars3.githubusercontent.com/u/8811914",
"keywords": ["node", "gun", "gunDB", "database","graph","offline-first"],
"description": "Javascript, Offline-First Javascript Graph Database Server Peer",
"env": {
"NPM_CONFIG_PRODUCTION": {
"description": "If you do not want default features, set to \"true\".",
"value": "false"
},
"PEERS": {
"description": "Comma-separated list of peer urls to connect to",
"required": false
}
}
}
================================================
FILE: as.js
================================================
;(function(){
function as(el, gun, cb, opt){
el = $(el);
if(gun === as.gui && as.el && as.el.is(el)){ return }
opt = opt || {};
opt.match = opt.match || '{{ ';
opt.end = opt.end || ' }}';
;(function(){ // experimental
function nest(t, s,e, r, i,tmp,u){
if(r && !r.length){ return t||'' }
if(!t){ return [] }
e = e || s;
i = t.indexOf(s, i||0);
if(0 > i){ return [] }
tmp = t.indexOf(e, i+1);
if(!r){ return [t.slice(i+s.length, tmp)].concat(nest(t, s,e, r, tmp,tmp,u)) }
return t.slice(0,i)+r[0]+nest(t.slice(tmp+e.length), s,e, r.slice(1), 0,tmp,u);
}
/* experimental */
function template(tag, attr){
var html = (tag = $(tag))[0].outerHTML, sub, tmp;
if(html && (0 > html.indexOf(opt.match))){ return }
if(!attr){
$.each(tag[0].attributes, function(i,v){
if(!v){ return }
if(!nest(v.value, opt.match, opt.end).length){ return }
template(tag, v.name)
});
if((sub = tag.children()).length){
return sub.each(function(){ template(this) });
}
}
var data = [], plate = attr? tag.attr(attr) : tag.html();
tmp = nest(plate, opt.match, opt.end);
if(!tmp.length){ return }
$.each(tmp, function(pos, match){
var expr = match.split(' ');
var path = (expr[0]).split('.');
if(expr = expr.slice(1).join(' ')){
expr = new Function("_", "b", "return (_)" + expr);
}
var val = (expr && expr('')) || '';
data.push(val);
if(!attr){ tag.text(val) }
var ref = gun, sup = [], tmp;
if(tmp = tag.attr('name')){ sup.push(tmp) }
tag.parents("[name]").each(function(){
sup.push($(this).attr('name'));
});
$.each(path = sup.reverse().concat(path), function(i,v){
ref = ref.get(v);
});
ref.on(function(v){
v = data[pos] = expr? expr(v) : v;
var tmp = nest(plate, opt.match, opt.end, data);
if(attr){
tag.attr(attr, tmp);
} else {
tag.text(tmp);
}
});
});
}
template(el);
}());
as.gui = gun;
as.el = el;
if(el.data('as')){
el.html(el.data('as').fresh);
} else {
el.data('as', {
fresh: el.html()
})
}
el.find("[name]").each(function(){
if($(this).find("[name]").length){ return }
var name = $(this),
parents = name.parents("[name]"),
path = [],
ref = gun;
path.push(name.attr('name'));
parents.each(function(){
path.push($(this).attr('name'));
});
path = path.reverse();
path.forEach(function(key){
if('#' === key){
ref = ref.map()
} else {
ref = ref.get(key);
}
});
var many = path.slice().reverse().indexOf('#'), model;
many = (0 < ++many)? many : false;
if(many){
model = name.closest("[name='#']");
model = model.data('model') || model.data('model', {$: model.clone(), on: model.parent(), has: {}}).hide().data('model');
}
ref.get(function(at){
var data = at.put, key = at.get, gui = at.gun || at.$, ui = name, back;
if(model){
ui = model.has[(gui._).id];
if(!ui){
back = gui.back(many - 1);
ui = model.has[(back._).id];
if(!ui){
if(!(back._).get){ return }
ui = (model.has[(back._).id] = model.$.clone(true).prependTo(model.on));
}
ui = ui.find("[name='"+key+"']").first();
model.has[(gui._).id] = ui;
}
}
ui.data('gun', gui);
if(ui.data('was') === data){ return }
if(many && ui.is('.sort')){
var up = ui.closest("[name='#']");
var tmp = as.sort(data, up.parent().children().last());
tmp? up.insertAfter(tmp) : up.prependTo(up.parent());
}
if(as.lock === gui){ return }
if(!(data && data instanceof Object)){
(ui[0] && u === ui[0].value)? ui.text(data) : ui.val(data);
}
ui.data('was', data);
if(cb){
cb(data, key, ui);
}
});
});
}
as.wait = function(cb, wait, to){
return function(a,b,c){
var me = as.typing = this;
clearTimeout(to);
to = setTimeout(function(){
cb.call(me, a,b,c);
as.typing = me = false;
}, wait || 200);
}
}
as.sort = function sort(num, li){ return parseFloat(num) >= parseFloat($(li).find('.sort').text() || -Infinity)? li : sort(num, li.prev()) }
$(document).on('keyup', 'input, textarea, [contenteditable]', as.wait(function(){
var el = $(this);
var data = (el[0] && u === el[0].value)? el.text() : el.val();
var g = el.data('gun');
if(!g){ return }
as.lock = g;
g.put(data);
}, 99));
//$(document).on('submit', 'form', function(e){ e.preventDefault() });
var u;
window.as = as;
$.as = as;
}());
;(function(){
$(document).on('click', 'a, button', function(e){
var tmp = $(this).attr('href') || '';
if(0 === tmp.indexOf('http')){ return }
e.preventDefault();
r(tmp);
});
function r(href){
if(!href){ return }
if(href[0] == '#'){ href = href.slice(1) }
var h = href.split('/')[0];
$('.page').hide();
$('#' + h).show();
if(r.on === h){ return }
location.hash = href;
(r.page[h] || {on:function(){}}).on();
r.on = h;
return r;
};
r.page = function(h, cb){
r.page[h] = r.page[h] || {on: cb};
return r;
}
r.render = function(id, model, onto, data){
var $data = $(
$('#' + id).get(0) ||
$('.model').find(model).clone(true).attr('id', id).appendTo(onto)
);
$.each(data, function(field, val){
if($.isPlainObject(val)){ return }
$data.find("[name='" + field + "']").val(val).text(val);
});
return $data;
}
window.onhashchange = function(){ r(location.hash.slice(1)) };
$.as && ($.as.route = r);
if(window.as){
as.route = r;
} else {
$.route = r;
}
}());
;$(function(){
$('.page').not(':first').hide();
$.as.route(location.hash.slice(1));
$(JOY.start = JOY.start || function(){ $.as(document, gun, null, JOY.opt) });
if($('body').attr('peers')){ (console.warn || console.log)('Warning: Please upgrade to https://github.com/eraeco/joydb#peers !') }
});
;(function(){ // need to isolate into separate module!
var joy = window.JOY = function(){};
joy.auth = function(a,b,cb,o){
if(!o){ o = cb ; cb = 0 }
if(o === true){
gun.user().create(a, b);
return;
}
gun.user().auth(a,b, cb,o);
}
var opt = joy.opt = window.CONFIG || {}, peers;
$('link[type=peer]').each(function(){ (peers || (peers = [])).push($(this).attr('href')) });
!window.gun && (opt.peers = opt.peers || peers || (function(){
(console.warn || console.log)('Warning: No peer provided, defaulting to DEMO peer. Do not run in production, or your data will be regularly wiped, reset, or deleted. For more info, check https://github.com/eraeco/joydb#peers !');
return ['https://gunjs.herokuapp.com/gun'];
}()));
window.gun = window.gun || Gun(opt);
gun.on('auth', function(ack){
console.log("Your namespace is publicly available at", ack.soul);
});
}());
================================================
FILE: axe.js
================================================
;(function(){
var sT = setTimeout || {}, u;
if(typeof window !== ''+u){ sT.window = window }
var AXE = (sT.window||'').AXE || function(){};
if(AXE.window = sT.window){ AXE.window.AXE = AXE }
var Gun = (AXE.window||'').GUN || require('./gun');
(Gun.AXE = AXE).GUN = AXE.Gun = Gun;
//if(!Gun.window){ try{ require('./lib/axe') }catch(e){} }
if(!Gun.window){ require('./lib/axe') }
Gun.on('opt', function(at){ start(at) ; this.to.next(at) }); // make sure to call the "next" middleware adapter.
function start(root){
if(root.axe){ return }
var opt = root.opt, peers = opt.peers;
if(false === opt.axe){ return }
if(!Gun.window){ return } // handled by ^ lib/axe.js
var w = Gun.window, lS = w.localStorage || opt.localStorage || {}, loc = w.location || opt.location || {}, nav = w.navigator || opt.navigator || {};
var axe = root.axe = {}, tmp, id;
var mesh = opt.mesh = opt.mesh || Gun.Mesh(root); // DAM!
tmp = peers[id = loc.origin + '/gun'] = peers[id] || {};
tmp.id = tmp.url = id; tmp.retry = tmp.retry || 0;
tmp = peers[id = 'http://localhost:8765/gun'] = peers[id] || {};
tmp.id = tmp.url = id; tmp.retry = tmp.retry || 0;
Gun.log.once("AXE", "AXE enabled: Trying to find network via (1) local peer (2) last used peers (3) a URL parameter, and last (4) hard coded peers.");
Gun.log.once("AXEWarn", "Warning: AXE is in alpha, use only for testing!");
var last = lS.peers || ''; if(last){ last += ' ' }
last += ((loc.search||'').split('peers=')[1]||'').split('&')[0];
root.on('bye', function(peer){
this.to.next(peer);
if(!peer.url){ return } // ignore WebRTC disconnects for now.
if(!nav.onLine){ peer.retry = 1 }
if(peer.retry){ return }
if(axe.fall){ delete axe.fall[peer.url || peer.id] }
(function next(){
if(!axe.fall){ setTimeout(next, 9); return } // not found yet
var fall = Object.keys(axe.fall||''), one = fall[(Math.random()*fall.length) >> 0];
if(!fall.length){ lS.peers = ''; one = 'https://gunjs.herokuapp.com/gun' } // out of peers
if(peers[one]){ next(); return } // already choose
mesh.hi(one);
}());
});
root.on('hi', function(peer){ // TEMPORARY! Try to connect all peers.
this.to.next(peer);
if(!peer.url){ return } // ignore WebRTC disconnects for now.
return; // DO NOT COMMIT THIS FEATURE YET! KEEP TESTING NETWORK PERFORMANCE FIRST!
(function next(){
if(!peer.wire){ return }
if(!axe.fall){ setTimeout(next, 9); return } // not found yet
var one = (next.fall = next.fall || Object.keys(axe.fall||'')).pop();
if(!one){ return }
setTimeout(next, 99);
mesh.say({dam: 'opt', opt: {peers: one}}, peer);
}());
});
function found(text){
axe.fall = {};
((text||'').match(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/ig)||[]).forEach(function(url){
axe.fall[url] = {url: url, id: url, retry: 0}; // RETRY
});
return;
// TODO: Finish porting below? Maybe not.
Object.keys(last.peers||'').forEach(function(key){
tmp = peers[id = key] = peers[id] || {};
tmp.id = tmp.url = id;
});
tmp = peers[id = 'https://guntest.herokuapp.com/gun'] = peers[id] || {};
tmp.id = tmp.url = id;
var mesh = opt.mesh = opt.mesh || Gun.Mesh(root); // DAM!
mesh.way = function(msg){
if(root.$ === msg.$ || (msg._||'').via){
mesh.say(msg, opt.peers);
return;
}
var at = (msg.$||'')._;
if(!at){ mesh.say(msg, opt.peers); return }
if(msg.get){
if(at.axe){ return } // don't ask for it again!
at.axe = {};
}
mesh.say(msg, opt.peers);
}
}
if(last){ found(last); return }
try{ fetch(((loc.search||'').split('axe=')[1]||'').split('&')[0] || loc.axe || 'https://raw.githubusercontent.com/wiki/amark/gun/volunteer.dht.md').then(function(res){
return res.text()
}).then(function(text){
found(lS.peers = text);
}).catch(function(){
found(); // nothing
})}catch(e){found()}
}
var empty = {}, yes = true;
try{ if(typeof module != ''+u){ module.exports = AXE } }catch(e){}
}());
================================================
FILE: bower.json
================================================
{
"name": "gun",
"main": "gun.js",
"version": "0.1.5",
"homepage": "http://gunDB.io",
"authors": [
{ "name": "Mark Nadal", "email": "mark@accelsor.com" },
{ "name": "Alex LaFroscia", "email": "alex@lafroscia.com" }
],
"repository": {
"type": "git",
"url": "https://github.com/amark/gun"
},
"description": "A distributed, embedded, graph database engine.",
"moduleType": [
"globals"
],
"keywords": [
"graph",
"database",
"gun",
"gundb",
"nodb"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}
================================================
FILE: browser.js
================================================
// if(!(typeof navigator == "undefined") && navigator.product == "ReactNative"){
// require("./lib/mobile.js");
// }
module.exports = require('./gun.js');
================================================
FILE: examples/.gitignore
================================================
node_modules/*
npm-debug.log
*data.json
================================================
FILE: examples/Main.js
================================================
import { render } from './iris/js/lib/preact.js';
import { Router, route } from './iris/js/lib/preact-router.es.js';
import { createHashHistory } from './iris/js/lib/history.production.min.js';
import { Component } from './iris/js/lib/preact.js';
import { Link } from './iris/js/lib/preact.match.js';
import Helpers from './iris/js/Helpers.js';
import { html } from './iris/js/Helpers.js';
import QRScanner from './iris/js/QRScanner.js';
import PeerManager from './iris/js/PeerManager.js';
import Session from './iris/js/Session.js';
import { translate as t } from './iris/js/Translation.js';
import Settings from './iris/js/views/Settings.js';
import LogoutConfirmation from './iris/js/views/LogoutConfirmation.js';
import Chat from './iris/js/views/Chat.js';
import Store from './iris/js/views/Store.js';
import Checkout from './iris/js/views/Checkout.js';
import Product from './iris/js/views/Product.js';
import Login from './iris/js/views/Login.js';
import Profile from './iris/js/views/Profile.js';
import Group from './iris/js/views/Group.js';
import Message from './iris/js/views/Message.js';
import Follows from './iris/js/views/Follows.js';
import Feed from './iris/js/views/Feed.js';
import About from './iris/js/views/About.js';
import Explorer from './iris/js/views/Explorer.js';
import Contacts from './iris/js/views/Contacts.js';
import Torrent from './iris/js/views/Torrent.js';
import VideoCall from './iris/js/components/VideoCall.js';
import Identicon from './iris/js/components/Identicon.js';
import MediaPlayer from './iris/js/components/MediaPlayer.js';
import Footer from './iris/js/components/Footer.js';
import State from './iris/js/State.js';
import Icons from './iris/js/Icons.js';
const userAgent = navigator.userAgent.toLowerCase();
const isElectron = (userAgent.indexOf(' electron/') > -1);
if (!isElectron && ('serviceWorker' in navigator)) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('iris/serviceworker.js')
.catch(function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}
State.init();
Session.init({autologin: true});
PeerManager.init();
Helpers.checkColorScheme();
const APPLICATIONS = [ // TODO: move editable shortcuts to State.local gun
{url: '/', text: t('home'), icon: Icons.home},
{url: '/feed', text: t('feed'), icon: Icons.feed},
{url: '/media', text: t('media'), icon: Icons.play},
{url: '/settings', text: t('settings'), icon: Icons.settings},
{url: '/store', text: t('store'), icon: Icons.store},
{url: '/explorer', text: t('explorer'), icon: Icons.folder},
{url: '/chat', text: t('messages'), icon: Icons.chat},
// {url: '/store', text: t('store'), icon: Icons.store}, // restore when it works!
{},
{url: '../stats.html', text: 'Gun node stats'},
{url: '../iris/index.html', text: 'Iris', icon: html``},
{url: '../infinite-scroll/index.html', text: 'Infinite scroll'},
{url: '../chat/index.html', text: 'Chat'},
{url: '../game/space.html', text: 'Space'},
{},
{url: 'https://gun.eco/docs/', text: 'Gun documentation'},
{url: 'https://examples.iris.to/components/', text: 'Iris web components'}
];
const HomeView = () => {
return html`
Hello, world!
Here you can find sample applications and utilities for GUN.
If you need any help, please feel free to join the GUN community chat: http://chat.gun.eco
================================================
FILE: examples/express.js
================================================
console.log("If module not found, install express globally `npm i express -g`!");
var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765;
var express = require('express');
var Gun = require('..');
require('../axe');
var app = express();
app.use(Gun.serve);
app.use(express.static(__dirname));
var server = app.listen(port);
var gun = Gun({ file: 'data', web: server });
global.Gun = Gun; /// make global to `node --inspect` - debug only
global.gun = gun; /// make global to `node --inspect` - debug only
console.log('Server started on port ' + port + ' with /gun');
================================================
FILE: examples/game/furball.html
================================================
Furball
Neon ERA presents
Furball Forces
Choose Team:
Episode 1: Waking
"How long until they're online?"
"We're copying the soul files, almost done."
"Monsters are on the bridge, we do not have time!"
"The new body is printing now, it'll be able to outrun them all, just hold on."
"It won't know where to run! We're risking ruining the whole resistance, I need to talk to it now."
"95% done." The voice behind the glass turns to the soul in the body, "My cub, can you hear me?"
...
SCORE: 0%
LIFE: 50%
A fire explodes in the room behind the glass as an AutoMecha blows the door open.
The floor shakes and the bed crashes through the wall, flying out of the building.
"Mom!!!"
There is a total free fall from 10 levels up, water down below.
...
The water splashes, swelling and swirling all around.
...
Rapidly tap to swim up to air:
Episode 2: Who Am I?
"Grab on!" A voice calls out from the darkness.
A life vest hits the water and floats within arm's distance.
The shivering body is pulled up onto the boat.
"Wow, you're heavier than you look. Are you OK? What's your name?"
...
Write your reply & hit enter:
"Well, it's a miracle you did not die in the building explosion or from that fall."
"What is going on? What happened?"
"You can't remember? Your brain must be knocked up pretty hard."
"No, I was mid copy into this body and now my memories are glitching."
"Woah, you're one of those pro elite AREION revolutionaries? All flesh & blood! Dense, too. I would've assumed they were stealing AutoMecha tech for that instead."
"I was about to be told vital data for the resistance, but then they blew up the build--"
...
"Hey, what's the matter?"
"My mom. She was in there. I need to go back. Please, help me and tell me everything you know."
"I'm so sorry. I can only get so close with the boat, you're gonna have to jump over a lot of broken bits. You ready?"