@git-stunts/git-cas 1.6.0 → 1.6.2
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/CHANGELOG.md +20 -0
- package/index.d.ts +155 -0
- package/index.js +1 -0
- package/package.json +4 -3
- package/src/domain/schemas/ManifestSchema.d.ts +31 -0
- package/src/domain/schemas/ManifestSchema.js +1 -0
- package/src/domain/services/CasService.d.ts +100 -0
- package/src/domain/services/CasService.js +5 -0
- package/src/domain/value-objects/Chunk.d.ts +16 -0
- package/src/domain/value-objects/Manifest.d.ts +33 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.6.2] — OIDC publishing + JSR docs coverage (2026-02-07)
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- JSDoc comments on all exported TypeScript interfaces (`CryptoPort`, `CodecPort`, `GitPersistencePort`, `CasServiceOptions`, `EncryptionMeta`, `ManifestData`, `ContentAddressableStoreOptions`) to reach 100% JSR symbol documentation coverage.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- npm publish workflow now uses OIDC trusted publishing (no stored token). Upgrades npm to >=11.5.1 at publish time since pnpm does not yet support OIDC natively.
|
|
17
|
+
|
|
18
|
+
## [1.6.1] — JSR quality fixes (2026-02-07)
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- TypeScript declaration files (`.d.ts`) for all three entrypoints and shared value objects, resolving JSR "slow types" scoring penalty.
|
|
22
|
+
- `@ts-self-types` directives in `index.js`, `CasService.js`, and `ManifestSchema.js`.
|
|
23
|
+
- `@fileoverview` module doc to `CasService.js` (required by JSR for module docs scoring).
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- JSR package name corrected to `@git-stunts/git-cas`.
|
|
27
|
+
- JSR publication now excludes tests, docs, CI configs, and other non-distribution files via `jsr.json` exclude list.
|
|
28
|
+
- `index.d.ts` added to `package.json` files array for npm distribution.
|
|
29
|
+
|
|
10
30
|
## [1.6.0] — M4 Compass + M5 Sonar + M6 Cartographer (2026-02-06)
|
|
11
31
|
|
|
12
32
|
### Added
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* Content Addressable Store — Managed blob storage in Git.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import Manifest from "./src/domain/value-objects/Manifest.js";
|
|
7
|
+
import type { EncryptionMeta, ManifestData } from "./src/domain/value-objects/Manifest.js";
|
|
8
|
+
import Chunk from "./src/domain/value-objects/Chunk.js";
|
|
9
|
+
import CasService from "./src/domain/services/CasService.js";
|
|
10
|
+
import type {
|
|
11
|
+
CryptoPort,
|
|
12
|
+
CodecPort,
|
|
13
|
+
GitPersistencePort,
|
|
14
|
+
CasServiceOptions,
|
|
15
|
+
} from "./src/domain/services/CasService.js";
|
|
16
|
+
|
|
17
|
+
export { CasService, Manifest, Chunk };
|
|
18
|
+
export type { EncryptionMeta, ManifestData, CryptoPort, CodecPort, GitPersistencePort, CasServiceOptions };
|
|
19
|
+
|
|
20
|
+
/** Abstract port for cryptographic operations. */
|
|
21
|
+
export declare class CryptoPortBase {
|
|
22
|
+
sha256(buf: Buffer): string | Promise<string>;
|
|
23
|
+
randomBytes(n: number): Buffer;
|
|
24
|
+
encryptBuffer(
|
|
25
|
+
buffer: Buffer,
|
|
26
|
+
key: Buffer,
|
|
27
|
+
): { buf: Buffer; meta: EncryptionMeta } | Promise<{ buf: Buffer; meta: EncryptionMeta }>;
|
|
28
|
+
decryptBuffer(buffer: Buffer, key: Buffer, meta: EncryptionMeta): Buffer | Promise<Buffer>;
|
|
29
|
+
createEncryptionStream(key: Buffer): {
|
|
30
|
+
encrypt: (source: AsyncIterable<Buffer>) => AsyncIterable<Buffer>;
|
|
31
|
+
finalize: () => EncryptionMeta;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Abstract port for persisting data to Git's object database. */
|
|
36
|
+
export declare class GitPersistencePortBase {
|
|
37
|
+
writeBlob(content: Buffer | string): Promise<string>;
|
|
38
|
+
writeTree(entries: string[]): Promise<string>;
|
|
39
|
+
readBlob(oid: string): Promise<Buffer>;
|
|
40
|
+
readTree(
|
|
41
|
+
treeOid: string,
|
|
42
|
+
): Promise<Array<{ mode: string; type: string; oid: string; name: string }>>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Git-backed implementation of the persistence port. */
|
|
46
|
+
export declare class GitPersistenceAdapter extends GitPersistencePortBase {
|
|
47
|
+
constructor(options: { plumbing: unknown; policy?: unknown });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Node.js crypto implementation of CryptoPort. */
|
|
51
|
+
export declare class NodeCryptoAdapter extends CryptoPortBase {
|
|
52
|
+
constructor();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Abstract codec interface for manifest serialization. */
|
|
56
|
+
export declare class CodecPortBase {
|
|
57
|
+
encode(data: object): Buffer | string;
|
|
58
|
+
decode(buffer: Buffer | string): object;
|
|
59
|
+
get extension(): string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** JSON codec for manifest serialization. */
|
|
63
|
+
export declare class JsonCodec extends CodecPortBase {
|
|
64
|
+
constructor();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** CBOR codec for manifest serialization. */
|
|
68
|
+
export declare class CborCodec extends CodecPortBase {
|
|
69
|
+
constructor();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Constructor options for {@link ContentAddressableStore}. */
|
|
73
|
+
export interface ContentAddressableStoreOptions {
|
|
74
|
+
plumbing: unknown;
|
|
75
|
+
chunkSize?: number;
|
|
76
|
+
codec?: CodecPort;
|
|
77
|
+
crypto?: CryptoPort;
|
|
78
|
+
policy?: unknown;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* High-level facade for the Content Addressable Store library.
|
|
83
|
+
*
|
|
84
|
+
* Wraps CasService with lazy initialization, runtime-adaptive crypto
|
|
85
|
+
* selection, and convenience helpers for file I/O.
|
|
86
|
+
*/
|
|
87
|
+
export default class ContentAddressableStore {
|
|
88
|
+
constructor(options: ContentAddressableStoreOptions);
|
|
89
|
+
|
|
90
|
+
get chunkSize(): number;
|
|
91
|
+
|
|
92
|
+
getService(): Promise<CasService>;
|
|
93
|
+
|
|
94
|
+
static createJson(options: {
|
|
95
|
+
plumbing: unknown;
|
|
96
|
+
chunkSize?: number;
|
|
97
|
+
policy?: unknown;
|
|
98
|
+
}): ContentAddressableStore;
|
|
99
|
+
|
|
100
|
+
static createCbor(options: {
|
|
101
|
+
plumbing: unknown;
|
|
102
|
+
chunkSize?: number;
|
|
103
|
+
policy?: unknown;
|
|
104
|
+
}): ContentAddressableStore;
|
|
105
|
+
|
|
106
|
+
encrypt(options: {
|
|
107
|
+
buffer: Buffer;
|
|
108
|
+
key: Buffer;
|
|
109
|
+
}): Promise<{ buf: Buffer; meta: EncryptionMeta }>;
|
|
110
|
+
|
|
111
|
+
decrypt(options: {
|
|
112
|
+
buffer: Buffer;
|
|
113
|
+
key: Buffer;
|
|
114
|
+
meta: EncryptionMeta;
|
|
115
|
+
}): Promise<Buffer>;
|
|
116
|
+
|
|
117
|
+
storeFile(options: {
|
|
118
|
+
filePath: string;
|
|
119
|
+
slug: string;
|
|
120
|
+
filename?: string;
|
|
121
|
+
encryptionKey?: Buffer;
|
|
122
|
+
}): Promise<Manifest>;
|
|
123
|
+
|
|
124
|
+
store(options: {
|
|
125
|
+
source: AsyncIterable<Buffer>;
|
|
126
|
+
slug: string;
|
|
127
|
+
filename: string;
|
|
128
|
+
encryptionKey?: Buffer;
|
|
129
|
+
}): Promise<Manifest>;
|
|
130
|
+
|
|
131
|
+
restoreFile(options: {
|
|
132
|
+
manifest: Manifest;
|
|
133
|
+
encryptionKey?: Buffer;
|
|
134
|
+
outputPath: string;
|
|
135
|
+
}): Promise<{ bytesWritten: number }>;
|
|
136
|
+
|
|
137
|
+
restore(options: {
|
|
138
|
+
manifest: Manifest;
|
|
139
|
+
encryptionKey?: Buffer;
|
|
140
|
+
}): Promise<{ buffer: Buffer; bytesWritten: number }>;
|
|
141
|
+
|
|
142
|
+
createTree(options: { manifest: Manifest }): Promise<string>;
|
|
143
|
+
|
|
144
|
+
verifyIntegrity(manifest: Manifest): Promise<boolean>;
|
|
145
|
+
|
|
146
|
+
readManifest(options: { treeOid: string }): Promise<Manifest>;
|
|
147
|
+
|
|
148
|
+
deleteAsset(options: {
|
|
149
|
+
treeOid: string;
|
|
150
|
+
}): Promise<{ slug: string; chunksOrphaned: number }>;
|
|
151
|
+
|
|
152
|
+
findOrphanedChunks(options: {
|
|
153
|
+
treeOids: string[];
|
|
154
|
+
}): Promise<{ referenced: Set<string>; total: number }>;
|
|
155
|
+
}
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@git-stunts/git-cas",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"description": "Content-addressed storage backed by Git's object database, with optional encryption and pluggable codecs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"git-cas": "
|
|
8
|
+
"git-cas": "bin/git-cas.js"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./index.js",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"index.js",
|
|
17
|
+
"index.d.ts",
|
|
17
18
|
"bin/",
|
|
18
19
|
"src/",
|
|
19
20
|
"README.md",
|
|
@@ -78,4 +79,4 @@
|
|
|
78
79
|
"prettier": "^3.4.2",
|
|
79
80
|
"vitest": "^2.1.8"
|
|
80
81
|
}
|
|
81
|
-
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* Zod schemas for validating CAS manifest and chunk data.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
/** Validates a single chunk entry within a manifest. */
|
|
9
|
+
export declare const ChunkSchema: z.ZodObject<{
|
|
10
|
+
index: z.ZodNumber;
|
|
11
|
+
size: z.ZodNumber;
|
|
12
|
+
digest: z.ZodString;
|
|
13
|
+
blob: z.ZodString;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
/** Validates the encryption metadata attached to an encrypted manifest. */
|
|
17
|
+
export declare const EncryptionSchema: z.ZodObject<{
|
|
18
|
+
algorithm: z.ZodString;
|
|
19
|
+
nonce: z.ZodString;
|
|
20
|
+
tag: z.ZodString;
|
|
21
|
+
encrypted: z.ZodDefault<z.ZodBoolean>;
|
|
22
|
+
}>;
|
|
23
|
+
|
|
24
|
+
/** Validates a complete file manifest. */
|
|
25
|
+
export declare const ManifestSchema: z.ZodObject<{
|
|
26
|
+
slug: z.ZodString;
|
|
27
|
+
filename: z.ZodString;
|
|
28
|
+
size: z.ZodNumber;
|
|
29
|
+
chunks: z.ZodArray<typeof ChunkSchema>;
|
|
30
|
+
encryption: z.ZodOptional<typeof EncryptionSchema>;
|
|
31
|
+
}>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* Domain service for Content Addressable Storage operations.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { EventEmitter } from "node:events";
|
|
7
|
+
import Manifest from "../value-objects/Manifest.js";
|
|
8
|
+
import type { EncryptionMeta } from "../value-objects/Manifest.js";
|
|
9
|
+
|
|
10
|
+
/** Port interface for cryptographic operations (hashing, encryption, random bytes). */
|
|
11
|
+
export interface CryptoPort {
|
|
12
|
+
sha256(buf: Buffer): string | Promise<string>;
|
|
13
|
+
randomBytes(n: number): Buffer;
|
|
14
|
+
encryptBuffer(
|
|
15
|
+
buffer: Buffer,
|
|
16
|
+
key: Buffer,
|
|
17
|
+
): { buf: Buffer; meta: EncryptionMeta } | Promise<{ buf: Buffer; meta: EncryptionMeta }>;
|
|
18
|
+
decryptBuffer(buffer: Buffer, key: Buffer, meta: EncryptionMeta): Buffer | Promise<Buffer>;
|
|
19
|
+
createEncryptionStream(key: Buffer): {
|
|
20
|
+
encrypt: (source: AsyncIterable<Buffer>) => AsyncIterable<Buffer>;
|
|
21
|
+
finalize: () => EncryptionMeta;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Port interface for encoding and decoding manifest data. */
|
|
26
|
+
export interface CodecPort {
|
|
27
|
+
encode(data: object): Buffer | string;
|
|
28
|
+
decode(buffer: Buffer | string): object;
|
|
29
|
+
get extension(): string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Port interface for persisting data to Git's object database. */
|
|
33
|
+
export interface GitPersistencePort {
|
|
34
|
+
writeBlob(content: Buffer | string): Promise<string>;
|
|
35
|
+
writeTree(entries: string[]): Promise<string>;
|
|
36
|
+
readBlob(oid: string): Promise<Buffer>;
|
|
37
|
+
readTree(
|
|
38
|
+
treeOid: string,
|
|
39
|
+
): Promise<Array<{ mode: string; type: string; oid: string; name: string }>>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Constructor options for {@link CasService}. */
|
|
43
|
+
export interface CasServiceOptions {
|
|
44
|
+
persistence: GitPersistencePort;
|
|
45
|
+
codec: CodecPort;
|
|
46
|
+
crypto: CryptoPort;
|
|
47
|
+
chunkSize?: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Domain service for Content Addressable Storage operations.
|
|
52
|
+
*
|
|
53
|
+
* Provides chunking, encryption, and integrity verification for storing
|
|
54
|
+
* arbitrary data in Git's object database.
|
|
55
|
+
*/
|
|
56
|
+
export default class CasService extends EventEmitter {
|
|
57
|
+
readonly persistence: GitPersistencePort;
|
|
58
|
+
readonly codec: CodecPort;
|
|
59
|
+
readonly crypto: CryptoPort;
|
|
60
|
+
readonly chunkSize: number;
|
|
61
|
+
|
|
62
|
+
constructor(options: CasServiceOptions);
|
|
63
|
+
|
|
64
|
+
encrypt(options: {
|
|
65
|
+
buffer: Buffer;
|
|
66
|
+
key: Buffer;
|
|
67
|
+
}): Promise<{ buf: Buffer; meta: EncryptionMeta }>;
|
|
68
|
+
|
|
69
|
+
decrypt(options: {
|
|
70
|
+
buffer: Buffer;
|
|
71
|
+
key: Buffer;
|
|
72
|
+
meta: EncryptionMeta;
|
|
73
|
+
}): Promise<Buffer>;
|
|
74
|
+
|
|
75
|
+
store(options: {
|
|
76
|
+
source: AsyncIterable<Buffer>;
|
|
77
|
+
slug: string;
|
|
78
|
+
filename: string;
|
|
79
|
+
encryptionKey?: Buffer;
|
|
80
|
+
}): Promise<Manifest>;
|
|
81
|
+
|
|
82
|
+
createTree(options: { manifest: Manifest }): Promise<string>;
|
|
83
|
+
|
|
84
|
+
restore(options: {
|
|
85
|
+
manifest: Manifest;
|
|
86
|
+
encryptionKey?: Buffer;
|
|
87
|
+
}): Promise<{ buffer: Buffer; bytesWritten: number }>;
|
|
88
|
+
|
|
89
|
+
readManifest(options: { treeOid: string }): Promise<Manifest>;
|
|
90
|
+
|
|
91
|
+
deleteAsset(options: {
|
|
92
|
+
treeOid: string;
|
|
93
|
+
}): Promise<{ slug: string; chunksOrphaned: number }>;
|
|
94
|
+
|
|
95
|
+
findOrphanedChunks(options: {
|
|
96
|
+
treeOids: string[];
|
|
97
|
+
}): Promise<{ referenced: Set<string>; total: number }>;
|
|
98
|
+
|
|
99
|
+
verifyIntegrity(manifest: Manifest): Promise<boolean>;
|
|
100
|
+
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/* @ts-self-types="./CasService.d.ts" */
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Domain service for Content Addressable Storage operations.
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
1
6
|
import { EventEmitter } from 'node:events';
|
|
2
7
|
import Manifest from '../value-objects/Manifest.js';
|
|
3
8
|
import CasError from '../errors/CasError.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Immutable value object representing a single content chunk.
|
|
3
|
+
*/
|
|
4
|
+
export default class Chunk {
|
|
5
|
+
readonly index: number;
|
|
6
|
+
readonly size: number;
|
|
7
|
+
readonly digest: string;
|
|
8
|
+
readonly blob: string;
|
|
9
|
+
|
|
10
|
+
constructor(data: {
|
|
11
|
+
index: number;
|
|
12
|
+
size: number;
|
|
13
|
+
digest: string;
|
|
14
|
+
blob: string;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Chunk from "./Chunk.js";
|
|
2
|
+
|
|
3
|
+
/** AES-256-GCM encryption metadata attached to an encrypted manifest. */
|
|
4
|
+
export interface EncryptionMeta {
|
|
5
|
+
algorithm: string;
|
|
6
|
+
nonce: string;
|
|
7
|
+
tag: string;
|
|
8
|
+
encrypted: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Raw manifest data accepted by the {@link Manifest} constructor. */
|
|
12
|
+
export interface ManifestData {
|
|
13
|
+
slug: string;
|
|
14
|
+
filename: string;
|
|
15
|
+
size: number;
|
|
16
|
+
chunks: Array<{ index: number; size: number; digest: string; blob: string }>;
|
|
17
|
+
encryption?: EncryptionMeta;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Immutable value object representing a file manifest.
|
|
22
|
+
*/
|
|
23
|
+
export default class Manifest {
|
|
24
|
+
readonly slug: string;
|
|
25
|
+
readonly filename: string;
|
|
26
|
+
readonly size: number;
|
|
27
|
+
readonly chunks: readonly Chunk[];
|
|
28
|
+
readonly encryption?: EncryptionMeta;
|
|
29
|
+
|
|
30
|
+
constructor(data: ManifestData);
|
|
31
|
+
|
|
32
|
+
toJSON(): ManifestData;
|
|
33
|
+
}
|