@package-broker/core 0.17.4 → 0.19.7
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/dist/cache/index.d.ts +0 -1
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +0 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/memory-driver.d.ts +1 -1
- package/dist/cache/memory-driver.d.ts.map +1 -1
- package/dist/cache/memory-driver.js +4 -2
- package/dist/cache/memory-driver.js.map +1 -1
- package/dist/db/create-database.d.ts +8 -0
- package/dist/db/create-database.d.ts.map +1 -0
- package/dist/db/create-database.js +13 -0
- package/dist/db/create-database.js.map +1 -0
- package/dist/db/index.d.ts +0 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +0 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/schema.d.ts +557 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +72 -2
- package/dist/db/schema.js.map +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +22 -2
- package/dist/factory.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/jobs/processor.d.ts.map +1 -1
- package/dist/jobs/processor.js +16 -6
- package/dist/jobs/processor.js.map +1 -1
- package/dist/kernel/container.d.ts +12 -0
- package/dist/kernel/container.d.ts.map +1 -0
- package/dist/kernel/container.js +43 -0
- package/dist/kernel/container.js.map +1 -0
- package/dist/kernel/events.d.ts +17 -0
- package/dist/kernel/events.d.ts.map +1 -0
- package/dist/kernel/events.js +54 -0
- package/dist/kernel/events.js.map +1 -0
- package/dist/kernel/hooks.d.ts +14 -0
- package/dist/kernel/hooks.d.ts.map +1 -0
- package/dist/kernel/hooks.js +31 -0
- package/dist/kernel/hooks.js.map +1 -0
- package/dist/kernel/index.d.ts +5 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +5 -0
- package/dist/kernel/index.js.map +1 -0
- package/dist/kernel/plugin.d.ts +21 -0
- package/dist/kernel/plugin.d.ts.map +1 -0
- package/dist/kernel/plugin.js +30 -0
- package/dist/kernel/plugin.js.map +1 -0
- package/dist/middleware/auth.d.ts +2 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +20 -5
- package/dist/middleware/auth.js.map +1 -1
- package/dist/modules/admin/admin.handlers.d.ts +1 -1
- package/dist/modules/admin/admin.handlers.d.ts.map +1 -1
- package/dist/modules/artifacts/artifacts.handlers.d.ts +1 -1
- package/dist/modules/artifacts/artifacts.handlers.d.ts.map +1 -1
- package/dist/modules/auth/auth.handlers.js +1 -1
- package/dist/modules/auth/auth.handlers.js.map +1 -1
- package/dist/modules/composer/index.d.ts.map +1 -1
- package/dist/modules/composer/index.js +5 -0
- package/dist/modules/composer/index.js.map +1 -1
- package/dist/modules/composer/tenant-composer.d.ts +32 -0
- package/dist/modules/composer/tenant-composer.d.ts.map +1 -0
- package/dist/modules/composer/tenant-composer.js +198 -0
- package/dist/modules/composer/tenant-composer.js.map +1 -0
- package/dist/modules/import/import.handlers.d.ts +4 -0
- package/dist/modules/import/import.handlers.d.ts.map +1 -0
- package/dist/modules/import/import.handlers.js +16 -0
- package/dist/modules/import/import.handlers.js.map +1 -0
- package/dist/{routes/api/openapi/settings.d.ts → modules/import/import.routes.d.ts} +20 -35
- package/dist/modules/import/import.routes.d.ts.map +1 -0
- package/dist/modules/import/import.routes.js +63 -0
- package/dist/modules/import/import.routes.js.map +1 -0
- package/dist/modules/import/index.d.ts +8 -0
- package/dist/modules/import/index.d.ts.map +1 -0
- package/dist/modules/import/index.js +8 -0
- package/dist/modules/import/index.js.map +1 -0
- package/dist/modules/organizations/index.d.ts +8 -0
- package/dist/modules/organizations/index.d.ts.map +1 -0
- package/dist/modules/organizations/index.js +22 -0
- package/dist/modules/organizations/index.js.map +1 -0
- package/dist/modules/organizations/organizations.handlers.d.ts +24 -0
- package/dist/modules/organizations/organizations.handlers.d.ts.map +1 -0
- package/dist/modules/organizations/organizations.handlers.js +278 -0
- package/dist/modules/organizations/organizations.handlers.js.map +1 -0
- package/dist/modules/organizations/organizations.routes.d.ts +596 -0
- package/dist/modules/organizations/organizations.routes.d.ts.map +1 -0
- package/dist/modules/organizations/organizations.routes.js +263 -0
- package/dist/modules/organizations/organizations.routes.js.map +1 -0
- package/dist/modules/packages/packages.handlers.d.ts +1 -1
- package/dist/modules/packages/packages.handlers.d.ts.map +1 -1
- package/dist/modules/packages/packages.handlers.js +3 -69
- package/dist/modules/packages/packages.handlers.js.map +1 -1
- package/dist/modules/repositories/repositories.handlers.d.ts +1 -1
- package/dist/modules/repositories/repositories.handlers.d.ts.map +1 -1
- package/dist/modules/repositories/repositories.handlers.js +74 -3
- package/dist/modules/repositories/repositories.handlers.js.map +1 -1
- package/dist/modules/repositories/repositories.routes.d.ts +12 -0
- package/dist/modules/repositories/repositories.routes.d.ts.map +1 -1
- package/dist/modules/system/index.d.ts.map +1 -1
- package/dist/modules/system/index.js +2 -1
- package/dist/modules/system/index.js.map +1 -1
- package/dist/modules/system/system.handlers.d.ts +11 -1
- package/dist/modules/system/system.handlers.d.ts.map +1 -1
- package/dist/modules/system/system.handlers.js +31 -1
- package/dist/modules/system/system.handlers.js.map +1 -1
- package/dist/modules/system/system.routes.d.ts +34 -4
- package/dist/modules/system/system.routes.d.ts.map +1 -1
- package/dist/modules/system/system.routes.js +21 -1
- package/dist/modules/system/system.routes.js.map +1 -1
- package/dist/modules/tenants/index.d.ts +8 -0
- package/dist/modules/tenants/index.d.ts.map +1 -0
- package/dist/modules/tenants/index.js +21 -0
- package/dist/modules/tenants/index.js.map +1 -0
- package/dist/modules/tenants/tenants.handlers.d.ts +24 -0
- package/dist/modules/tenants/tenants.handlers.d.ts.map +1 -0
- package/dist/modules/tenants/tenants.handlers.js +268 -0
- package/dist/modules/tenants/tenants.handlers.js.map +1 -0
- package/dist/modules/tenants/tenants.routes.d.ts +486 -0
- package/dist/modules/tenants/tenants.routes.d.ts.map +1 -0
- package/dist/modules/tenants/tenants.routes.js +227 -0
- package/dist/modules/tenants/tenants.routes.js.map +1 -0
- package/dist/modules/tokens/tokens.handlers.d.ts +1 -1
- package/dist/modules/tokens/tokens.handlers.d.ts.map +1 -1
- package/dist/modules/users/users.handlers.d.ts +1 -1
- package/dist/modules/users/users.handlers.d.ts.map +1 -1
- package/dist/modules/users/users.handlers.js +1 -1
- package/dist/modules/users/users.handlers.js.map +1 -1
- package/dist/plugins/security-advisories/advisory-db.d.ts +85 -0
- package/dist/plugins/security-advisories/advisory-db.d.ts.map +1 -0
- package/dist/plugins/security-advisories/advisory-db.js +161 -0
- package/dist/plugins/security-advisories/advisory-db.js.map +1 -0
- package/dist/plugins/security-advisories/advisory-service.d.ts +44 -0
- package/dist/plugins/security-advisories/advisory-service.d.ts.map +1 -0
- package/dist/plugins/security-advisories/advisory-service.js +122 -0
- package/dist/plugins/security-advisories/advisory-service.js.map +1 -0
- package/dist/plugins/security-advisories/advisory.handlers.d.ts +13 -0
- package/dist/plugins/security-advisories/advisory.handlers.d.ts.map +1 -0
- package/dist/plugins/security-advisories/advisory.handlers.js +87 -0
- package/dist/plugins/security-advisories/advisory.handlers.js.map +1 -0
- package/dist/plugins/security-advisories/advisory.module.d.ts +4 -0
- package/dist/plugins/security-advisories/advisory.module.d.ts.map +1 -0
- package/dist/plugins/security-advisories/advisory.module.js +13 -0
- package/dist/plugins/security-advisories/advisory.module.js.map +1 -0
- package/dist/plugins/security-advisories/advisory.routes.d.ts +73 -0
- package/dist/plugins/security-advisories/advisory.routes.d.ts.map +1 -0
- package/dist/plugins/security-advisories/advisory.routes.js +76 -0
- package/dist/plugins/security-advisories/advisory.routes.js.map +1 -0
- package/dist/plugins/security-advisories/index.d.ts +31 -0
- package/dist/plugins/security-advisories/index.d.ts.map +1 -0
- package/dist/plugins/security-advisories/index.js +100 -0
- package/dist/plugins/security-advisories/index.js.map +1 -0
- package/dist/ports.d.ts +39 -21
- package/dist/ports.d.ts.map +1 -1
- package/dist/queue/consumer.d.ts +0 -8
- package/dist/queue/consumer.d.ts.map +1 -1
- package/dist/queue/consumer.js +2 -23
- package/dist/queue/consumer.js.map +1 -1
- package/dist/queue/index.d.ts +2 -0
- package/dist/queue/index.d.ts.map +1 -1
- package/dist/queue/index.js +2 -0
- package/dist/queue/index.js.map +1 -1
- package/dist/queue/memory-driver.d.ts +3 -2
- package/dist/queue/memory-driver.d.ts.map +1 -1
- package/dist/queue/memory-driver.js.map +1 -1
- package/dist/routes/composer.d.ts +7 -1
- package/dist/routes/composer.d.ts.map +1 -1
- package/dist/routes/composer.js +172 -70
- package/dist/routes/composer.js.map +1 -1
- package/dist/routes/dist.d.ts.map +1 -1
- package/dist/routes/dist.js +26 -80
- package/dist/routes/dist.js.map +1 -1
- package/dist/routes/index.d.ts +0 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +0 -1
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/package-revalidation.d.ts +38 -0
- package/dist/routes/package-revalidation.d.ts.map +1 -0
- package/dist/routes/package-revalidation.js +66 -0
- package/dist/routes/package-revalidation.js.map +1 -0
- package/dist/services/GitHubOrgImporter.d.ts +21 -0
- package/dist/services/GitHubOrgImporter.d.ts.map +1 -0
- package/dist/services/GitHubOrgImporter.js +51 -0
- package/dist/services/GitHubOrgImporter.js.map +1 -0
- package/dist/services/TokenScopeService.d.ts +15 -0
- package/dist/services/TokenScopeService.d.ts.map +1 -0
- package/dist/services/TokenScopeService.js +42 -0
- package/dist/services/TokenScopeService.js.map +1 -0
- package/dist/storage/index.d.ts +0 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +0 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/sync/repository-sync.d.ts.map +1 -1
- package/dist/sync/repository-sync.js +35 -23
- package/dist/sync/repository-sync.js.map +1 -1
- package/dist/sync/strategies/git-ssh.d.ts +17 -0
- package/dist/sync/strategies/git-ssh.d.ts.map +1 -0
- package/dist/sync/strategies/git-ssh.js +325 -0
- package/dist/sync/strategies/git-ssh.js.map +1 -0
- package/dist/{routes/api/types.d.ts → types/openapi.d.ts} +3 -4
- package/dist/types/openapi.d.ts.map +1 -0
- package/dist/{routes/api/types.js → types/openapi.js} +1 -1
- package/dist/types/openapi.js.map +1 -0
- package/dist/utils/background.d.ts +7 -0
- package/dist/utils/background.d.ts.map +1 -0
- package/dist/utils/background.js +11 -0
- package/dist/utils/background.js.map +1 -0
- package/dist/utils/environment.d.ts +15 -0
- package/dist/utils/environment.d.ts.map +1 -0
- package/dist/utils/environment.js +38 -0
- package/dist/utils/environment.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/package-filter.d.ts +7 -0
- package/dist/utils/package-filter.d.ts.map +1 -0
- package/dist/utils/package-filter.js +23 -0
- package/dist/utils/package-filter.js.map +1 -0
- package/dist/utils/package-validator.d.ts +3 -3
- package/dist/utils/package-validator.d.ts.map +1 -1
- package/dist/utils/package-validator.js +4 -37
- package/dist/utils/package-validator.js.map +1 -1
- package/dist/utils/upstream-fetch.d.ts +18 -0
- package/dist/utils/upstream-fetch.d.ts.map +1 -1
- package/dist/utils/upstream-fetch.js +76 -5
- package/dist/utils/upstream-fetch.js.map +1 -1
- package/dist/utils/zip-utils.d.ts +13 -0
- package/dist/utils/zip-utils.d.ts.map +1 -0
- package/dist/utils/zip-utils.js +66 -0
- package/dist/utils/zip-utils.js.map +1 -0
- package/dist/vcs/bitbucket-provider.d.ts +19 -0
- package/dist/vcs/bitbucket-provider.d.ts.map +1 -0
- package/dist/vcs/bitbucket-provider.js +249 -0
- package/dist/vcs/bitbucket-provider.js.map +1 -0
- package/dist/vcs/github-provider.d.ts +16 -0
- package/dist/vcs/github-provider.d.ts.map +1 -0
- package/dist/vcs/github-provider.js +117 -0
- package/dist/vcs/github-provider.js.map +1 -0
- package/dist/vcs/gitlab-provider.d.ts +17 -0
- package/dist/vcs/gitlab-provider.d.ts.map +1 -0
- package/dist/vcs/gitlab-provider.js +216 -0
- package/dist/vcs/gitlab-provider.js.map +1 -0
- package/dist/vcs/index.d.ts +10 -0
- package/dist/vcs/index.d.ts.map +1 -0
- package/dist/vcs/index.js +24 -0
- package/dist/vcs/index.js.map +1 -0
- package/dist/vcs/registry.d.ts +32 -0
- package/dist/vcs/registry.d.ts.map +1 -0
- package/dist/vcs/registry.js +47 -0
- package/dist/vcs/registry.js.map +1 -0
- package/dist/workflows/package-storage.d.ts.map +1 -1
- package/dist/workflows/package-storage.js +3 -3
- package/dist/workflows/package-storage.js.map +1 -1
- package/package.json +11 -8
- package/dist/cache/kv-driver.d.ts +0 -16
- package/dist/cache/kv-driver.d.ts.map +0 -1
- package/dist/cache/kv-driver.js +0 -23
- package/dist/cache/kv-driver.js.map +0 -1
- package/dist/db/d1-driver.d.ts +0 -3
- package/dist/db/d1-driver.d.ts.map +0 -1
- package/dist/db/d1-driver.js +0 -7
- package/dist/db/d1-driver.js.map +0 -1
- package/dist/routes/api/artifacts.d.ts +0 -27
- package/dist/routes/api/artifacts.d.ts.map +0 -1
- package/dist/routes/api/artifacts.js +0 -57
- package/dist/routes/api/artifacts.js.map +0 -1
- package/dist/routes/api/auth.d.ts +0 -52
- package/dist/routes/api/auth.d.ts.map +0 -1
- package/dist/routes/api/auth.js +0 -277
- package/dist/routes/api/auth.js.map +0 -1
- package/dist/routes/api/index.d.ts +0 -10
- package/dist/routes/api/index.d.ts.map +0 -1
- package/dist/routes/api/index.js +0 -11
- package/dist/routes/api/index.js.map +0 -1
- package/dist/routes/api/openapi/artifacts.d.ts +0 -80
- package/dist/routes/api/openapi/artifacts.d.ts.map +0 -1
- package/dist/routes/api/openapi/artifacts.js +0 -73
- package/dist/routes/api/openapi/artifacts.js.map +0 -1
- package/dist/routes/api/openapi/auth.d.ts +0 -187
- package/dist/routes/api/openapi/auth.d.ts.map +0 -1
- package/dist/routes/api/openapi/auth.js +0 -135
- package/dist/routes/api/openapi/auth.js.map +0 -1
- package/dist/routes/api/openapi/health.d.ts +0 -23
- package/dist/routes/api/openapi/health.d.ts.map +0 -1
- package/dist/routes/api/openapi/health.js +0 -25
- package/dist/routes/api/openapi/health.js.map +0 -1
- package/dist/routes/api/openapi/index.d.ts +0 -10
- package/dist/routes/api/openapi/index.d.ts.map +0 -1
- package/dist/routes/api/openapi/index.js +0 -16
- package/dist/routes/api/openapi/index.js.map +0 -1
- package/dist/routes/api/openapi/packages.d.ts +0 -172
- package/dist/routes/api/openapi/packages.d.ts.map +0 -1
- package/dist/routes/api/openapi/packages.js +0 -126
- package/dist/routes/api/openapi/packages.js.map +0 -1
- package/dist/routes/api/openapi/repositories.d.ts +0 -451
- package/dist/routes/api/openapi/repositories.d.ts.map +0 -1
- package/dist/routes/api/openapi/repositories.js +0 -238
- package/dist/routes/api/openapi/repositories.js.map +0 -1
- package/dist/routes/api/openapi/settings.d.ts.map +0 -1
- package/dist/routes/api/openapi/settings.js +0 -72
- package/dist/routes/api/openapi/settings.js.map +0 -1
- package/dist/routes/api/openapi/stats.d.ts +0 -59
- package/dist/routes/api/openapi/stats.d.ts.map +0 -1
- package/dist/routes/api/openapi/stats.js +0 -53
- package/dist/routes/api/openapi/stats.js.map +0 -1
- package/dist/routes/api/openapi/tokens.d.ts +0 -202
- package/dist/routes/api/openapi/tokens.d.ts.map +0 -1
- package/dist/routes/api/openapi/tokens.js +0 -132
- package/dist/routes/api/openapi/tokens.js.map +0 -1
- package/dist/routes/api/openapi/users.d.ts +0 -190
- package/dist/routes/api/openapi/users.d.ts.map +0 -1
- package/dist/routes/api/openapi/users.js +0 -126
- package/dist/routes/api/openapi/users.js.map +0 -1
- package/dist/routes/api/packages.d.ts +0 -50
- package/dist/routes/api/packages.d.ts.map +0 -1
- package/dist/routes/api/packages.js +0 -708
- package/dist/routes/api/packages.js.map +0 -1
- package/dist/routes/api/repositories.d.ts +0 -58
- package/dist/routes/api/repositories.d.ts.map +0 -1
- package/dist/routes/api/repositories.js +0 -321
- package/dist/routes/api/repositories.js.map +0 -1
- package/dist/routes/api/settings.d.ts +0 -29
- package/dist/routes/api/settings.d.ts.map +0 -1
- package/dist/routes/api/settings.js +0 -81
- package/dist/routes/api/settings.js.map +0 -1
- package/dist/routes/api/stats.d.ts +0 -21
- package/dist/routes/api/stats.d.ts.map +0 -1
- package/dist/routes/api/stats.js +0 -51
- package/dist/routes/api/stats.js.map +0 -1
- package/dist/routes/api/tokens.d.ts +0 -40
- package/dist/routes/api/tokens.d.ts.map +0 -1
- package/dist/routes/api/tokens.js +0 -187
- package/dist/routes/api/tokens.js.map +0 -1
- package/dist/routes/api/types.d.ts.map +0 -1
- package/dist/routes/api/types.js.map +0 -1
- package/dist/routes/api/users.d.ts +0 -6
- package/dist/routes/api/users.d.ts.map +0 -1
- package/dist/routes/api/users.js +0 -115
- package/dist/routes/api/users.js.map +0 -1
- package/dist/storage/r2-driver.d.ts +0 -16
- package/dist/storage/r2-driver.d.ts.map +0 -1
- package/dist/storage/r2-driver.js +0 -28
- package/dist/storage/r2-driver.js.map +0 -1
package/dist/routes/composer.js
CHANGED
|
@@ -12,6 +12,8 @@ import { nanoid } from 'nanoid';
|
|
|
12
12
|
import { encryptCredentials } from '../utils/encryption';
|
|
13
13
|
import { getLogger } from '../utils/logger';
|
|
14
14
|
import { getAnalytics } from '../utils/analytics';
|
|
15
|
+
import { runInBackground } from '../utils/background';
|
|
16
|
+
import { revalidateStalePackage, REVALIDATION_TTL_SECONDS } from './package-revalidation';
|
|
15
17
|
/** Default maximum versions per package to avoid CPU timeout on Cloudflare Workers */
|
|
16
18
|
export const DEFAULT_MAX_VERSIONS = 50;
|
|
17
19
|
/**
|
|
@@ -28,7 +30,7 @@ function schedulePackageStorage(c, packageName, packageData, repoId, baseUrl) {
|
|
|
28
30
|
const logger = getLogger();
|
|
29
31
|
if (workflow) {
|
|
30
32
|
// Use Cloudflare Workflow for durable background processing
|
|
31
|
-
c
|
|
33
|
+
runInBackground(c, (async () => {
|
|
32
34
|
try {
|
|
33
35
|
const instance = await workflow.create({
|
|
34
36
|
id: `pkg-${packageName.replace('/', '-')}-${repoId}-${Date.now()}`,
|
|
@@ -67,7 +69,7 @@ function schedulePackageStorage(c, packageName, packageData, repoId, baseUrl) {
|
|
|
67
69
|
}
|
|
68
70
|
else {
|
|
69
71
|
// Inline background processing
|
|
70
|
-
c
|
|
72
|
+
runInBackground(c, (async () => {
|
|
71
73
|
try {
|
|
72
74
|
const db = c.get('database');
|
|
73
75
|
const { storedCount, errors } = await transformPackageDistUrls(packageData, repoId, baseUrl, db);
|
|
@@ -133,10 +135,13 @@ export async function packagesJsonRoute(c) {
|
|
|
133
135
|
}
|
|
134
136
|
// No cache - build packages.json from database
|
|
135
137
|
const packagesJson = await buildPackagesJson(c);
|
|
136
|
-
// Cache the result (fire-and-forget to avoid blocking on KV rate limits)
|
|
138
|
+
// Cache the result (fire-and-forget to avoid blocking on KV rate limits).
|
|
139
|
+
// Never cache while repository syncs are pending or in flight: the list is
|
|
140
|
+
// built from pre-sync data and would otherwise be pinned in KV until the
|
|
141
|
+
// next manual purge.
|
|
137
142
|
const cachingEnabled = await isPackageCachingEnabled(c.env.KV);
|
|
138
|
-
if (cachingEnabled && c.env.KV) {
|
|
139
|
-
c
|
|
143
|
+
if (cachingEnabled && c.env.KV && !hasPendingRepos) {
|
|
144
|
+
runInBackground(c, Promise.all([
|
|
140
145
|
c.env.KV.put(kvKey, JSON.stringify(packagesJson)).catch(() => { }),
|
|
141
146
|
c.env.KV.put(metadataKey, JSON.stringify({ lastModified: Date.now() })).catch(() => { })
|
|
142
147
|
]));
|
|
@@ -186,6 +191,36 @@ function matchesPackageFilter(packageName, filter) {
|
|
|
186
191
|
return pkgLower === pattern;
|
|
187
192
|
});
|
|
188
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Fetch package metadata from a single repository, dispatching on vcs_type.
|
|
196
|
+
* Returns the raw upstream package data, or null when the repo does not
|
|
197
|
+
* provide the package (filter mismatch, unsupported host, not found).
|
|
198
|
+
*/
|
|
199
|
+
export async function fetchPackageFromRepository(repo, packageName, encryptionKey) {
|
|
200
|
+
if (!matchesPackageFilter(packageName, repo.package_filter)) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
const repoRef = {
|
|
204
|
+
id: repo.id,
|
|
205
|
+
url: repo.url,
|
|
206
|
+
vcs_type: repo.vcs_type,
|
|
207
|
+
credential_type: repo.credential_type,
|
|
208
|
+
auth_credentials: repo.auth_credentials,
|
|
209
|
+
package_filter: repo.package_filter,
|
|
210
|
+
};
|
|
211
|
+
if (repo.vcs_type === 'composer') {
|
|
212
|
+
const { fetchPackageFromUpstream } = await import('../utils/upstream-fetch');
|
|
213
|
+
return fetchPackageFromUpstream(repoRef, packageName, encryptionKey);
|
|
214
|
+
}
|
|
215
|
+
if (repo.vcs_type === 'git') {
|
|
216
|
+
const { fetchPackageFromGitHub, isGitHubUrl } = await import('../utils/upstream-fetch');
|
|
217
|
+
if (!isGitHubUrl(repo.url)) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
return fetchPackageFromGitHub(repoRef, packageName, encryptionKey);
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
189
224
|
/**
|
|
190
225
|
* Lazy load package metadata from all available repositories
|
|
191
226
|
* Returns package data and repo_id if found, null otherwise
|
|
@@ -198,35 +233,7 @@ export async function lazyLoadPackageFromRepositories(db, packageName, encryptio
|
|
|
198
233
|
const sortedRepos = sortRepositoriesByPriority(allRepos);
|
|
199
234
|
for (const repo of sortedRepos) {
|
|
200
235
|
try {
|
|
201
|
-
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
let packageData = null;
|
|
205
|
-
if (repo.vcs_type === 'composer') {
|
|
206
|
-
const { fetchPackageFromUpstream } = await import('../utils/upstream-fetch');
|
|
207
|
-
packageData = await fetchPackageFromUpstream({
|
|
208
|
-
id: repo.id,
|
|
209
|
-
url: repo.url,
|
|
210
|
-
vcs_type: repo.vcs_type,
|
|
211
|
-
credential_type: repo.credential_type,
|
|
212
|
-
auth_credentials: repo.auth_credentials,
|
|
213
|
-
package_filter: repo.package_filter,
|
|
214
|
-
}, packageName, encryptionKey);
|
|
215
|
-
}
|
|
216
|
-
else if (repo.vcs_type === 'git') {
|
|
217
|
-
const { fetchPackageFromGitHub, isGitHubUrl } = await import('../utils/upstream-fetch');
|
|
218
|
-
if (!isGitHubUrl(repo.url)) {
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
packageData = await fetchPackageFromGitHub({
|
|
222
|
-
id: repo.id,
|
|
223
|
-
url: repo.url,
|
|
224
|
-
vcs_type: repo.vcs_type,
|
|
225
|
-
credential_type: repo.credential_type,
|
|
226
|
-
auth_credentials: repo.auth_credentials,
|
|
227
|
-
package_filter: repo.package_filter,
|
|
228
|
-
}, packageName, encryptionKey);
|
|
229
|
-
}
|
|
236
|
+
const packageData = await fetchPackageFromRepository(repo, packageName, encryptionKey);
|
|
230
237
|
if (packageData) {
|
|
231
238
|
return { packageData, repoId: repo.id };
|
|
232
239
|
}
|
|
@@ -245,6 +252,7 @@ export async function lazyLoadPackageFromRepositories(db, packageName, encryptio
|
|
|
245
252
|
const mirroringEnabled = await isPackagistMirroringEnabled(kv);
|
|
246
253
|
if (mirroringEnabled) {
|
|
247
254
|
try {
|
|
255
|
+
await ensurePackagistRepository(db, encryptionKey, kv || undefined);
|
|
248
256
|
const packagistUrl = `https://repo.packagist.org/p2/${packageName}.json`;
|
|
249
257
|
const response = await fetch(packagistUrl, {
|
|
250
258
|
headers: {
|
|
@@ -274,13 +282,16 @@ export async function lazyLoadPackageFromRepositories(db, packageName, encryptio
|
|
|
274
282
|
export async function p2PackageRoute(c) {
|
|
275
283
|
const vendor = c.req.param('vendor');
|
|
276
284
|
const packageFile = c.req.param('package');
|
|
277
|
-
|
|
285
|
+
// Strip only the trailing extension - package names may contain ".json"
|
|
286
|
+
const packageName = `${vendor}/${packageFile?.replace(/\.json$/, '')}`;
|
|
278
287
|
if (!vendor || !packageFile) {
|
|
279
288
|
return c.json({ error: 'Bad Request', message: 'Invalid package name' }, 400);
|
|
280
289
|
}
|
|
281
290
|
const kvKey = `p2:${packageName}`;
|
|
282
291
|
const metadataKey = `p2:${packageName}:metadata`;
|
|
283
292
|
const db = c.get('database');
|
|
293
|
+
const requestUrl = new URL(c.req.url);
|
|
294
|
+
const requestBaseUrl = `${requestUrl.protocol}//${requestUrl.host}`;
|
|
284
295
|
// Check conditional request
|
|
285
296
|
const ifModifiedSince = c.req.header('If-Modified-Since');
|
|
286
297
|
const metadata = c.env.KV ? await c.env.KV.get(metadataKey, 'json') : null;
|
|
@@ -303,7 +314,7 @@ export async function p2PackageRoute(c) {
|
|
|
303
314
|
logger.warn('Invalid cache format (not an object or old format), treating as cache miss', { packageName });
|
|
304
315
|
// Fire-and-forget cache deletion
|
|
305
316
|
if (c.env.KV) {
|
|
306
|
-
c
|
|
317
|
+
runInBackground(c, Promise.all([
|
|
307
318
|
c.env.KV.delete(kvKey).catch(() => { }),
|
|
308
319
|
c.env.KV.delete(metadataKey).catch(() => { })
|
|
309
320
|
]));
|
|
@@ -336,7 +347,7 @@ export async function p2PackageRoute(c) {
|
|
|
336
347
|
logger.warn('Invalid JSON in cache, treating as cache miss', { packageName, error: e instanceof Error ? e.message : String(e) });
|
|
337
348
|
// Fire-and-forget cache deletion
|
|
338
349
|
if (c.env.KV) {
|
|
339
|
-
c
|
|
350
|
+
runInBackground(c, Promise.all([
|
|
340
351
|
c.env.KV.delete(kvKey).catch(() => { }),
|
|
341
352
|
c.env.KV.delete(metadataKey).catch(() => { })
|
|
342
353
|
]));
|
|
@@ -351,16 +362,41 @@ export async function p2PackageRoute(c) {
|
|
|
351
362
|
if (existingPackages.length > 0) {
|
|
352
363
|
// Build response from database packages
|
|
353
364
|
const maxVersions = getMaxVersions(c.env);
|
|
354
|
-
const
|
|
355
|
-
const baseUrl = `${url.protocol}//${url.host}`;
|
|
356
|
-
const packageData = buildP2Response(packageName, existingPackages, maxVersions, baseUrl);
|
|
365
|
+
const packageData = buildP2Response(packageName, existingPackages, maxVersions, requestBaseUrl);
|
|
357
366
|
// Cache the result (fire-and-forget to avoid blocking on KV rate limits)
|
|
367
|
+
// TTL keeps cached responses from outliving the revalidation window
|
|
358
368
|
const cachingEnabled = await isPackageCachingEnabled(c.env.KV);
|
|
359
369
|
if (cachingEnabled && c.env.KV) {
|
|
360
|
-
c.
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
370
|
+
const kv = c.env.KV;
|
|
371
|
+
// Stale-while-revalidate: this branch is only reached when the cached
|
|
372
|
+
// response has expired (at most once per TTL), so it doubles as the
|
|
373
|
+
// trigger to re-check upstream for new releases. The cache write MUST
|
|
374
|
+
// complete before revalidation runs - otherwise revalidation's cache
|
|
375
|
+
// purge could be overwritten by this stale response.
|
|
376
|
+
// Pinned to the repos the rows came from - see package-revalidation.ts.
|
|
377
|
+
const repoIds = [...new Set(existingPackages.map((pkg) => pkg.repo_id))];
|
|
378
|
+
runInBackground(c, (async () => {
|
|
379
|
+
await Promise.all([
|
|
380
|
+
kv.put(kvKey, JSON.stringify(packageData), { expirationTtl: REVALIDATION_TTL_SECONDS }).catch(() => { }),
|
|
381
|
+
kv.put(metadataKey, JSON.stringify({ lastModified: Date.now() }), { expirationTtl: REVALIDATION_TTL_SECONDS }).catch(() => { })
|
|
382
|
+
]);
|
|
383
|
+
await revalidateStalePackage({
|
|
384
|
+
db,
|
|
385
|
+
cache: kv,
|
|
386
|
+
packageName,
|
|
387
|
+
repoIds,
|
|
388
|
+
encryptionKey: c.env.ENCRYPTION_KEY,
|
|
389
|
+
proxyBaseUrl: requestBaseUrl,
|
|
390
|
+
loadPackageFromRepo: fetchPackageFromRepository,
|
|
391
|
+
storePackages: transformPackageDistUrls,
|
|
392
|
+
});
|
|
393
|
+
})().catch((error) => {
|
|
394
|
+
const logger = getLogger();
|
|
395
|
+
logger.warn('Background package revalidation failed', {
|
|
396
|
+
packageName,
|
|
397
|
+
error: error instanceof Error ? error.message : String(error),
|
|
398
|
+
});
|
|
399
|
+
}));
|
|
364
400
|
}
|
|
365
401
|
// Track metadata request (cache miss, from DB)
|
|
366
402
|
const analytics = getAnalytics();
|
|
@@ -379,15 +415,13 @@ export async function p2PackageRoute(c) {
|
|
|
379
415
|
return new Response(JSON.stringify(packageData), { status: 200, headers });
|
|
380
416
|
}
|
|
381
417
|
// Not in database - try lazy loading from upstream repositories
|
|
382
|
-
const url = new URL(c.req.url);
|
|
383
|
-
const baseUrl = `${url.protocol}//${url.host}`;
|
|
384
418
|
const maxVersions = getMaxVersions(c.env);
|
|
385
419
|
const lazyLoadResult = await lazyLoadPackageFromRepositories(db, packageName, c.env.ENCRYPTION_KEY, c.env.KV);
|
|
386
420
|
if (lazyLoadResult) {
|
|
387
421
|
const { packageData, repoId } = lazyLoadResult;
|
|
388
|
-
const transformedData = transformDistUrlsInMemory(packageData, repoId,
|
|
422
|
+
const transformedData = transformDistUrlsInMemory(packageData, repoId, requestBaseUrl, maxVersions);
|
|
389
423
|
// Store package versions in background
|
|
390
|
-
schedulePackageStorage(c, packageName, packageData, repoId,
|
|
424
|
+
schedulePackageStorage(c, packageName, packageData, repoId, requestBaseUrl);
|
|
391
425
|
// Track metadata request (cache miss, from upstream)
|
|
392
426
|
const analytics = getAnalytics();
|
|
393
427
|
const requestId = c.get('requestId');
|
|
@@ -673,9 +707,61 @@ export function buildP2Response(packageName, packageVersions, maxVersions = DEFA
|
|
|
673
707
|
};
|
|
674
708
|
}
|
|
675
709
|
export function deriveVersionNormalized(version) {
|
|
676
|
-
const v = version.
|
|
710
|
+
const v = version.trim();
|
|
711
|
+
if (v.startsWith('dev-')) {
|
|
712
|
+
return v;
|
|
713
|
+
}
|
|
714
|
+
const versionWithoutV = v.startsWith('v') ? v.slice(1) : v;
|
|
715
|
+
const isNumericSegment = (part) => {
|
|
716
|
+
if (part.length === 0) {
|
|
717
|
+
return false;
|
|
718
|
+
}
|
|
719
|
+
for (let i = 0; i < part.length; i++) {
|
|
720
|
+
const ch = part.charCodeAt(i);
|
|
721
|
+
if (ch < 48 || ch > 57) {
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
return true;
|
|
726
|
+
};
|
|
727
|
+
const normalizeBranchName = (branchName) => {
|
|
728
|
+
const branchWithoutV = branchName.startsWith('v') ? branchName.slice(1) : branchName;
|
|
729
|
+
const parts = branchWithoutV.split('.');
|
|
730
|
+
if (parts.length < 1 || parts.length > 4) {
|
|
731
|
+
return undefined;
|
|
732
|
+
}
|
|
733
|
+
const normalizedParts = [];
|
|
734
|
+
for (const part of parts) {
|
|
735
|
+
if (isNumericSegment(part)) {
|
|
736
|
+
normalizedParts.push(part);
|
|
737
|
+
}
|
|
738
|
+
else if (part === 'x' || part === 'X' || part === '*') {
|
|
739
|
+
normalizedParts.push('9999999');
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
return undefined;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
while (normalizedParts.length < 4) {
|
|
746
|
+
normalizedParts.push('9999999');
|
|
747
|
+
}
|
|
748
|
+
return `${normalizedParts.join('.')}-dev`;
|
|
749
|
+
};
|
|
750
|
+
const lowerVersion = versionWithoutV.toLowerCase();
|
|
751
|
+
let branchName = null;
|
|
752
|
+
if (lowerVersion.endsWith('-dev') || lowerVersion.endsWith('.dev')) {
|
|
753
|
+
branchName = versionWithoutV.slice(0, -4);
|
|
754
|
+
}
|
|
755
|
+
if (branchName) {
|
|
756
|
+
if (branchName.includes('x') || branchName.includes('X') || branchName.includes('*')) {
|
|
757
|
+
const normalizedBranch = normalizeBranchName(branchName);
|
|
758
|
+
if (normalizedBranch) {
|
|
759
|
+
return normalizedBranch;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
677
763
|
// Handle patch versions (e.g., "103.0.7-p8" → "103.0.7.0-patch8")
|
|
678
|
-
const patchMatch =
|
|
764
|
+
const patchMatch = versionWithoutV.match(/^(\d+\.\d+\.\d+)-p(\d+)$/);
|
|
679
765
|
if (patchMatch) {
|
|
680
766
|
const [, base, patch] = patchMatch;
|
|
681
767
|
return `${base}.0-patch${patch}`;
|
|
@@ -684,13 +770,13 @@ export function deriveVersionNormalized(version) {
|
|
|
684
770
|
// 1. Parse up to 4 numeric segments separated by dots from the start of the string.
|
|
685
771
|
// 2. Treat everything after the parsed numeric part as the suffix (e.g., "-beta", "-alpha", "-dev").
|
|
686
772
|
let index = 0;
|
|
687
|
-
const length =
|
|
773
|
+
const length = versionWithoutV.length;
|
|
688
774
|
const segments = [];
|
|
689
775
|
while (index < length && segments.length < 4) {
|
|
690
776
|
const start = index;
|
|
691
777
|
// Read a numeric segment
|
|
692
778
|
while (index < length) {
|
|
693
|
-
const ch =
|
|
779
|
+
const ch = versionWithoutV.charCodeAt(index);
|
|
694
780
|
if (ch < 48 || ch > 57) { // not '0'–'9'
|
|
695
781
|
break;
|
|
696
782
|
}
|
|
@@ -700,13 +786,13 @@ export function deriveVersionNormalized(version) {
|
|
|
700
786
|
// No digits found where a segment was expected
|
|
701
787
|
break;
|
|
702
788
|
}
|
|
703
|
-
segments.push(
|
|
789
|
+
segments.push(versionWithoutV.slice(start, index));
|
|
704
790
|
// If we have 4 segments or we've reached the end, stop
|
|
705
791
|
if (segments.length === 4 || index >= length) {
|
|
706
792
|
break;
|
|
707
793
|
}
|
|
708
794
|
// Expect a dot between segments; if not present, stop parsing numeric part
|
|
709
|
-
if (
|
|
795
|
+
if (versionWithoutV[index] === '.') {
|
|
710
796
|
index++;
|
|
711
797
|
continue;
|
|
712
798
|
}
|
|
@@ -714,7 +800,7 @@ export function deriveVersionNormalized(version) {
|
|
|
714
800
|
}
|
|
715
801
|
if (segments.length > 0) {
|
|
716
802
|
const [major, minor = '0', patch = '0', build = '0'] = segments;
|
|
717
|
-
const suffix =
|
|
803
|
+
const suffix = versionWithoutV.slice(index); // everything after the numeric part
|
|
718
804
|
return `${major}.${minor}.${patch}.${build}${suffix}`;
|
|
719
805
|
}
|
|
720
806
|
// Fallback: return undefined for non-standard versions
|
|
@@ -764,21 +850,35 @@ export async function ensurePackagistRepository(db, encryptionKey, kv) {
|
|
|
764
850
|
await kv.put(cacheKey, 'true', { expirationTtl: 3600 });
|
|
765
851
|
}
|
|
766
852
|
}
|
|
853
|
+
/** A repo stuck in 'syncing' longer than this is treated as dead (killed worker) */
|
|
854
|
+
const STALE_SYNC_THRESHOLD_SECONDS = 900;
|
|
767
855
|
/**
|
|
768
|
-
* Sync all pending repositories
|
|
769
|
-
* Uses job processor which automatically chooses sync vs async execution
|
|
770
|
-
* @returns true
|
|
856
|
+
* Sync all pending repositories in the background.
|
|
857
|
+
* Uses job processor which automatically chooses sync vs async execution.
|
|
858
|
+
* @returns true while any repository sync is pending or still running -
|
|
859
|
+
* callers must not cache packages.json built in that window
|
|
771
860
|
*/
|
|
772
861
|
async function syncPendingRepositories(c) {
|
|
773
862
|
const db = c.get('database');
|
|
774
|
-
|
|
775
|
-
const reposToSync = await db
|
|
863
|
+
const unsettledRepos = await db
|
|
776
864
|
.select()
|
|
777
865
|
.from(repositories)
|
|
778
|
-
.where(
|
|
866
|
+
.where(inArray(repositories.status, ['pending', 'syncing']));
|
|
867
|
+
const now = Math.floor(Date.now() / 1000);
|
|
868
|
+
const isStaleSync = (repo) => repo.status === 'syncing' && (repo.last_synced_at || 0) <= now - STALE_SYNC_THRESHOLD_SECONDS;
|
|
869
|
+
// Re-sync repos stuck in 'syncing' (worker killed mid-sync) along with
|
|
870
|
+
// pending ones - otherwise they would stay unsynced forever
|
|
871
|
+
const reposToSync = unsettledRepos.filter((repo) => repo.status === 'pending' || isStaleSync(repo));
|
|
872
|
+
const syncsInFlight = unsettledRepos.filter((repo) => repo.status === 'syncing' && !isStaleSync(repo));
|
|
779
873
|
if (reposToSync.length === 0) {
|
|
780
|
-
return
|
|
874
|
+
return syncsInFlight.length > 0;
|
|
781
875
|
}
|
|
876
|
+
// Claim the repos before backgrounding the sync so concurrent
|
|
877
|
+
// packages.json requests do not start duplicate syncs of the same repo
|
|
878
|
+
await db
|
|
879
|
+
.update(repositories)
|
|
880
|
+
.set({ status: 'syncing', last_synced_at: now })
|
|
881
|
+
.where(and(inArray(repositories.id, reposToSync.map((repo) => repo.id)), inArray(repositories.status, ['pending', 'syncing'])));
|
|
782
882
|
// Determine proxy base URL from request
|
|
783
883
|
const url = new URL(c.req.url);
|
|
784
884
|
const proxyBaseUrl = `${url.protocol}//${url.host}`;
|
|
@@ -799,8 +899,12 @@ async function syncPendingRepositories(c) {
|
|
|
799
899
|
type: 'sync_repository',
|
|
800
900
|
repoId: repo.id,
|
|
801
901
|
}));
|
|
802
|
-
//
|
|
803
|
-
|
|
902
|
+
// Run syncs in the background: inline sync of a large repository would
|
|
903
|
+
// otherwise block the packages.json response until every repo finishes
|
|
904
|
+
runInBackground(c, jobProcessor.enqueueAll(syncJobs).catch((error) => {
|
|
905
|
+
const logger = getLogger();
|
|
906
|
+
logger.error('Background repository sync failed', {}, error instanceof Error ? error : new Error(String(error)));
|
|
907
|
+
}));
|
|
804
908
|
return true;
|
|
805
909
|
}
|
|
806
910
|
/**
|
|
@@ -1053,7 +1157,7 @@ export async function transformPackageDistUrls(packageData, repoId, proxyBaseUrl
|
|
|
1053
1157
|
const allVersions = await db
|
|
1054
1158
|
.select()
|
|
1055
1159
|
.from(packages)
|
|
1056
|
-
.where(inArray(packages.name, nameChunk));
|
|
1160
|
+
.where(and(eq(packages.repo_id, repoId), inArray(packages.name, nameChunk)));
|
|
1057
1161
|
// Add all results to map
|
|
1058
1162
|
for (const existing of allVersions) {
|
|
1059
1163
|
existingMap.set(`${existing.name}:${existing.version}`, existing);
|
|
@@ -1124,9 +1228,8 @@ export async function transformPackageDistUrls(packageData, repoId, proxyBaseUrl
|
|
|
1124
1228
|
.insert(packages)
|
|
1125
1229
|
.values(pkgData)
|
|
1126
1230
|
.onConflictDoUpdate({
|
|
1127
|
-
target: [packages.name, packages.version],
|
|
1231
|
+
target: [packages.repo_id, packages.name, packages.version],
|
|
1128
1232
|
set: {
|
|
1129
|
-
repo_id: pkgData.repo_id,
|
|
1130
1233
|
dist_url: pkgData.dist_url,
|
|
1131
1234
|
source_dist_url: pkgData.source_dist_url,
|
|
1132
1235
|
dist_reference: pkgData.dist_reference,
|
|
@@ -1195,7 +1298,7 @@ export async function storePackageInDB(db, packageName, version, metadata, repoI
|
|
|
1195
1298
|
const [existing] = await db
|
|
1196
1299
|
.select()
|
|
1197
1300
|
.from(packages)
|
|
1198
|
-
.where(and(eq(packages.name, packageName), eq(packages.version, version)))
|
|
1301
|
+
.where(and(eq(packages.repo_id, repoId), eq(packages.name, packageName), eq(packages.version, version)))
|
|
1199
1302
|
.limit(1);
|
|
1200
1303
|
// Use existing reference or generate simple one (no expensive crypto)
|
|
1201
1304
|
// Most Packagist packages already have dist.reference, so this is rarely needed
|
|
@@ -1229,7 +1332,6 @@ export async function storePackageInDB(db, packageName, version, metadata, repoI
|
|
|
1229
1332
|
await db
|
|
1230
1333
|
.update(packages)
|
|
1231
1334
|
.set({
|
|
1232
|
-
repo_id: repoId, // Update repo_id in case it changed
|
|
1233
1335
|
dist_url: proxyDistUrl,
|
|
1234
1336
|
source_dist_url: sourceDistUrl,
|
|
1235
1337
|
dist_reference: distReference,
|
|
@@ -1240,7 +1342,7 @@ export async function storePackageInDB(db, packageName, version, metadata, repoI
|
|
|
1240
1342
|
released_at: releasedAt,
|
|
1241
1343
|
metadata: packageData.metadata, // Update metadata
|
|
1242
1344
|
})
|
|
1243
|
-
.where(and(eq(packages.name, packageName), eq(packages.version, version)));
|
|
1345
|
+
.where(and(eq(packages.repo_id, repoId), eq(packages.name, packageName), eq(packages.version, version)));
|
|
1244
1346
|
}
|
|
1245
1347
|
else {
|
|
1246
1348
|
await db.insert(packages).values(packageData);
|