@enbox/gitd 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +177 -0
- package/README.md +134 -0
- package/dist/esm/ci.js +76 -0
- package/dist/esm/ci.js.map +1 -0
- package/dist/esm/cli/agent.js +86 -0
- package/dist/esm/cli/agent.js.map +1 -0
- package/dist/esm/cli/commands/ci.js +278 -0
- package/dist/esm/cli/commands/ci.js.map +1 -0
- package/dist/esm/cli/commands/clone.js +77 -0
- package/dist/esm/cli/commands/clone.js.map +1 -0
- package/dist/esm/cli/commands/daemon.js +132 -0
- package/dist/esm/cli/commands/daemon.js.map +1 -0
- package/dist/esm/cli/commands/github-api.js +36 -0
- package/dist/esm/cli/commands/github-api.js.map +1 -0
- package/dist/esm/cli/commands/init.js +69 -0
- package/dist/esm/cli/commands/init.js.map +1 -0
- package/dist/esm/cli/commands/issue.js +293 -0
- package/dist/esm/cli/commands/issue.js.map +1 -0
- package/dist/esm/cli/commands/log.js +90 -0
- package/dist/esm/cli/commands/log.js.map +1 -0
- package/dist/esm/cli/commands/migrate.js +444 -0
- package/dist/esm/cli/commands/migrate.js.map +1 -0
- package/dist/esm/cli/commands/notification.js +141 -0
- package/dist/esm/cli/commands/notification.js.map +1 -0
- package/dist/esm/cli/commands/org.js +353 -0
- package/dist/esm/cli/commands/org.js.map +1 -0
- package/dist/esm/cli/commands/patch.js +375 -0
- package/dist/esm/cli/commands/patch.js.map +1 -0
- package/dist/esm/cli/commands/registry.js +501 -0
- package/dist/esm/cli/commands/registry.js.map +1 -0
- package/dist/esm/cli/commands/release.js +197 -0
- package/dist/esm/cli/commands/release.js.map +1 -0
- package/dist/esm/cli/commands/repo.js +148 -0
- package/dist/esm/cli/commands/repo.js.map +1 -0
- package/dist/esm/cli/commands/serve.js +148 -0
- package/dist/esm/cli/commands/serve.js.map +1 -0
- package/dist/esm/cli/commands/setup.js +92 -0
- package/dist/esm/cli/commands/setup.js.map +1 -0
- package/dist/esm/cli/commands/shim.js +75 -0
- package/dist/esm/cli/commands/shim.js.map +1 -0
- package/dist/esm/cli/commands/social.js +206 -0
- package/dist/esm/cli/commands/social.js.map +1 -0
- package/dist/esm/cli/commands/web.js +36 -0
- package/dist/esm/cli/commands/web.js.map +1 -0
- package/dist/esm/cli/commands/wiki.js +185 -0
- package/dist/esm/cli/commands/wiki.js.map +1 -0
- package/dist/esm/cli/flags.js +29 -0
- package/dist/esm/cli/flags.js.map +1 -0
- package/dist/esm/cli/main.js +331 -0
- package/dist/esm/cli/main.js.map +1 -0
- package/dist/esm/cli/repo-context.js +53 -0
- package/dist/esm/cli/repo-context.js.map +1 -0
- package/dist/esm/daemon/adapter.js +18 -0
- package/dist/esm/daemon/adapter.js.map +1 -0
- package/dist/esm/daemon/adapters/github.js +112 -0
- package/dist/esm/daemon/adapters/github.js.map +1 -0
- package/dist/esm/daemon/adapters/go.js +51 -0
- package/dist/esm/daemon/adapters/go.js.map +1 -0
- package/dist/esm/daemon/adapters/index.js +32 -0
- package/dist/esm/daemon/adapters/index.js.map +1 -0
- package/dist/esm/daemon/adapters/npm.js +51 -0
- package/dist/esm/daemon/adapters/npm.js.map +1 -0
- package/dist/esm/daemon/adapters/oci.js +62 -0
- package/dist/esm/daemon/adapters/oci.js.map +1 -0
- package/dist/esm/daemon/index.js +12 -0
- package/dist/esm/daemon/index.js.map +1 -0
- package/dist/esm/daemon/server.js +167 -0
- package/dist/esm/daemon/server.js.map +1 -0
- package/dist/esm/git-remote/credential-helper.js +106 -0
- package/dist/esm/git-remote/credential-helper.js.map +1 -0
- package/dist/esm/git-remote/credential-main.js +109 -0
- package/dist/esm/git-remote/credential-main.js.map +1 -0
- package/dist/esm/git-remote/index.js +10 -0
- package/dist/esm/git-remote/index.js.map +1 -0
- package/dist/esm/git-remote/main.js +78 -0
- package/dist/esm/git-remote/main.js.map +1 -0
- package/dist/esm/git-remote/parse-url.js +60 -0
- package/dist/esm/git-remote/parse-url.js.map +1 -0
- package/dist/esm/git-remote/resolve.js +175 -0
- package/dist/esm/git-remote/resolve.js.map +1 -0
- package/dist/esm/git-remote/service.js +82 -0
- package/dist/esm/git-remote/service.js.map +1 -0
- package/dist/esm/git-server/auth.js +211 -0
- package/dist/esm/git-server/auth.js.map +1 -0
- package/dist/esm/git-server/bundle-restore.js +180 -0
- package/dist/esm/git-server/bundle-restore.js.map +1 -0
- package/dist/esm/git-server/bundle-sync.js +233 -0
- package/dist/esm/git-server/bundle-sync.js.map +1 -0
- package/dist/esm/git-server/did-service.js +73 -0
- package/dist/esm/git-server/did-service.js.map +1 -0
- package/dist/esm/git-server/git-backend.js +186 -0
- package/dist/esm/git-server/git-backend.js.map +1 -0
- package/dist/esm/git-server/http-handler.js +295 -0
- package/dist/esm/git-server/http-handler.js.map +1 -0
- package/dist/esm/git-server/index.js +16 -0
- package/dist/esm/git-server/index.js.map +1 -0
- package/dist/esm/git-server/push-authorizer.js +62 -0
- package/dist/esm/git-server/push-authorizer.js.map +1 -0
- package/dist/esm/git-server/ref-sync.js +132 -0
- package/dist/esm/git-server/ref-sync.js.map +1 -0
- package/dist/esm/git-server/server.js +185 -0
- package/dist/esm/git-server/server.js.map +1 -0
- package/dist/esm/git-server/verify.js +109 -0
- package/dist/esm/git-server/verify.js.map +1 -0
- package/dist/esm/github-shim/helpers.js +273 -0
- package/dist/esm/github-shim/helpers.js.map +1 -0
- package/dist/esm/github-shim/index.js +13 -0
- package/dist/esm/github-shim/index.js.map +1 -0
- package/dist/esm/github-shim/issues.js +318 -0
- package/dist/esm/github-shim/issues.js.map +1 -0
- package/dist/esm/github-shim/pulls.js +423 -0
- package/dist/esm/github-shim/pulls.js.map +1 -0
- package/dist/esm/github-shim/releases.js +154 -0
- package/dist/esm/github-shim/releases.js.map +1 -0
- package/dist/esm/github-shim/repos.js +86 -0
- package/dist/esm/github-shim/repos.js.map +1 -0
- package/dist/esm/github-shim/server.js +351 -0
- package/dist/esm/github-shim/server.js.map +1 -0
- package/dist/esm/github-shim/users.js +61 -0
- package/dist/esm/github-shim/users.js.map +1 -0
- package/dist/esm/index.js +26 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/indexer/api.js +132 -0
- package/dist/esm/indexer/api.js.map +1 -0
- package/dist/esm/indexer/crawler.js +256 -0
- package/dist/esm/indexer/crawler.js.map +1 -0
- package/dist/esm/indexer/index.js +9 -0
- package/dist/esm/indexer/index.js.map +1 -0
- package/dist/esm/indexer/main.js +76 -0
- package/dist/esm/indexer/main.js.map +1 -0
- package/dist/esm/indexer/store.js +334 -0
- package/dist/esm/indexer/store.js.map +1 -0
- package/dist/esm/issues.js +133 -0
- package/dist/esm/issues.js.map +1 -0
- package/dist/esm/notifications.js +47 -0
- package/dist/esm/notifications.js.map +1 -0
- package/dist/esm/org.js +90 -0
- package/dist/esm/org.js.map +1 -0
- package/dist/esm/patches.js +136 -0
- package/dist/esm/patches.js.map +1 -0
- package/dist/esm/refs.js +54 -0
- package/dist/esm/refs.js.map +1 -0
- package/dist/esm/registry.js +81 -0
- package/dist/esm/registry.js.map +1 -0
- package/dist/esm/releases.js +78 -0
- package/dist/esm/releases.js.map +1 -0
- package/dist/esm/repo.js +150 -0
- package/dist/esm/repo.js.map +1 -0
- package/dist/esm/resolver/index.js +10 -0
- package/dist/esm/resolver/index.js.map +1 -0
- package/dist/esm/resolver/resolve.js +189 -0
- package/dist/esm/resolver/resolve.js.map +1 -0
- package/dist/esm/resolver/trust-chain.js +155 -0
- package/dist/esm/resolver/trust-chain.js.map +1 -0
- package/dist/esm/resolver/verify.js +186 -0
- package/dist/esm/resolver/verify.js.map +1 -0
- package/dist/esm/shims/go/index.js +9 -0
- package/dist/esm/shims/go/index.js.map +1 -0
- package/dist/esm/shims/go/proxy.js +275 -0
- package/dist/esm/shims/go/proxy.js.map +1 -0
- package/dist/esm/shims/go/server.js +70 -0
- package/dist/esm/shims/go/server.js.map +1 -0
- package/dist/esm/shims/index.js +15 -0
- package/dist/esm/shims/index.js.map +1 -0
- package/dist/esm/shims/npm/index.js +9 -0
- package/dist/esm/shims/npm/index.js.map +1 -0
- package/dist/esm/shims/npm/registry.js +234 -0
- package/dist/esm/shims/npm/registry.js.map +1 -0
- package/dist/esm/shims/npm/server.js +72 -0
- package/dist/esm/shims/npm/server.js.map +1 -0
- package/dist/esm/shims/oci/index.js +9 -0
- package/dist/esm/shims/oci/index.js.map +1 -0
- package/dist/esm/shims/oci/registry.js +276 -0
- package/dist/esm/shims/oci/registry.js.map +1 -0
- package/dist/esm/shims/oci/server.js +82 -0
- package/dist/esm/shims/oci/server.js.map +1 -0
- package/dist/esm/social.js +70 -0
- package/dist/esm/social.js.map +1 -0
- package/dist/esm/web/html.js +123 -0
- package/dist/esm/web/html.js.map +1 -0
- package/dist/esm/web/index.js +7 -0
- package/dist/esm/web/index.js.map +1 -0
- package/dist/esm/web/routes.js +420 -0
- package/dist/esm/web/routes.js.map +1 -0
- package/dist/esm/web/server.js +225 -0
- package/dist/esm/web/server.js.map +1 -0
- package/dist/esm/wiki.js +63 -0
- package/dist/esm/wiki.js.map +1 -0
- package/dist/types/ci.d.ts +203 -0
- package/dist/types/ci.d.ts.map +1 -0
- package/dist/types/cli/agent.d.ts +59 -0
- package/dist/types/cli/agent.d.ts.map +1 -0
- package/dist/types/cli/commands/ci.d.ts +16 -0
- package/dist/types/cli/commands/ci.d.ts.map +1 -0
- package/dist/types/cli/commands/clone.d.ts +13 -0
- package/dist/types/cli/commands/clone.d.ts.map +1 -0
- package/dist/types/cli/commands/daemon.d.ts +29 -0
- package/dist/types/cli/commands/daemon.d.ts.map +1 -0
- package/dist/types/cli/commands/github-api.d.ts +14 -0
- package/dist/types/cli/commands/github-api.d.ts.map +1 -0
- package/dist/types/cli/commands/init.d.ts +11 -0
- package/dist/types/cli/commands/init.d.ts.map +1 -0
- package/dist/types/cli/commands/issue.d.ts +16 -0
- package/dist/types/cli/commands/issue.d.ts.map +1 -0
- package/dist/types/cli/commands/log.d.ts +13 -0
- package/dist/types/cli/commands/log.d.ts.map +1 -0
- package/dist/types/cli/commands/migrate.d.ts +19 -0
- package/dist/types/cli/commands/migrate.d.ts.map +1 -0
- package/dist/types/cli/commands/notification.d.ts +16 -0
- package/dist/types/cli/commands/notification.d.ts.map +1 -0
- package/dist/types/cli/commands/org.d.ts +19 -0
- package/dist/types/cli/commands/org.d.ts.map +1 -0
- package/dist/types/cli/commands/patch.d.ts +17 -0
- package/dist/types/cli/commands/patch.d.ts.map +1 -0
- package/dist/types/cli/commands/registry.d.ts +25 -0
- package/dist/types/cli/commands/registry.d.ts.map +1 -0
- package/dist/types/cli/commands/release.d.ts +13 -0
- package/dist/types/cli/commands/release.d.ts.map +1 -0
- package/dist/types/cli/commands/repo.d.ts +15 -0
- package/dist/types/cli/commands/repo.d.ts.map +1 -0
- package/dist/types/cli/commands/serve.d.ts +22 -0
- package/dist/types/cli/commands/serve.d.ts.map +1 -0
- package/dist/types/cli/commands/setup.d.ts +16 -0
- package/dist/types/cli/commands/setup.d.ts.map +1 -0
- package/dist/types/cli/commands/shim.d.ts +16 -0
- package/dist/types/cli/commands/shim.d.ts.map +1 -0
- package/dist/types/cli/commands/social.d.ts +19 -0
- package/dist/types/cli/commands/social.d.ts.map +1 -0
- package/dist/types/cli/commands/web.d.ts +14 -0
- package/dist/types/cli/commands/web.d.ts.map +1 -0
- package/dist/types/cli/commands/wiki.d.ts +14 -0
- package/dist/types/cli/commands/wiki.d.ts.map +1 -0
- package/dist/types/cli/flags.d.ts +16 -0
- package/dist/types/cli/flags.d.ts.map +1 -0
- package/dist/types/cli/main.d.ts +69 -0
- package/dist/types/cli/main.d.ts.map +1 -0
- package/dist/types/cli/repo-context.d.ts +30 -0
- package/dist/types/cli/repo-context.d.ts.map +1 -0
- package/dist/types/daemon/adapter.d.ts +74 -0
- package/dist/types/daemon/adapter.d.ts.map +1 -0
- package/dist/types/daemon/adapters/github.d.ts +10 -0
- package/dist/types/daemon/adapters/github.d.ts.map +1 -0
- package/dist/types/daemon/adapters/go.d.ts +10 -0
- package/dist/types/daemon/adapters/go.d.ts.map +1 -0
- package/dist/types/daemon/adapters/index.d.ts +22 -0
- package/dist/types/daemon/adapters/index.d.ts.map +1 -0
- package/dist/types/daemon/adapters/npm.d.ts +10 -0
- package/dist/types/daemon/adapters/npm.d.ts.map +1 -0
- package/dist/types/daemon/adapters/oci.d.ts +10 -0
- package/dist/types/daemon/adapters/oci.d.ts.map +1 -0
- package/dist/types/daemon/index.d.ts +14 -0
- package/dist/types/daemon/index.d.ts.map +1 -0
- package/dist/types/daemon/server.d.ts +55 -0
- package/dist/types/daemon/server.d.ts.map +1 -0
- package/dist/types/git-remote/credential-helper.d.ts +49 -0
- package/dist/types/git-remote/credential-helper.d.ts.map +1 -0
- package/dist/types/git-remote/credential-main.d.ts +24 -0
- package/dist/types/git-remote/credential-main.d.ts.map +1 -0
- package/dist/types/git-remote/index.d.ts +10 -0
- package/dist/types/git-remote/index.d.ts.map +1 -0
- package/dist/types/git-remote/main.d.ts +23 -0
- package/dist/types/git-remote/main.d.ts.map +1 -0
- package/dist/types/git-remote/parse-url.d.ts +32 -0
- package/dist/types/git-remote/parse-url.d.ts.map +1 -0
- package/dist/types/git-remote/resolve.d.ts +30 -0
- package/dist/types/git-remote/resolve.d.ts.map +1 -0
- package/dist/types/git-remote/service.d.ts +75 -0
- package/dist/types/git-remote/service.d.ts.map +1 -0
- package/dist/types/git-server/auth.d.ts +129 -0
- package/dist/types/git-server/auth.d.ts.map +1 -0
- package/dist/types/git-server/bundle-restore.d.ts +48 -0
- package/dist/types/git-server/bundle-restore.d.ts.map +1 -0
- package/dist/types/git-server/bundle-sync.d.ts +90 -0
- package/dist/types/git-server/bundle-sync.d.ts.map +1 -0
- package/dist/types/git-server/did-service.d.ts +26 -0
- package/dist/types/git-server/did-service.d.ts.map +1 -0
- package/dist/types/git-server/git-backend.d.ts +84 -0
- package/dist/types/git-server/git-backend.d.ts.map +1 -0
- package/dist/types/git-server/http-handler.d.ts +73 -0
- package/dist/types/git-server/http-handler.d.ts.map +1 -0
- package/dist/types/git-server/index.d.ts +16 -0
- package/dist/types/git-server/index.d.ts.map +1 -0
- package/dist/types/git-server/push-authorizer.d.ts +38 -0
- package/dist/types/git-server/push-authorizer.d.ts.map +1 -0
- package/dist/types/git-server/ref-sync.d.ts +52 -0
- package/dist/types/git-server/ref-sync.d.ts.map +1 -0
- package/dist/types/git-server/server.d.ts +70 -0
- package/dist/types/git-server/server.d.ts.map +1 -0
- package/dist/types/git-server/verify.d.ts +12 -0
- package/dist/types/git-server/verify.d.ts.map +1 -0
- package/dist/types/github-shim/helpers.d.ts +108 -0
- package/dist/types/github-shim/helpers.d.ts.map +1 -0
- package/dist/types/github-shim/index.d.ts +15 -0
- package/dist/types/github-shim/index.d.ts.map +1 -0
- package/dist/types/github-shim/issues.d.ts +24 -0
- package/dist/types/github-shim/issues.d.ts.map +1 -0
- package/dist/types/github-shim/pulls.d.ts +31 -0
- package/dist/types/github-shim/pulls.d.ts.map +1 -0
- package/dist/types/github-shim/releases.d.ts +18 -0
- package/dist/types/github-shim/releases.d.ts.map +1 -0
- package/dist/types/github-shim/repos.d.ts +21 -0
- package/dist/types/github-shim/repos.d.ts.map +1 -0
- package/dist/types/github-shim/server.d.ts +53 -0
- package/dist/types/github-shim/server.d.ts.map +1 -0
- package/dist/types/github-shim/users.d.ts +17 -0
- package/dist/types/github-shim/users.d.ts.map +1 -0
- package/dist/types/index.d.ts +26 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/indexer/api.d.ts +32 -0
- package/dist/types/indexer/api.d.ts.map +1 -0
- package/dist/types/indexer/crawler.d.ts +72 -0
- package/dist/types/indexer/crawler.d.ts.map +1 -0
- package/dist/types/indexer/index.d.ts +12 -0
- package/dist/types/indexer/index.d.ts.map +1 -0
- package/dist/types/indexer/main.d.ts +21 -0
- package/dist/types/indexer/main.d.ts.map +1 -0
- package/dist/types/indexer/store.d.ts +168 -0
- package/dist/types/indexer/store.d.ts.map +1 -0
- package/dist/types/issues.d.ts +395 -0
- package/dist/types/issues.d.ts.map +1 -0
- package/dist/types/notifications.d.ts +93 -0
- package/dist/types/notifications.d.ts.map +1 -0
- package/dist/types/org.d.ts +232 -0
- package/dist/types/org.d.ts.map +1 -0
- package/dist/types/patches.d.ts +410 -0
- package/dist/types/patches.d.ts.map +1 -0
- package/dist/types/refs.d.ts +114 -0
- package/dist/types/refs.d.ts.map +1 -0
- package/dist/types/registry.d.ts +212 -0
- package/dist/types/registry.d.ts.map +1 -0
- package/dist/types/releases.d.ts +204 -0
- package/dist/types/releases.d.ts.map +1 -0
- package/dist/types/repo.d.ts +450 -0
- package/dist/types/repo.d.ts.map +1 -0
- package/dist/types/resolver/index.d.ts +13 -0
- package/dist/types/resolver/index.d.ts.map +1 -0
- package/dist/types/resolver/resolve.d.ts +80 -0
- package/dist/types/resolver/resolve.d.ts.map +1 -0
- package/dist/types/resolver/trust-chain.d.ts +54 -0
- package/dist/types/resolver/trust-chain.d.ts.map +1 -0
- package/dist/types/resolver/verify.d.ts +62 -0
- package/dist/types/resolver/verify.d.ts.map +1 -0
- package/dist/types/shims/go/index.d.ts +11 -0
- package/dist/types/shims/go/index.d.ts.map +1 -0
- package/dist/types/shims/go/proxy.d.ts +51 -0
- package/dist/types/shims/go/proxy.d.ts.map +1 -0
- package/dist/types/shims/go/server.d.ts +23 -0
- package/dist/types/shims/go/server.d.ts.map +1 -0
- package/dist/types/shims/index.d.ts +18 -0
- package/dist/types/shims/index.d.ts.map +1 -0
- package/dist/types/shims/npm/index.d.ts +11 -0
- package/dist/types/shims/npm/index.d.ts.map +1 -0
- package/dist/types/shims/npm/registry.d.ts +46 -0
- package/dist/types/shims/npm/registry.d.ts.map +1 -0
- package/dist/types/shims/npm/server.d.ts +23 -0
- package/dist/types/shims/npm/server.d.ts.map +1 -0
- package/dist/types/shims/oci/index.d.ts +11 -0
- package/dist/types/shims/oci/index.d.ts.map +1 -0
- package/dist/types/shims/oci/registry.d.ts +56 -0
- package/dist/types/shims/oci/registry.d.ts.map +1 -0
- package/dist/types/shims/oci/server.d.ts +23 -0
- package/dist/types/shims/oci/server.d.ts.map +1 -0
- package/dist/types/social.d.ts +162 -0
- package/dist/types/social.d.ts.map +1 -0
- package/dist/types/web/html.d.ts +23 -0
- package/dist/types/web/html.d.ts.map +1 -0
- package/dist/types/web/index.d.ts +8 -0
- package/dist/types/web/index.d.ts.map +1 -0
- package/dist/types/web/routes.d.ts +21 -0
- package/dist/types/web/routes.d.ts.map +1 -0
- package/dist/types/web/server.d.ts +38 -0
- package/dist/types/web/server.d.ts.map +1 -0
- package/dist/types/wiki.d.ts +143 -0
- package/dist/types/wiki.d.ts.map +1 -0
- package/package.json +108 -0
- package/schemas/ci/check-run.json +23 -0
- package/schemas/ci/check-suite.json +23 -0
- package/schemas/issues/assignment.json +17 -0
- package/schemas/issues/comment.json +14 -0
- package/schemas/issues/issue.json +20 -0
- package/schemas/issues/label.json +17 -0
- package/schemas/issues/reaction.json +14 -0
- package/schemas/issues/status-change.json +14 -0
- package/schemas/notifications/notification.json +20 -0
- package/schemas/org/org-member.json +17 -0
- package/schemas/org/org.json +26 -0
- package/schemas/org/team-member.json +17 -0
- package/schemas/org/team.json +17 -0
- package/schemas/patches/merge-result.json +14 -0
- package/schemas/patches/patch-status-change.json +14 -0
- package/schemas/patches/patch.json +20 -0
- package/schemas/patches/review-comment.json +17 -0
- package/schemas/patches/review.json +14 -0
- package/schemas/patches/revision.json +30 -0
- package/schemas/refs/git-ref.json +32 -0
- package/schemas/registry/attestation.json +23 -0
- package/schemas/registry/package-version.json +23 -0
- package/schemas/registry/package.json +32 -0
- package/schemas/releases/release.json +17 -0
- package/schemas/repo/collaborator.json +17 -0
- package/schemas/repo/repo.json +35 -0
- package/schemas/repo/settings.json +39 -0
- package/schemas/repo/topic.json +14 -0
- package/schemas/repo/webhook.json +26 -0
- package/schemas/social/activity.json +23 -0
- package/schemas/social/follow.json +17 -0
- package/schemas/social/star.json +20 -0
- package/schemas/wiki/wiki-history.json +20 -0
- package/schemas/wiki/wiki-page.json +17 -0
- package/src/ci.ts +118 -0
- package/src/cli/agent.ts +117 -0
- package/src/cli/commands/ci.ts +300 -0
- package/src/cli/commands/clone.ts +78 -0
- package/src/cli/commands/daemon.ts +129 -0
- package/src/cli/commands/github-api.ts +30 -0
- package/src/cli/commands/init.ts +69 -0
- package/src/cli/commands/issue.ts +321 -0
- package/src/cli/commands/log.ts +106 -0
- package/src/cli/commands/migrate.ts +525 -0
- package/src/cli/commands/notification.ts +148 -0
- package/src/cli/commands/org.ts +381 -0
- package/src/cli/commands/patch.ts +413 -0
- package/src/cli/commands/registry.ts +542 -0
- package/src/cli/commands/release.ts +189 -0
- package/src/cli/commands/repo.ts +160 -0
- package/src/cli/commands/serve.ts +153 -0
- package/src/cli/commands/setup.ts +97 -0
- package/src/cli/commands/shim.ts +79 -0
- package/src/cli/commands/social.ts +221 -0
- package/src/cli/commands/web.ts +30 -0
- package/src/cli/commands/wiki.ts +199 -0
- package/src/cli/flags.ts +28 -0
- package/src/cli/main.ts +350 -0
- package/src/cli/repo-context.ts +55 -0
- package/src/daemon/adapter.ts +95 -0
- package/src/daemon/adapters/github.ts +86 -0
- package/src/daemon/adapters/go.ts +47 -0
- package/src/daemon/adapters/index.ts +36 -0
- package/src/daemon/adapters/npm.ts +47 -0
- package/src/daemon/adapters/oci.ts +59 -0
- package/src/daemon/index.ts +16 -0
- package/src/daemon/server.ts +204 -0
- package/src/git-remote/credential-helper.ts +114 -0
- package/src/git-remote/credential-main.ts +118 -0
- package/src/git-remote/index.ts +10 -0
- package/src/git-remote/main.ts +74 -0
- package/src/git-remote/parse-url.ts +81 -0
- package/src/git-remote/resolve.ts +207 -0
- package/src/git-remote/service.ts +126 -0
- package/src/git-server/auth.ts +308 -0
- package/src/git-server/bundle-restore.ts +217 -0
- package/src/git-server/bundle-sync.ts +300 -0
- package/src/git-server/did-service.ts +77 -0
- package/src/git-server/git-backend.ts +222 -0
- package/src/git-server/http-handler.ts +386 -0
- package/src/git-server/index.ts +16 -0
- package/src/git-server/push-authorizer.ts +77 -0
- package/src/git-server/ref-sync.ts +166 -0
- package/src/git-server/server.ts +236 -0
- package/src/git-server/verify.ts +116 -0
- package/src/github-shim/helpers.ts +311 -0
- package/src/github-shim/index.ts +35 -0
- package/src/github-shim/issues.ts +389 -0
- package/src/github-shim/pulls.ts +500 -0
- package/src/github-shim/releases.ts +185 -0
- package/src/github-shim/repos.ts +95 -0
- package/src/github-shim/server.ts +334 -0
- package/src/github-shim/users.ts +63 -0
- package/src/index.ts +26 -0
- package/src/indexer/api.ts +162 -0
- package/src/indexer/crawler.ts +290 -0
- package/src/indexer/index.ts +22 -0
- package/src/indexer/main.ts +83 -0
- package/src/indexer/store.ts +408 -0
- package/src/issues.ts +200 -0
- package/src/notifications.ts +80 -0
- package/src/org.ts +147 -0
- package/src/patches.ts +203 -0
- package/src/refs.ts +94 -0
- package/src/registry.ts +132 -0
- package/src/releases.ts +124 -0
- package/src/repo.ts +234 -0
- package/src/resolver/index.ts +42 -0
- package/src/resolver/resolve.ts +244 -0
- package/src/resolver/trust-chain.ts +217 -0
- package/src/resolver/verify.ts +237 -0
- package/src/shims/go/index.ts +14 -0
- package/src/shims/go/proxy.ts +336 -0
- package/src/shims/go/server.ts +82 -0
- package/src/shims/index.ts +20 -0
- package/src/shims/npm/index.ts +14 -0
- package/src/shims/npm/registry.ts +288 -0
- package/src/shims/npm/server.ts +84 -0
- package/src/shims/oci/index.ts +14 -0
- package/src/shims/oci/registry.ts +334 -0
- package/src/shims/oci/server.ts +94 -0
- package/src/social.ts +116 -0
- package/src/web/html.ts +120 -0
- package/src/web/index.ts +8 -0
- package/src/web/routes.ts +449 -0
- package/src/web/server.ts +256 -0
- package/src/wiki.ts +102 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git bundle → DWN sync — creates/updates a git bundle as a DWN record.
|
|
3
|
+
*
|
|
4
|
+
* After a successful `git push`, this module generates a `git bundle` from
|
|
5
|
+
* the bare repository and writes it as a ForgeRepo `bundle` record.
|
|
6
|
+
* Incremental bundles are created when a previous bundle exists; periodic
|
|
7
|
+
* squash writes compact all incrementals into a single full bundle.
|
|
8
|
+
*
|
|
9
|
+
* Bundle sync flow:
|
|
10
|
+
* 1. Query existing bundle records for the repo (sorted by timestamp desc)
|
|
11
|
+
* 2. If no bundles exist → create full bundle (`git bundle create --all`)
|
|
12
|
+
* 3. If bundles exist → create incremental bundle since last tip commit
|
|
13
|
+
* 4. Every N pushes (configurable), create a squash bundle (full bundle
|
|
14
|
+
* with `squash: true`) which purges all older bundle records
|
|
15
|
+
*
|
|
16
|
+
* The bundle data (binary `application/x-git-bundle`) is stored as the
|
|
17
|
+
* record payload. Queryable metadata is stored in tags.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { ForgeRepoProtocol } from '../repo.js';
|
|
23
|
+
import type { ForgeRepoSchemaMap } from '../repo.js';
|
|
24
|
+
import type { OnPushComplete } from './ref-sync.js';
|
|
25
|
+
import type { TypedWeb5 } from '@enbox/api';
|
|
26
|
+
|
|
27
|
+
import { DateSort } from '@enbox/dwn-sdk-js';
|
|
28
|
+
import { join } from 'node:path';
|
|
29
|
+
import { spawn } from 'node:child_process';
|
|
30
|
+
import { tmpdir } from 'node:os';
|
|
31
|
+
import { readFile, stat, unlink } from 'node:fs/promises';
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Types
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
/** Options for creating a bundle syncer. */
|
|
38
|
+
export type BundleSyncOptions = {
|
|
39
|
+
/** The typed ForgeRepoProtocol Web5 handle. */
|
|
40
|
+
repo: TypedWeb5<typeof ForgeRepoProtocol.definition, ForgeRepoSchemaMap>;
|
|
41
|
+
|
|
42
|
+
/** The repo's contextId (from the ForgeRepoProtocol repo record). */
|
|
43
|
+
repoContextId: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Repo visibility — controls whether bundle records are encrypted.
|
|
47
|
+
*
|
|
48
|
+
* - `'private'` → bundles are JWE-encrypted (only key-holders can read)
|
|
49
|
+
* - `'public'` → bundles are plaintext (IPFS-friendly, globally readable)
|
|
50
|
+
*
|
|
51
|
+
* The protocol must be installed with `encryption: true` for private repos
|
|
52
|
+
* to work (this injects `$encryption` keys on all protocol paths).
|
|
53
|
+
*
|
|
54
|
+
* @default 'public'
|
|
55
|
+
*/
|
|
56
|
+
visibility?: 'public' | 'private';
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Number of incremental bundles to accumulate before squashing.
|
|
60
|
+
* When this threshold is reached, the next bundle write is a squash
|
|
61
|
+
* that replaces all older bundles with a single full bundle.
|
|
62
|
+
*
|
|
63
|
+
* @default 5
|
|
64
|
+
*/
|
|
65
|
+
squashThreshold?: number;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/** Metadata about a generated git bundle. */
|
|
69
|
+
export type BundleInfo = {
|
|
70
|
+
/** Path to the bundle file on disk. */
|
|
71
|
+
path: string;
|
|
72
|
+
/** SHA of the tip commit (HEAD of default branch). */
|
|
73
|
+
tipCommit: string;
|
|
74
|
+
/** Whether this is a full bundle (all refs) or incremental. */
|
|
75
|
+
isFull: boolean;
|
|
76
|
+
/** Number of refs included in the bundle. */
|
|
77
|
+
refCount: number;
|
|
78
|
+
/** File size in bytes. */
|
|
79
|
+
size: number;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Public API
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Create an `onPushComplete` callback that syncs a git bundle to a DWN record.
|
|
88
|
+
*
|
|
89
|
+
* @param options - Bundle sync configuration
|
|
90
|
+
* @returns An async callback to invoke after a successful push
|
|
91
|
+
*/
|
|
92
|
+
export function createBundleSyncer(options: BundleSyncOptions): OnPushComplete {
|
|
93
|
+
const { repo, repoContextId, visibility = 'public', squashThreshold = 5 } = options;
|
|
94
|
+
const encrypt = visibility === 'private';
|
|
95
|
+
|
|
96
|
+
return async (_did: string, _repoName: string, repoPath: string): Promise<void> => {
|
|
97
|
+
// Query existing bundle records, newest first.
|
|
98
|
+
const { records: existingBundles } = await repo.records.query('repo/bundle', {
|
|
99
|
+
filter : { tags: { isFull: true } },
|
|
100
|
+
dateSort : DateSort.CreatedDescending,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Also query incremental bundles.
|
|
104
|
+
const { records: incrementalBundles } = await repo.records.query('repo/bundle', {
|
|
105
|
+
filter : { tags: { isFull: false } },
|
|
106
|
+
dateSort : DateSort.CreatedDescending,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const totalBundles = existingBundles.length + incrementalBundles.length;
|
|
110
|
+
|
|
111
|
+
// Determine the last tip commit from the most recent bundle (full or incremental).
|
|
112
|
+
let lastTipCommit: string | undefined;
|
|
113
|
+
if (incrementalBundles.length > 0 && incrementalBundles[0].tags) {
|
|
114
|
+
lastTipCommit = incrementalBundles[0].tags.tipCommit as string;
|
|
115
|
+
} else if (existingBundles.length > 0 && existingBundles[0].tags) {
|
|
116
|
+
lastTipCommit = existingBundles[0].tags.tipCommit as string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Decide whether to create a full or incremental bundle.
|
|
120
|
+
const shouldSquash = totalBundles > 0 && totalBundles >= squashThreshold;
|
|
121
|
+
const isIncremental = !shouldSquash && lastTipCommit !== undefined;
|
|
122
|
+
|
|
123
|
+
let bundleInfo: BundleInfo;
|
|
124
|
+
try {
|
|
125
|
+
if (isIncremental) {
|
|
126
|
+
// Create incremental bundle: only objects reachable from --all but not from lastTipCommit.
|
|
127
|
+
bundleInfo = await createIncrementalBundle(repoPath, lastTipCommit!);
|
|
128
|
+
} else {
|
|
129
|
+
// Create full bundle: all refs, all objects.
|
|
130
|
+
bundleInfo = await createFullBundle(repoPath);
|
|
131
|
+
}
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.error(`bundle-sync: failed to create bundle: ${(err as Error).message}`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
// Read the bundle data from disk.
|
|
139
|
+
const bundleData = new Uint8Array(await readFile(bundleInfo.path));
|
|
140
|
+
|
|
141
|
+
const tags = {
|
|
142
|
+
tipCommit : bundleInfo.tipCommit,
|
|
143
|
+
isFull : bundleInfo.isFull,
|
|
144
|
+
refCount : bundleInfo.refCount,
|
|
145
|
+
size : bundleInfo.size,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const createOptions: any = {
|
|
149
|
+
data : bundleData,
|
|
150
|
+
dataFormat : 'application/x-git-bundle',
|
|
151
|
+
tags,
|
|
152
|
+
parentContextId : repoContextId,
|
|
153
|
+
encryption : encrypt,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
if (shouldSquash) {
|
|
157
|
+
// Squash write: creates a new bundle record and purges all older ones.
|
|
158
|
+
createOptions.squash = true;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
await repo.records.create('repo/bundle', createOptions);
|
|
162
|
+
} finally {
|
|
163
|
+
// Clean up the temp bundle file.
|
|
164
|
+
await unlink(bundleInfo.path).catch(() => {});
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Bundle creation
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Create a full git bundle containing all refs and all reachable objects.
|
|
175
|
+
*
|
|
176
|
+
* @param repoPath - Path to the bare git repository
|
|
177
|
+
* @returns Bundle metadata and file path
|
|
178
|
+
*/
|
|
179
|
+
export async function createFullBundle(repoPath: string): Promise<BundleInfo> {
|
|
180
|
+
const bundlePath = join(tmpdir(), `gitd-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.bundle`);
|
|
181
|
+
|
|
182
|
+
await spawnChecked('git', ['bundle', 'create', bundlePath, '--all'], repoPath);
|
|
183
|
+
|
|
184
|
+
const tipCommit = await getTipCommit(repoPath);
|
|
185
|
+
const refCount = await getRefCount(repoPath);
|
|
186
|
+
const fileInfo = await stat(bundlePath);
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
path : bundlePath,
|
|
190
|
+
tipCommit,
|
|
191
|
+
isFull : true,
|
|
192
|
+
refCount,
|
|
193
|
+
size : fileInfo.size,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Create an incremental git bundle containing only objects since a base commit.
|
|
199
|
+
*
|
|
200
|
+
* The bundle uses the base commit as a prerequisite, meaning the consumer
|
|
201
|
+
* must already have it to apply the incremental bundle.
|
|
202
|
+
*
|
|
203
|
+
* @param repoPath - Path to the bare git repository
|
|
204
|
+
* @param baseCommit - The commit SHA to use as the prerequisite (exclude point)
|
|
205
|
+
* @returns Bundle metadata and file path
|
|
206
|
+
*/
|
|
207
|
+
export async function createIncrementalBundle(
|
|
208
|
+
repoPath: string,
|
|
209
|
+
baseCommit: string,
|
|
210
|
+
): Promise<BundleInfo> {
|
|
211
|
+
const bundlePath = join(tmpdir(), `gitd-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.bundle`);
|
|
212
|
+
|
|
213
|
+
// `--all ^<base>` means: include all refs, exclude objects reachable from base.
|
|
214
|
+
await spawnChecked('git', ['bundle', 'create', bundlePath, '--all', `^${baseCommit}`], repoPath);
|
|
215
|
+
|
|
216
|
+
const tipCommit = await getTipCommit(repoPath);
|
|
217
|
+
const refCount = await getRefCount(repoPath);
|
|
218
|
+
const fileInfo = await stat(bundlePath);
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
path : bundlePath,
|
|
222
|
+
tipCommit,
|
|
223
|
+
isFull : false,
|
|
224
|
+
refCount,
|
|
225
|
+
size : fileInfo.size,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
// Helpers
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get the tip commit SHA (HEAD of the default branch).
|
|
235
|
+
* Falls back to the first ref if HEAD is unset.
|
|
236
|
+
*/
|
|
237
|
+
async function getTipCommit(repoPath: string): Promise<string> {
|
|
238
|
+
try {
|
|
239
|
+
const sha = (await spawnCollectStdout('git', ['rev-parse', 'HEAD'], repoPath)).trim();
|
|
240
|
+
// In bare repos, HEAD may be a dangling symbolic ref (e.g. refs/heads/master
|
|
241
|
+
// doesn't exist). `git rev-parse HEAD` outputs the literal string "HEAD" in
|
|
242
|
+
// that case instead of a 40-hex SHA.
|
|
243
|
+
if (/^[0-9a-f]{40}$/.test(sha)) {
|
|
244
|
+
return sha;
|
|
245
|
+
}
|
|
246
|
+
} catch {
|
|
247
|
+
// rev-parse failed entirely — fall through to for-each-ref.
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// HEAD didn't resolve; get the first ref.
|
|
251
|
+
const output = await spawnCollectStdout(
|
|
252
|
+
'git', ['for-each-ref', '--format=%(objectname)', '--count=1', 'refs/'], repoPath,
|
|
253
|
+
);
|
|
254
|
+
return output.trim();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Count the number of refs (branches + tags) in the repo. */
|
|
258
|
+
async function getRefCount(repoPath: string): Promise<number> {
|
|
259
|
+
const output = await spawnCollectStdout(
|
|
260
|
+
'git', ['for-each-ref', '--format=x', 'refs/heads/', 'refs/tags/'], repoPath,
|
|
261
|
+
);
|
|
262
|
+
return output.split('\n').filter((l) => l.trim()).length;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Spawn a process and reject if it exits with non-zero code. */
|
|
266
|
+
function spawnChecked(cmd: string, args: string[], cwd: string): Promise<void> {
|
|
267
|
+
return new Promise((resolve, reject) => {
|
|
268
|
+
const child = spawn(cmd, args, { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
269
|
+
const stderrChunks: Buffer[] = [];
|
|
270
|
+
|
|
271
|
+
child.stderr!.on('data', (chunk: Buffer) => stderrChunks.push(chunk));
|
|
272
|
+
child.on('error', reject);
|
|
273
|
+
child.on('exit', (code) => {
|
|
274
|
+
if (code !== 0) {
|
|
275
|
+
const stderr = Buffer.concat(stderrChunks).toString('utf-8');
|
|
276
|
+
reject(new Error(`${cmd} ${args.join(' ')} exited with code ${code}: ${stderr}`));
|
|
277
|
+
} else {
|
|
278
|
+
resolve();
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Spawn a process, collect stdout, and return it as a string. */
|
|
285
|
+
function spawnCollectStdout(cmd: string, args: string[], cwd: string): Promise<string> {
|
|
286
|
+
return new Promise((resolve, reject) => {
|
|
287
|
+
const child = spawn(cmd, args, { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
288
|
+
const chunks: Buffer[] = [];
|
|
289
|
+
|
|
290
|
+
child.stdout!.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
291
|
+
child.on('error', reject);
|
|
292
|
+
child.on('exit', (code) => {
|
|
293
|
+
if (code !== 0) {
|
|
294
|
+
reject(new Error(`${cmd} ${args.join(' ')} exited with code ${code}`));
|
|
295
|
+
} else {
|
|
296
|
+
resolve(Buffer.concat(chunks).toString('utf-8'));
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DID document service management for git transport.
|
|
3
|
+
*
|
|
4
|
+
* Adds or updates a `GitTransport` service entry in a DID document,
|
|
5
|
+
* advertising the git smart HTTP endpoint for the `git-remote-did` helper.
|
|
6
|
+
*
|
|
7
|
+
* This module works with the agent's DID API to persist and publish
|
|
8
|
+
* service updates. For `did:dht`, the updated document is republished
|
|
9
|
+
* to the DHT network.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { Web5 } from '@enbox/api';
|
|
15
|
+
|
|
16
|
+
import { GIT_TRANSPORT_SERVICE_TYPE } from '../git-remote/service.js';
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Constants
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
/** Default service entry ID for the git transport endpoint. */
|
|
23
|
+
const GIT_SERVICE_ID = '#git';
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Public API
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Register a GitTransport service endpoint in the agent's DID document.
|
|
31
|
+
*
|
|
32
|
+
* If a GitTransport service already exists, its endpoint is updated.
|
|
33
|
+
* Otherwise, a new service entry is created. The updated DID document
|
|
34
|
+
* is persisted in the agent store and (for did:dht) republished.
|
|
35
|
+
*
|
|
36
|
+
* @param web5 - The Web5 instance (provides agent DID and did API)
|
|
37
|
+
* @param endpoint - The git transport HTTPS URL (e.g. `https://git.example.com`)
|
|
38
|
+
* @throws If the agent does not support DID updates
|
|
39
|
+
*/
|
|
40
|
+
export async function registerGitService(web5: Web5, endpoint: string): Promise<void> {
|
|
41
|
+
const agent = web5.agent as any;
|
|
42
|
+
|
|
43
|
+
// Verify the agent supports DID updates.
|
|
44
|
+
if (!agent.did?.update) {
|
|
45
|
+
console.warn(
|
|
46
|
+
'Agent does not support DID document updates. ' +
|
|
47
|
+
'GitTransport service not registered. ' +
|
|
48
|
+
'The git-remote-did helper will need a DWN endpoint fallback.',
|
|
49
|
+
);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const bearerDid = agent.agentDid;
|
|
54
|
+
const portableDid = await bearerDid.export();
|
|
55
|
+
|
|
56
|
+
// Look for an existing GitTransport service.
|
|
57
|
+
const services = portableDid.document.service ?? [];
|
|
58
|
+
const existingIdx = services.findIndex(
|
|
59
|
+
(s: any) => s.type === GIT_TRANSPORT_SERVICE_TYPE || s.id?.endsWith('git'),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const newService = {
|
|
63
|
+
id : GIT_SERVICE_ID,
|
|
64
|
+
type : GIT_TRANSPORT_SERVICE_TYPE,
|
|
65
|
+
serviceEndpoint : endpoint,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (existingIdx >= 0) {
|
|
69
|
+
services[existingIdx] = newService;
|
|
70
|
+
} else {
|
|
71
|
+
services.push(newService);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
portableDid.document.service = services;
|
|
75
|
+
|
|
76
|
+
await agent.did.update({ portableDid });
|
|
77
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git backend — wraps Git CLI commands for bare repository management.
|
|
3
|
+
*
|
|
4
|
+
* Provides a thin abstraction over `git init --bare`, `git upload-pack`, and
|
|
5
|
+
* `git receive-pack` for use by the smart HTTP transport handler.
|
|
6
|
+
*
|
|
7
|
+
* All repositories are stored as bare repos under a configurable base
|
|
8
|
+
* directory, organized by DID: `<basePath>/<did-hash>/<repo-name>.git`
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { createHash } from 'node:crypto';
|
|
14
|
+
import { spawn } from 'node:child_process';
|
|
15
|
+
import { join, resolve } from 'node:path';
|
|
16
|
+
|
|
17
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Types
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
/** Options for creating a GitBackend instance. */
|
|
24
|
+
export type GitBackendOptions = {
|
|
25
|
+
/**
|
|
26
|
+
* Base directory for storing bare repositories.
|
|
27
|
+
* Repos are stored as `<basePath>/<did-hash>/<repo>.git`
|
|
28
|
+
*/
|
|
29
|
+
basePath: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** Readable stream from a git subprocess. */
|
|
33
|
+
export type GitProcess = {
|
|
34
|
+
/** The subprocess stdout (pack data). */
|
|
35
|
+
stdout: ReadableStream<Uint8Array>;
|
|
36
|
+
|
|
37
|
+
/** The subprocess stdin for writing request data. */
|
|
38
|
+
stdin: WritableStream<Uint8Array>;
|
|
39
|
+
|
|
40
|
+
/** Promise that resolves with the exit code when the process completes. */
|
|
41
|
+
exitCode: Promise<number>;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// GitBackend
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Manages bare git repositories on the filesystem and spawns git subprocess
|
|
50
|
+
* for smart HTTP transport.
|
|
51
|
+
*/
|
|
52
|
+
export class GitBackend {
|
|
53
|
+
private readonly _basePath: string;
|
|
54
|
+
|
|
55
|
+
public constructor(options: GitBackendOptions) {
|
|
56
|
+
this._basePath = options.basePath;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Get the base path for all repositories. */
|
|
60
|
+
public get basePath(): string {
|
|
61
|
+
return this._basePath;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Compute the filesystem path for a repository.
|
|
66
|
+
*
|
|
67
|
+
* @param did - The DID of the repository owner
|
|
68
|
+
* @param repo - The repository name
|
|
69
|
+
* @returns Absolute path to the bare repo directory
|
|
70
|
+
* @throws If the repo name contains path traversal characters
|
|
71
|
+
*/
|
|
72
|
+
public repoPath(did: string, repo: string): string {
|
|
73
|
+
validateRepoName(repo);
|
|
74
|
+
const didHash = hashDid(did);
|
|
75
|
+
const repoDir = join(this._basePath, didHash, `${repo}.git`);
|
|
76
|
+
const resolved = resolve(repoDir);
|
|
77
|
+
const base = resolve(this._basePath);
|
|
78
|
+
if (!resolved.startsWith(base + '/') && resolved !== base) {
|
|
79
|
+
throw new Error(`Path traversal detected: repo name '${repo}' escapes base directory`);
|
|
80
|
+
}
|
|
81
|
+
return resolved;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check whether a repository exists on disk.
|
|
86
|
+
*
|
|
87
|
+
* @param did - The DID of the repository owner
|
|
88
|
+
* @param repo - The repository name
|
|
89
|
+
*/
|
|
90
|
+
public exists(did: string, repo: string): boolean {
|
|
91
|
+
const path = this.repoPath(did, repo);
|
|
92
|
+
return existsSync(join(path, 'HEAD'));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Initialize a new bare repository.
|
|
97
|
+
*
|
|
98
|
+
* @param did - The DID of the repository owner
|
|
99
|
+
* @param repo - The repository name
|
|
100
|
+
* @returns The path to the new bare repository
|
|
101
|
+
* @throws If `git init --bare` fails
|
|
102
|
+
*/
|
|
103
|
+
public async initRepo(did: string, repo: string): Promise<string> {
|
|
104
|
+
const path = this.repoPath(did, repo);
|
|
105
|
+
mkdirSync(path, { recursive: true });
|
|
106
|
+
|
|
107
|
+
const exitCode = await runGit(['init', '--bare', path]);
|
|
108
|
+
if (exitCode !== 0) {
|
|
109
|
+
throw new Error(`git init --bare failed with exit code ${exitCode} for ${path}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return path;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Spawn `git upload-pack` for fetch/clone operations.
|
|
117
|
+
*
|
|
118
|
+
* @param did - The DID of the repository owner
|
|
119
|
+
* @param repo - The repository name
|
|
120
|
+
* @returns A GitProcess with stdin/stdout streams for the subprocess
|
|
121
|
+
* @throws If the repository does not exist
|
|
122
|
+
*/
|
|
123
|
+
public uploadPack(did: string, repo: string): GitProcess {
|
|
124
|
+
this._assertRepoExists(did, repo);
|
|
125
|
+
const path = this.repoPath(did, repo);
|
|
126
|
+
return spawnGitService('upload-pack', path);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Spawn `git receive-pack` for push operations.
|
|
131
|
+
*
|
|
132
|
+
* @param did - The DID of the repository owner
|
|
133
|
+
* @param repo - The repository name
|
|
134
|
+
* @returns A GitProcess with stdin/stdout streams for the subprocess
|
|
135
|
+
* @throws If the repository does not exist
|
|
136
|
+
*/
|
|
137
|
+
public receivePack(did: string, repo: string): GitProcess {
|
|
138
|
+
this._assertRepoExists(did, repo);
|
|
139
|
+
const path = this.repoPath(did, repo);
|
|
140
|
+
return spawnGitService('receive-pack', path);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Throw if the repo doesn't exist on disk. */
|
|
144
|
+
private _assertRepoExists(did: string, repo: string): void {
|
|
145
|
+
if (!this.exists(did, repo)) {
|
|
146
|
+
throw new Error(`Repository not found: ${did}/${repo}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Helpers
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
|
|
155
|
+
/** Allowed characters in a repository name: alphanumeric, dots, hyphens, underscores. */
|
|
156
|
+
const SAFE_REPO_NAME_RE = /^[a-zA-Z0-9._-]+$/;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Validate that a repository name is safe for filesystem use.
|
|
160
|
+
* Rejects path traversal components and unsafe characters.
|
|
161
|
+
*
|
|
162
|
+
* @throws If the repo name is invalid
|
|
163
|
+
*/
|
|
164
|
+
function validateRepoName(name: string): void {
|
|
165
|
+
if (!name || !SAFE_REPO_NAME_RE.test(name)) {
|
|
166
|
+
throw new Error(`Invalid repository name: '${name}'. Names must match ${SAFE_REPO_NAME_RE}`);
|
|
167
|
+
}
|
|
168
|
+
if (name === '.' || name === '..' || name.startsWith('.git')) {
|
|
169
|
+
throw new Error(`Invalid repository name: '${name}'`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Hash a DID to a short filesystem-safe directory name. */
|
|
174
|
+
function hashDid(did: string): string {
|
|
175
|
+
return createHash('sha256').update(did).digest('hex').slice(0, 16);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Run a git command and return the exit code. */
|
|
179
|
+
async function runGit(args: string[]): Promise<number> {
|
|
180
|
+
return new Promise((resolve, reject) => {
|
|
181
|
+
const child = spawn('git', args, { stdio: 'pipe' });
|
|
182
|
+
child.on('error', reject);
|
|
183
|
+
child.on('exit', (code) => resolve(code ?? 128));
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Spawn a git service subprocess (upload-pack or receive-pack) and return
|
|
189
|
+
* web-standard ReadableStream/WritableStream wrappers around its stdio.
|
|
190
|
+
*/
|
|
191
|
+
function spawnGitService(service: 'upload-pack' | 'receive-pack', repoPath: string): GitProcess {
|
|
192
|
+
const child = spawn('git', [service, '--stateless-rpc', repoPath], {
|
|
193
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const stdout = new ReadableStream<Uint8Array>({
|
|
197
|
+
start(controller): void {
|
|
198
|
+
child.stdout!.on('data', (chunk: Buffer) => controller.enqueue(new Uint8Array(chunk)));
|
|
199
|
+
child.stdout!.on('end', () => controller.close());
|
|
200
|
+
child.stdout!.on('error', (err) => controller.error(err));
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const stdin = new WritableStream<Uint8Array>({
|
|
205
|
+
write(chunk): void {
|
|
206
|
+
child.stdin!.write(chunk);
|
|
207
|
+
},
|
|
208
|
+
close(): void {
|
|
209
|
+
child.stdin!.end();
|
|
210
|
+
},
|
|
211
|
+
abort(): void {
|
|
212
|
+
child.stdin!.destroy();
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const exitCode = new Promise<number>((resolve, reject) => {
|
|
217
|
+
child.on('error', reject);
|
|
218
|
+
child.on('exit', (code) => resolve(code ?? 128));
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return { stdout, stdin, exitCode };
|
|
222
|
+
}
|