@push.rocks/smartregistry 1.1.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.
Files changed (52) hide show
  1. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  2. package/dist_ts/00_commitinfo_data.js +9 -0
  3. package/dist_ts/classes.smartregistry.d.ts +45 -0
  4. package/dist_ts/classes.smartregistry.js +113 -0
  5. package/dist_ts/core/classes.authmanager.d.ts +108 -0
  6. package/dist_ts/core/classes.authmanager.js +315 -0
  7. package/dist_ts/core/classes.baseregistry.d.ts +28 -0
  8. package/dist_ts/core/classes.baseregistry.js +6 -0
  9. package/dist_ts/core/classes.registrystorage.d.ts +109 -0
  10. package/dist_ts/core/classes.registrystorage.js +226 -0
  11. package/dist_ts/core/index.d.ts +7 -0
  12. package/dist_ts/core/index.js +10 -0
  13. package/dist_ts/core/interfaces.core.d.ts +142 -0
  14. package/dist_ts/core/interfaces.core.js +5 -0
  15. package/dist_ts/index.d.ts +8 -0
  16. package/dist_ts/index.js +13 -0
  17. package/dist_ts/npm/classes.npmregistry.d.ts +36 -0
  18. package/dist_ts/npm/classes.npmregistry.js +717 -0
  19. package/dist_ts/npm/index.d.ts +5 -0
  20. package/dist_ts/npm/index.js +6 -0
  21. package/dist_ts/npm/interfaces.npm.d.ts +245 -0
  22. package/dist_ts/npm/interfaces.npm.js +6 -0
  23. package/dist_ts/oci/classes.ociregistry.d.ts +43 -0
  24. package/dist_ts/oci/classes.ociregistry.js +565 -0
  25. package/dist_ts/oci/index.d.ts +5 -0
  26. package/dist_ts/oci/index.js +6 -0
  27. package/dist_ts/oci/interfaces.oci.d.ts +103 -0
  28. package/dist_ts/oci/interfaces.oci.js +5 -0
  29. package/dist_ts/paths.d.ts +1 -0
  30. package/dist_ts/paths.js +3 -0
  31. package/dist_ts/plugins.d.ts +6 -0
  32. package/dist_ts/plugins.js +9 -0
  33. package/npmextra.json +18 -0
  34. package/package.json +49 -0
  35. package/readme.hints.md +3 -0
  36. package/readme.md +486 -0
  37. package/ts/00_commitinfo_data.ts +8 -0
  38. package/ts/classes.smartregistry.ts +129 -0
  39. package/ts/core/classes.authmanager.ts +388 -0
  40. package/ts/core/classes.baseregistry.ts +36 -0
  41. package/ts/core/classes.registrystorage.ts +270 -0
  42. package/ts/core/index.ts +11 -0
  43. package/ts/core/interfaces.core.ts +159 -0
  44. package/ts/index.ts +16 -0
  45. package/ts/npm/classes.npmregistry.ts +890 -0
  46. package/ts/npm/index.ts +6 -0
  47. package/ts/npm/interfaces.npm.ts +263 -0
  48. package/ts/oci/classes.ociregistry.ts +734 -0
  49. package/ts/oci/index.ts +6 -0
  50. package/ts/oci/interfaces.oci.ts +101 -0
  51. package/ts/paths.ts +5 -0
  52. package/ts/plugins.ts +11 -0
@@ -0,0 +1,270 @@
1
+ import * as plugins from '../plugins.js';
2
+ import type { IStorageConfig, IStorageBackend } from './interfaces.core.js';
3
+
4
+ /**
5
+ * Storage abstraction layer for registry
6
+ * Provides a unified interface over SmartBucket
7
+ */
8
+ export class RegistryStorage implements IStorageBackend {
9
+ private smartBucket: plugins.smartbucket.SmartBucket;
10
+ private bucket: plugins.smartbucket.Bucket;
11
+ private bucketName: string;
12
+
13
+ constructor(private config: IStorageConfig) {
14
+ this.bucketName = config.bucketName;
15
+ }
16
+
17
+ /**
18
+ * Initialize the storage backend
19
+ */
20
+ public async init(): Promise<void> {
21
+ this.smartBucket = new plugins.smartbucket.SmartBucket({
22
+ accessKey: this.config.accessKey,
23
+ accessSecret: this.config.accessSecret,
24
+ endpoint: this.config.endpoint,
25
+ port: this.config.port || 443,
26
+ useSsl: this.config.useSsl !== false,
27
+ region: this.config.region || 'us-east-1',
28
+ });
29
+
30
+ // Ensure bucket exists
31
+ await this.smartBucket.createBucket(this.bucketName).catch(() => {
32
+ // Bucket may already exist
33
+ });
34
+
35
+ this.bucket = await this.smartBucket.getBucketByName(this.bucketName);
36
+ }
37
+
38
+ /**
39
+ * Get an object from storage
40
+ */
41
+ public async getObject(key: string): Promise<Buffer | null> {
42
+ try {
43
+ return await this.bucket.fastGet({ path: key });
44
+ } catch (error) {
45
+ return null;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Store an object
51
+ */
52
+ public async putObject(
53
+ key: string,
54
+ data: Buffer,
55
+ metadata?: Record<string, string>
56
+ ): Promise<void> {
57
+ // Note: SmartBucket doesn't support metadata yet
58
+ await this.bucket.fastPut({
59
+ path: key,
60
+ contents: data,
61
+ overwrite: true, // Always overwrite existing objects
62
+ });
63
+ }
64
+
65
+ /**
66
+ * Delete an object
67
+ */
68
+ public async deleteObject(key: string): Promise<void> {
69
+ await this.bucket.fastRemove({ path: key });
70
+ }
71
+
72
+ /**
73
+ * List objects with a prefix (recursively)
74
+ */
75
+ public async listObjects(prefix: string): Promise<string[]> {
76
+ const paths: string[] = [];
77
+ for await (const path of this.bucket.listAllObjects(prefix)) {
78
+ paths.push(path);
79
+ }
80
+ return paths;
81
+ }
82
+
83
+ /**
84
+ * Check if an object exists
85
+ */
86
+ public async objectExists(key: string): Promise<boolean> {
87
+ return await this.bucket.fastExists({ path: key });
88
+ }
89
+
90
+ /**
91
+ * Get object metadata
92
+ * Note: SmartBucket may not support metadata retrieval, returning empty object
93
+ */
94
+ public async getMetadata(key: string): Promise<Record<string, string> | null> {
95
+ // SmartBucket doesn't expose metadata retrieval directly
96
+ // This is a limitation we'll document
97
+ const exists = await this.objectExists(key);
98
+ return exists ? {} : null;
99
+ }
100
+
101
+ // ========================================================================
102
+ // OCI-SPECIFIC HELPERS
103
+ // ========================================================================
104
+
105
+ /**
106
+ * Get OCI blob by digest
107
+ */
108
+ public async getOciBlob(digest: string): Promise<Buffer | null> {
109
+ const path = this.getOciBlobPath(digest);
110
+ return this.getObject(path);
111
+ }
112
+
113
+ /**
114
+ * Store OCI blob
115
+ */
116
+ public async putOciBlob(digest: string, data: Buffer): Promise<void> {
117
+ const path = this.getOciBlobPath(digest);
118
+ return this.putObject(path, data);
119
+ }
120
+
121
+ /**
122
+ * Check if OCI blob exists
123
+ */
124
+ public async ociBlobExists(digest: string): Promise<boolean> {
125
+ const path = this.getOciBlobPath(digest);
126
+ return this.objectExists(path);
127
+ }
128
+
129
+ /**
130
+ * Delete OCI blob
131
+ */
132
+ public async deleteOciBlob(digest: string): Promise<void> {
133
+ const path = this.getOciBlobPath(digest);
134
+ return this.deleteObject(path);
135
+ }
136
+
137
+ /**
138
+ * Get OCI manifest
139
+ */
140
+ public async getOciManifest(repository: string, digest: string): Promise<Buffer | null> {
141
+ const path = this.getOciManifestPath(repository, digest);
142
+ return this.getObject(path);
143
+ }
144
+
145
+ /**
146
+ * Store OCI manifest
147
+ */
148
+ public async putOciManifest(
149
+ repository: string,
150
+ digest: string,
151
+ data: Buffer,
152
+ contentType: string
153
+ ): Promise<void> {
154
+ const path = this.getOciManifestPath(repository, digest);
155
+ return this.putObject(path, data, { 'Content-Type': contentType });
156
+ }
157
+
158
+ /**
159
+ * Check if OCI manifest exists
160
+ */
161
+ public async ociManifestExists(repository: string, digest: string): Promise<boolean> {
162
+ const path = this.getOciManifestPath(repository, digest);
163
+ return this.objectExists(path);
164
+ }
165
+
166
+ /**
167
+ * Delete OCI manifest
168
+ */
169
+ public async deleteOciManifest(repository: string, digest: string): Promise<void> {
170
+ const path = this.getOciManifestPath(repository, digest);
171
+ return this.deleteObject(path);
172
+ }
173
+
174
+ // ========================================================================
175
+ // NPM-SPECIFIC HELPERS
176
+ // ========================================================================
177
+
178
+ /**
179
+ * Get NPM packument (package document)
180
+ */
181
+ public async getNpmPackument(packageName: string): Promise<any | null> {
182
+ const path = this.getNpmPackumentPath(packageName);
183
+ const data = await this.getObject(path);
184
+ return data ? JSON.parse(data.toString('utf-8')) : null;
185
+ }
186
+
187
+ /**
188
+ * Store NPM packument
189
+ */
190
+ public async putNpmPackument(packageName: string, packument: any): Promise<void> {
191
+ const path = this.getNpmPackumentPath(packageName);
192
+ const data = Buffer.from(JSON.stringify(packument, null, 2), 'utf-8');
193
+ return this.putObject(path, data, { 'Content-Type': 'application/json' });
194
+ }
195
+
196
+ /**
197
+ * Check if NPM packument exists
198
+ */
199
+ public async npmPackumentExists(packageName: string): Promise<boolean> {
200
+ const path = this.getNpmPackumentPath(packageName);
201
+ return this.objectExists(path);
202
+ }
203
+
204
+ /**
205
+ * Delete NPM packument
206
+ */
207
+ public async deleteNpmPackument(packageName: string): Promise<void> {
208
+ const path = this.getNpmPackumentPath(packageName);
209
+ return this.deleteObject(path);
210
+ }
211
+
212
+ /**
213
+ * Get NPM tarball
214
+ */
215
+ public async getNpmTarball(packageName: string, version: string): Promise<Buffer | null> {
216
+ const path = this.getNpmTarballPath(packageName, version);
217
+ return this.getObject(path);
218
+ }
219
+
220
+ /**
221
+ * Store NPM tarball
222
+ */
223
+ public async putNpmTarball(
224
+ packageName: string,
225
+ version: string,
226
+ tarball: Buffer
227
+ ): Promise<void> {
228
+ const path = this.getNpmTarballPath(packageName, version);
229
+ return this.putObject(path, tarball, { 'Content-Type': 'application/octet-stream' });
230
+ }
231
+
232
+ /**
233
+ * Check if NPM tarball exists
234
+ */
235
+ public async npmTarballExists(packageName: string, version: string): Promise<boolean> {
236
+ const path = this.getNpmTarballPath(packageName, version);
237
+ return this.objectExists(path);
238
+ }
239
+
240
+ /**
241
+ * Delete NPM tarball
242
+ */
243
+ public async deleteNpmTarball(packageName: string, version: string): Promise<void> {
244
+ const path = this.getNpmTarballPath(packageName, version);
245
+ return this.deleteObject(path);
246
+ }
247
+
248
+ // ========================================================================
249
+ // PATH HELPERS
250
+ // ========================================================================
251
+
252
+ private getOciBlobPath(digest: string): string {
253
+ const hash = digest.split(':')[1];
254
+ return `oci/blobs/sha256/${hash}`;
255
+ }
256
+
257
+ private getOciManifestPath(repository: string, digest: string): string {
258
+ const hash = digest.split(':')[1];
259
+ return `oci/manifests/${repository}/${hash}`;
260
+ }
261
+
262
+ private getNpmPackumentPath(packageName: string): string {
263
+ return `npm/packages/${packageName}/index.json`;
264
+ }
265
+
266
+ private getNpmTarballPath(packageName: string, version: string): string {
267
+ const safeName = packageName.replace('@', '').replace('/', '-');
268
+ return `npm/packages/${packageName}/${safeName}-${version}.tgz`;
269
+ }
270
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Core registry infrastructure exports
3
+ */
4
+
5
+ // Interfaces
6
+ export * from './interfaces.core.js';
7
+
8
+ // Classes
9
+ export { BaseRegistry } from './classes.baseregistry.js';
10
+ export { RegistryStorage } from './classes.registrystorage.js';
11
+ export { AuthManager } from './classes.authmanager.js';
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Core interfaces for the composable registry system
3
+ */
4
+
5
+ /**
6
+ * Registry protocol types
7
+ */
8
+ export type TRegistryProtocol = 'oci' | 'npm';
9
+
10
+ /**
11
+ * Unified action types across protocols
12
+ */
13
+ export type TRegistryAction = 'pull' | 'push' | 'delete' | 'read' | 'write' | '*';
14
+
15
+ /**
16
+ * Unified authentication token
17
+ */
18
+ export interface IAuthToken {
19
+ /** Token type/protocol */
20
+ type: TRegistryProtocol;
21
+ /** User ID */
22
+ userId: string;
23
+ /** Permission scopes (e.g., "npm:package:foo:write", "oci:repository:bar:push") */
24
+ scopes: string[];
25
+ /** Token expiration */
26
+ expiresAt?: Date;
27
+ /** Read-only flag */
28
+ readonly?: boolean;
29
+ /** Additional metadata */
30
+ metadata?: Record<string, any>;
31
+ }
32
+
33
+ /**
34
+ * Credentials for authentication
35
+ */
36
+ export interface ICredentials {
37
+ username: string;
38
+ password: string;
39
+ }
40
+
41
+ /**
42
+ * Storage backend configuration
43
+ */
44
+ export interface IStorageConfig {
45
+ accessKey: string;
46
+ accessSecret: string;
47
+ endpoint: string;
48
+ port?: number;
49
+ useSsl?: boolean;
50
+ region?: string;
51
+ bucketName: string;
52
+ }
53
+
54
+ /**
55
+ * Authentication configuration
56
+ */
57
+ export interface IAuthConfig {
58
+ /** JWT secret for OCI tokens */
59
+ jwtSecret: string;
60
+ /** Token storage type */
61
+ tokenStore: 'memory' | 'redis' | 'database';
62
+ /** NPM token settings */
63
+ npmTokens: {
64
+ enabled: boolean;
65
+ defaultReadonly?: boolean;
66
+ };
67
+ /** OCI token settings */
68
+ ociTokens: {
69
+ enabled: boolean;
70
+ realm: string;
71
+ service: string;
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Protocol-specific configuration
77
+ */
78
+ export interface IProtocolConfig {
79
+ enabled: boolean;
80
+ basePath: string;
81
+ features?: Record<string, boolean>;
82
+ }
83
+
84
+ /**
85
+ * Main registry configuration
86
+ */
87
+ export interface IRegistryConfig {
88
+ storage: IStorageConfig;
89
+ auth: IAuthConfig;
90
+ oci?: IProtocolConfig;
91
+ npm?: IProtocolConfig;
92
+ }
93
+
94
+ /**
95
+ * Storage backend interface
96
+ */
97
+ export interface IStorageBackend {
98
+ /**
99
+ * Get an object from storage
100
+ */
101
+ getObject(key: string): Promise<Buffer | null>;
102
+
103
+ /**
104
+ * Store an object
105
+ */
106
+ putObject(key: string, data: Buffer, metadata?: Record<string, string>): Promise<void>;
107
+
108
+ /**
109
+ * Delete an object
110
+ */
111
+ deleteObject(key: string): Promise<void>;
112
+
113
+ /**
114
+ * List objects with a prefix
115
+ */
116
+ listObjects(prefix: string): Promise<string[]>;
117
+
118
+ /**
119
+ * Check if an object exists
120
+ */
121
+ objectExists(key: string): Promise<boolean>;
122
+
123
+ /**
124
+ * Get object metadata
125
+ */
126
+ getMetadata(key: string): Promise<Record<string, string> | null>;
127
+ }
128
+
129
+ /**
130
+ * Error response structure
131
+ */
132
+ export interface IRegistryError {
133
+ errors: Array<{
134
+ code: string;
135
+ message: string;
136
+ detail?: any;
137
+ }>;
138
+ }
139
+
140
+ /**
141
+ * Base request context
142
+ */
143
+ export interface IRequestContext {
144
+ method: string;
145
+ path: string;
146
+ headers: Record<string, string>;
147
+ query: Record<string, string>;
148
+ body?: any;
149
+ token?: string;
150
+ }
151
+
152
+ /**
153
+ * Base response structure
154
+ */
155
+ export interface IResponse {
156
+ status: number;
157
+ headers: Record<string, string>;
158
+ body?: any;
159
+ }
package/ts/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @push.rocks/smartregistry
3
+ * Composable registry supporting OCI and NPM protocols
4
+ */
5
+
6
+ // Main orchestrator
7
+ export { SmartRegistry } from './classes.smartregistry.js';
8
+
9
+ // Core infrastructure
10
+ export * from './core/index.js';
11
+
12
+ // OCI Registry
13
+ export * from './oci/index.js';
14
+
15
+ // NPM Registry
16
+ export * from './npm/index.js';