@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,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push authentication for the git transport sidecar.
|
|
3
|
+
*
|
|
4
|
+
* Implements a DID-based authentication scheme for git push operations.
|
|
5
|
+
* The scheme uses signed tokens that prove DID ownership:
|
|
6
|
+
*
|
|
7
|
+
* 1. The client generates a token: `base64url(JSON({ did, repo, exp, nonce }))`
|
|
8
|
+
* 2. The client signs the token with their DID's Ed25519 key
|
|
9
|
+
* 3. The client sends the token + signature as HTTP Basic auth credentials:
|
|
10
|
+
* - username: `did-auth` (fixed; DIDs contain colons so can't be usernames)
|
|
11
|
+
* - password: `<base64url-signature>.<base64url-token>`
|
|
12
|
+
* 4. The server verifies the signature using the DID document's
|
|
13
|
+
* authentication verification method
|
|
14
|
+
*
|
|
15
|
+
* This approach works with git's native credential helper system — no custom
|
|
16
|
+
* transport modifications required.
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { randomBytes } from 'node:crypto';
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Constants
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Fixed username for HTTP Basic auth.
|
|
29
|
+
* DIDs contain colons which conflict with HTTP Basic auth's username:password
|
|
30
|
+
* separator, so we use a fixed username and embed the DID in the token payload.
|
|
31
|
+
*/
|
|
32
|
+
export const DID_AUTH_USERNAME = 'did-auth';
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Types
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/** The payload inside a signed push token. */
|
|
39
|
+
export type PushTokenPayload = {
|
|
40
|
+
/** The DID of the pusher. */
|
|
41
|
+
did: string;
|
|
42
|
+
|
|
43
|
+
/** The repository owner's DID. */
|
|
44
|
+
owner: string;
|
|
45
|
+
|
|
46
|
+
/** The repository name. */
|
|
47
|
+
repo: string;
|
|
48
|
+
|
|
49
|
+
/** Token expiration timestamp (seconds since epoch). */
|
|
50
|
+
exp: number;
|
|
51
|
+
|
|
52
|
+
/** Random nonce to prevent replay. */
|
|
53
|
+
nonce: string;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** A signed push token (token + signature). */
|
|
57
|
+
export type SignedPushToken = {
|
|
58
|
+
/** The base64url-encoded token payload. */
|
|
59
|
+
token: string;
|
|
60
|
+
|
|
61
|
+
/** The base64url-encoded Ed25519 signature over the token. */
|
|
62
|
+
signature: string;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Verification callback that resolves a DID, extracts the Ed25519 public key,
|
|
67
|
+
* and verifies the signature.
|
|
68
|
+
*
|
|
69
|
+
* @param did - The DID that claims to have signed the token
|
|
70
|
+
* @param payload - The raw token bytes that were signed
|
|
71
|
+
* @param signature - The signature bytes to verify
|
|
72
|
+
* @returns `true` if the signature is valid for the DID's authentication key
|
|
73
|
+
*/
|
|
74
|
+
export type SignatureVerifier = (
|
|
75
|
+
did: string,
|
|
76
|
+
payload: Uint8Array,
|
|
77
|
+
signature: Uint8Array,
|
|
78
|
+
) => Promise<boolean>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Authorization callback that checks whether a DID has push access to a repo.
|
|
82
|
+
* This typically queries the DWN for a `repo/maintainer` role record.
|
|
83
|
+
*
|
|
84
|
+
* @param did - The authenticated pusher's DID
|
|
85
|
+
* @param owner - The repository owner's DID
|
|
86
|
+
* @param repo - The repository name
|
|
87
|
+
* @returns `true` if the DID is authorized to push
|
|
88
|
+
*/
|
|
89
|
+
export type PushAuthorizer = (
|
|
90
|
+
did: string,
|
|
91
|
+
owner: string,
|
|
92
|
+
repo: string,
|
|
93
|
+
) => Promise<boolean>;
|
|
94
|
+
|
|
95
|
+
/** Options for creating a push authenticator. */
|
|
96
|
+
export type PushAuthenticatorOptions = {
|
|
97
|
+
/** Callback to verify Ed25519 signatures against a DID document. */
|
|
98
|
+
verifySignature: SignatureVerifier;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Optional callback to check push authorization (role-based access).
|
|
102
|
+
* If not provided, any authenticated DID is allowed to push.
|
|
103
|
+
*/
|
|
104
|
+
authorizePush?: PushAuthorizer;
|
|
105
|
+
|
|
106
|
+
/** Maximum token age in seconds. @default 300 (5 minutes) */
|
|
107
|
+
maxTokenAge?: number;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Token creation (client-side)
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Create a push token payload.
|
|
116
|
+
*
|
|
117
|
+
* @param did - The pusher's DID
|
|
118
|
+
* @param owner - The repository owner's DID
|
|
119
|
+
* @param repo - The repository name
|
|
120
|
+
* @param ttlSeconds - Token lifetime in seconds (default: 300)
|
|
121
|
+
* @returns The token payload
|
|
122
|
+
*/
|
|
123
|
+
export function createPushTokenPayload(
|
|
124
|
+
did: string,
|
|
125
|
+
owner: string,
|
|
126
|
+
repo: string,
|
|
127
|
+
ttlSeconds: number = 300,
|
|
128
|
+
): PushTokenPayload {
|
|
129
|
+
return {
|
|
130
|
+
did,
|
|
131
|
+
owner,
|
|
132
|
+
repo,
|
|
133
|
+
exp : Math.floor(Date.now() / 1000) + ttlSeconds,
|
|
134
|
+
nonce : randomBytes(16).toString('hex'),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Encode a push token payload as a base64url string.
|
|
140
|
+
*
|
|
141
|
+
* @param payload - The token payload
|
|
142
|
+
* @returns base64url-encoded JSON
|
|
143
|
+
*/
|
|
144
|
+
export function encodePushToken(payload: PushTokenPayload): string {
|
|
145
|
+
const json = JSON.stringify(payload);
|
|
146
|
+
return Buffer.from(json).toString('base64url');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Decode a base64url push token string back to a payload.
|
|
151
|
+
*
|
|
152
|
+
* @param token - The base64url-encoded token
|
|
153
|
+
* @returns The decoded payload
|
|
154
|
+
* @throws If the token is malformed
|
|
155
|
+
*/
|
|
156
|
+
export function decodePushToken(token: string): PushTokenPayload {
|
|
157
|
+
try {
|
|
158
|
+
const json = Buffer.from(token, 'base64url').toString('utf-8');
|
|
159
|
+
const payload = JSON.parse(json) as PushTokenPayload;
|
|
160
|
+
|
|
161
|
+
if (!payload.did || !payload.owner || !payload.repo || !payload.exp || !payload.nonce) {
|
|
162
|
+
throw new Error('missing required fields');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return payload;
|
|
166
|
+
} catch (err) {
|
|
167
|
+
throw new Error(`Invalid push token: ${(err as Error).message}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Format a signed push token for use as an HTTP Basic auth password.
|
|
173
|
+
* The format is `<base64url-signature>.<base64url-token>`.
|
|
174
|
+
*
|
|
175
|
+
* @param signed - The signed token
|
|
176
|
+
* @returns The formatted password string
|
|
177
|
+
*/
|
|
178
|
+
export function formatAuthPassword(signed: SignedPushToken): string {
|
|
179
|
+
return `${signed.signature}.${signed.token}`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Parse an HTTP Basic auth password back into a signed push token.
|
|
184
|
+
*
|
|
185
|
+
* @param password - The password from HTTP Basic auth
|
|
186
|
+
* @returns The parsed signed token
|
|
187
|
+
* @throws If the format is invalid
|
|
188
|
+
*/
|
|
189
|
+
export function parseAuthPassword(password: string): SignedPushToken {
|
|
190
|
+
const dotIndex = password.indexOf('.');
|
|
191
|
+
if (dotIndex === -1) {
|
|
192
|
+
throw new Error('Invalid auth password format: expected <signature>.<token>');
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
signature : password.slice(0, dotIndex),
|
|
196
|
+
token : password.slice(dotIndex + 1),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// Push authenticator factory (server-side)
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Create an `authenticatePush` callback for use with `createGitHttpHandler`.
|
|
206
|
+
*
|
|
207
|
+
* Extracts HTTP Basic credentials from the request, verifies the signed token,
|
|
208
|
+
* and optionally checks role-based authorization.
|
|
209
|
+
*
|
|
210
|
+
* @param options - Authenticator configuration
|
|
211
|
+
* @returns An authenticatePush callback
|
|
212
|
+
*/
|
|
213
|
+
export function createPushAuthenticator(
|
|
214
|
+
options: PushAuthenticatorOptions,
|
|
215
|
+
): (request: Request, did: string, repo: string) => Promise<boolean> {
|
|
216
|
+
const { verifySignature, authorizePush, maxTokenAge = 300 } = options;
|
|
217
|
+
|
|
218
|
+
// Nonce replay protection: track used nonces with timestamps for TTL eviction.
|
|
219
|
+
const usedNonces = new Map<string, number>();
|
|
220
|
+
const nonceMaxAge = (maxTokenAge + 60) * 1000; // ms — token TTL + clock skew
|
|
221
|
+
|
|
222
|
+
/** Evict expired nonces to prevent unbounded growth. */
|
|
223
|
+
function evictExpiredNonces(): void {
|
|
224
|
+
const cutoff = Date.now() - nonceMaxAge;
|
|
225
|
+
for (const [nonce, ts] of usedNonces) {
|
|
226
|
+
if (ts < cutoff) { usedNonces.delete(nonce); }
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return async (request: Request, ownerDid: string, repo: string): Promise<boolean> => {
|
|
231
|
+
// Extract HTTP Basic auth credentials.
|
|
232
|
+
// Username is fixed to "did-auth" (DIDs contain colons, which conflict
|
|
233
|
+
// with HTTP Basic auth's colon separator). The DID is inside the token.
|
|
234
|
+
const authHeader = request.headers.get('Authorization');
|
|
235
|
+
if (!authHeader?.startsWith('Basic ')) {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const decoded = Buffer.from(authHeader.slice(6), 'base64').toString('utf-8');
|
|
240
|
+
const colonIdx = decoded.indexOf(':');
|
|
241
|
+
if (colonIdx === -1) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const username = decoded.slice(0, colonIdx);
|
|
246
|
+
const password = decoded.slice(colonIdx + 1);
|
|
247
|
+
|
|
248
|
+
// Verify the username is the expected fixed value.
|
|
249
|
+
if (username !== DID_AUTH_USERNAME) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Parse the signed token from the password field.
|
|
254
|
+
let signed: SignedPushToken;
|
|
255
|
+
try {
|
|
256
|
+
signed = parseAuthPassword(password);
|
|
257
|
+
} catch {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Decode and validate the token payload.
|
|
262
|
+
let payload: PushTokenPayload;
|
|
263
|
+
try {
|
|
264
|
+
payload = decodePushToken(signed.token);
|
|
265
|
+
} catch {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Verify the token targets the correct owner and repo.
|
|
270
|
+
if (payload.owner !== ownerDid || payload.repo !== repo) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Verify the token hasn't expired.
|
|
275
|
+
const now = Math.floor(Date.now() / 1000);
|
|
276
|
+
if (payload.exp < now) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Verify the token isn't too far in the future (clock skew protection).
|
|
281
|
+
if (payload.exp > now + maxTokenAge + 60) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Verify the Ed25519 signature.
|
|
286
|
+
const tokenBytes = new TextEncoder().encode(signed.token);
|
|
287
|
+
const signatureBytes = new Uint8Array(Buffer.from(signed.signature, 'base64url'));
|
|
288
|
+
|
|
289
|
+
const signatureValid = await verifySignature(payload.did, tokenBytes, signatureBytes);
|
|
290
|
+
if (!signatureValid) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Nonce replay protection — reject already-used nonces.
|
|
295
|
+
evictExpiredNonces();
|
|
296
|
+
if (usedNonces.has(payload.nonce)) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
usedNonces.set(payload.nonce, Date.now());
|
|
300
|
+
|
|
301
|
+
// Optional: Check role-based push authorization.
|
|
302
|
+
if (authorizePush) {
|
|
303
|
+
return authorizePush(payload.did, ownerDid, repo);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return true;
|
|
307
|
+
};
|
|
308
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle restore — reconstructs a bare git repo from DWN bundle records.
|
|
3
|
+
*
|
|
4
|
+
* When a commodity git host receives a clone request for a repo it doesn't
|
|
5
|
+
* have on disk, it resolves the owner's DID, reads bundle records from
|
|
6
|
+
* the owner's DWN, and reconstructs the bare repo locally.
|
|
7
|
+
*
|
|
8
|
+
* Restore flow:
|
|
9
|
+
* 1. Query the owner's DWN for bundle records (via the repo's contextId)
|
|
10
|
+
* 2. Find the most recent full bundle (isFull: true)
|
|
11
|
+
* 3. Clone from the full bundle to create a bare repo
|
|
12
|
+
* 4. Apply any incremental bundles (in chronological order) that are newer
|
|
13
|
+
* 5. The restored repo is now ready to serve clones and accept pushes
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { ForgeRepoProtocol } from '../repo.js';
|
|
19
|
+
import type { ForgeRepoSchemaMap } from '../repo.js';
|
|
20
|
+
import type { TypedWeb5 } from '@enbox/api';
|
|
21
|
+
|
|
22
|
+
import { DateSort } from '@enbox/dwn-sdk-js';
|
|
23
|
+
import { existsSync } from 'node:fs';
|
|
24
|
+
import { join } from 'node:path';
|
|
25
|
+
import { spawn } from 'node:child_process';
|
|
26
|
+
import { tmpdir } from 'node:os';
|
|
27
|
+
import { mkdir, unlink, writeFile } from 'node:fs/promises';
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Types
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
/** Options for restoring a repository from DWN bundles. */
|
|
34
|
+
export type BundleRestoreOptions = {
|
|
35
|
+
/** The typed ForgeRepoProtocol Web5 handle for the owner's DWN. */
|
|
36
|
+
repo: TypedWeb5<typeof ForgeRepoProtocol.definition, ForgeRepoSchemaMap>;
|
|
37
|
+
|
|
38
|
+
/** Path where the bare repository should be created. */
|
|
39
|
+
repoPath: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** Result of a bundle restore operation. */
|
|
43
|
+
export type BundleRestoreResult = {
|
|
44
|
+
/** Whether the restore succeeded. */
|
|
45
|
+
success: boolean;
|
|
46
|
+
|
|
47
|
+
/** Number of bundles applied (1 full + N incrementals). */
|
|
48
|
+
bundlesApplied: number;
|
|
49
|
+
|
|
50
|
+
/** The tip commit SHA after restore. */
|
|
51
|
+
tipCommit?: string;
|
|
52
|
+
|
|
53
|
+
/** Error message if restore failed. */
|
|
54
|
+
error?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Public API
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Restore a bare git repository from DWN bundle records.
|
|
63
|
+
*
|
|
64
|
+
* Queries the owner's DWN for bundle records, downloads the most recent
|
|
65
|
+
* full bundle, clones from it, then applies any incremental bundles.
|
|
66
|
+
*
|
|
67
|
+
* @param options - Restore configuration
|
|
68
|
+
* @returns Result of the restore operation
|
|
69
|
+
*/
|
|
70
|
+
export async function restoreFromBundles(
|
|
71
|
+
options: BundleRestoreOptions,
|
|
72
|
+
): Promise<BundleRestoreResult> {
|
|
73
|
+
const { repo, repoPath } = options;
|
|
74
|
+
|
|
75
|
+
// 1. Query for the most recent full bundle.
|
|
76
|
+
const { records: fullBundles } = await repo.records.query('repo/bundle', {
|
|
77
|
+
filter : { tags: { isFull: true } },
|
|
78
|
+
dateSort : DateSort.CreatedDescending,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (fullBundles.length === 0) {
|
|
82
|
+
return { success: false, bundlesApplied: 0, error: 'No full bundle found in DWN' };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const latestFull = fullBundles[0];
|
|
86
|
+
const fullTimestamp = latestFull.dateCreated;
|
|
87
|
+
|
|
88
|
+
// 2. Download the full bundle to a temp file.
|
|
89
|
+
const fullBundlePath = tempBundlePath();
|
|
90
|
+
try {
|
|
91
|
+
const fullBlob = await latestFull.data.blob();
|
|
92
|
+
const fullBlobData = Buffer.from(await fullBlob.arrayBuffer());
|
|
93
|
+
await writeFile(fullBundlePath, fullBlobData);
|
|
94
|
+
|
|
95
|
+
// 3. Clone from the full bundle to create the bare repo.
|
|
96
|
+
await ensureParentDir(repoPath);
|
|
97
|
+
await spawnChecked('git', ['clone', '--bare', fullBundlePath, repoPath]);
|
|
98
|
+
|
|
99
|
+
let bundlesApplied = 1;
|
|
100
|
+
|
|
101
|
+
// 4. Query for incremental bundles newer than the full bundle.
|
|
102
|
+
const { records: incrementals } = await repo.records.query('repo/bundle', {
|
|
103
|
+
filter : { tags: { isFull: false } },
|
|
104
|
+
dateSort : DateSort.CreatedAscending,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Apply incremental bundles in chronological order.
|
|
108
|
+
for (const incBundle of incrementals) {
|
|
109
|
+
// Only apply incrementals that are newer than the full bundle.
|
|
110
|
+
if (incBundle.dateCreated <= fullTimestamp) { continue; }
|
|
111
|
+
|
|
112
|
+
const incPath = tempBundlePath();
|
|
113
|
+
try {
|
|
114
|
+
const incBlob = await incBundle.data.blob();
|
|
115
|
+
const incData = Buffer.from(await incBlob.arrayBuffer());
|
|
116
|
+
await writeFile(incPath, incData);
|
|
117
|
+
|
|
118
|
+
// Fetch all refs from the incremental bundle into the bare repo.
|
|
119
|
+
// The explicit refspec is required because bundles don't have a HEAD
|
|
120
|
+
// ref, and `git fetch` without a refspec tries to fetch HEAD.
|
|
121
|
+
await spawnChecked('git', ['fetch', incPath, 'refs/*:refs/*', '--update-head-ok'], repoPath);
|
|
122
|
+
bundlesApplied++;
|
|
123
|
+
} finally {
|
|
124
|
+
await unlink(incPath).catch(() => {});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 5. Get the tip commit.
|
|
129
|
+
const tipCommit = await getTipCommit(repoPath);
|
|
130
|
+
|
|
131
|
+
return { success: true, bundlesApplied, tipCommit };
|
|
132
|
+
} catch (err) {
|
|
133
|
+
return {
|
|
134
|
+
success : false,
|
|
135
|
+
bundlesApplied : 0,
|
|
136
|
+
error : (err as Error).message,
|
|
137
|
+
};
|
|
138
|
+
} finally {
|
|
139
|
+
await unlink(fullBundlePath).catch(() => {});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// Helpers
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
/** Generate a unique temp file path for a bundle. */
|
|
148
|
+
function tempBundlePath(): string {
|
|
149
|
+
return join(tmpdir(), `gitd-restore-${Date.now()}-${Math.random().toString(36).slice(2)}.bundle`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Ensure the parent directory of a path exists. */
|
|
153
|
+
async function ensureParentDir(filePath: string): Promise<void> {
|
|
154
|
+
const parentDir = join(filePath, '..');
|
|
155
|
+
if (!existsSync(parentDir)) {
|
|
156
|
+
await mkdir(parentDir, { recursive: true });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get the tip commit SHA from a bare repo.
|
|
162
|
+
*
|
|
163
|
+
* In bare repos restored from bundles, HEAD may be a dangling symbolic ref
|
|
164
|
+
* (e.g. `refs/heads/master` doesn't exist but `refs/heads/main` does).
|
|
165
|
+
* Falls back to the first ref SHA if HEAD doesn't resolve to a commit.
|
|
166
|
+
*/
|
|
167
|
+
async function getTipCommit(repoPath: string): Promise<string> {
|
|
168
|
+
// Try HEAD first.
|
|
169
|
+
const headResult = await spawnCollectOptional('git', ['rev-parse', 'HEAD'], repoPath);
|
|
170
|
+
if (headResult && /^[0-9a-f]{40}$/.test(headResult)) {
|
|
171
|
+
return headResult;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// HEAD didn't resolve; get the first ref.
|
|
175
|
+
const refResult = await spawnCollectOptional(
|
|
176
|
+
'git', ['for-each-ref', '--format=%(objectname)', '--count=1', 'refs/'], repoPath,
|
|
177
|
+
);
|
|
178
|
+
return refResult || 'unknown';
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Spawn a process, collect stdout, return trimmed output or null on failure. */
|
|
182
|
+
function spawnCollectOptional(cmd: string, args: string[], cwd: string): Promise<string | null> {
|
|
183
|
+
return new Promise((resolve) => {
|
|
184
|
+
const child = spawn(cmd, args, { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
185
|
+
const chunks: Buffer[] = [];
|
|
186
|
+
|
|
187
|
+
child.stdout!.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
188
|
+
child.on('error', () => resolve(null));
|
|
189
|
+
child.on('exit', (code) => {
|
|
190
|
+
if (code !== 0) {
|
|
191
|
+
resolve(null);
|
|
192
|
+
} else {
|
|
193
|
+
const result = Buffer.concat(chunks).toString('utf-8').trim();
|
|
194
|
+
resolve(result || null);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Spawn a process and reject if it exits with non-zero code. */
|
|
201
|
+
function spawnChecked(cmd: string, args: string[], cwd?: string): Promise<void> {
|
|
202
|
+
return new Promise((resolve, reject) => {
|
|
203
|
+
const child = spawn(cmd, args, { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
204
|
+
const stderrChunks: Buffer[] = [];
|
|
205
|
+
|
|
206
|
+
child.stderr!.on('data', (chunk: Buffer) => stderrChunks.push(chunk));
|
|
207
|
+
child.on('error', reject);
|
|
208
|
+
child.on('exit', (code) => {
|
|
209
|
+
if (code !== 0) {
|
|
210
|
+
const stderr = Buffer.concat(stderrChunks).toString('utf-8');
|
|
211
|
+
reject(new Error(`${cmd} ${args.join(' ')} exited with code ${code}: ${stderr}`));
|
|
212
|
+
} else {
|
|
213
|
+
resolve();
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|