@pierre/storage 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/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # @pierre/storage
2
+
3
+ Pierre Git Storage SDK for TypeScript/JavaScript applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @pierre/storage
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Setup
14
+
15
+ ```typescript
16
+ import { GitStorage } from '@pierre/storage';
17
+
18
+ // Initialize the client with your name and key
19
+ const store = new GitStorage({
20
+ name: 'your-name', // e.g., 'v0'
21
+ key: 'your-key', // Your API key
22
+ });
23
+ ```
24
+
25
+ ### Creating a Repository
26
+
27
+ ```typescript
28
+ // Create a new repository with auto-generated ID
29
+ const repo = await store.createRepo();
30
+ console.log(repo.id); // e.g., '123e4567-e89b-12d3-a456-426614174000'
31
+
32
+ // Create a repository with custom ID
33
+ const customRepo = await store.createRepo({ id: 'my-custom-repo' });
34
+ console.log(customRepo.id); // 'my-custom-repo'
35
+ ```
36
+
37
+ ### Finding a Repository
38
+
39
+ ```typescript
40
+ const foundRepo = await store.findOne({ id: 'repo-id' });
41
+ if (foundRepo) {
42
+ const url = await foundRepo.getRemoteURL();
43
+ console.log(`Repository URL: ${url}`);
44
+ }
45
+ ```
46
+
47
+ ### Getting Remote URLs
48
+
49
+ The SDK generates secure URLs with JWT authentication for Git operations:
50
+
51
+ ```typescript
52
+ // Get URL with default permissions (git:write, git:read) and 1-year TTL
53
+ const url = await repo.getRemoteURL();
54
+ // Returns: https://t:JWT@your-name.git.storage/repo-id.git
55
+
56
+ // Configure the Git remote
57
+ console.log(`Run: git remote add origin ${url}`);
58
+
59
+ // Get URL with custom permissions and TTL
60
+ const readOnlyUrl = await repo.getRemoteURL({
61
+ permissions: ['git:read'], // Read-only access
62
+ ttl: 3600, // 1 hour in seconds
63
+ });
64
+
65
+ // Available permissions:
66
+ // - 'git:read' - Read access to Git repository
67
+ // - 'git:write' - Write access to Git repository
68
+ // - 'repo:write' - Create a repository
69
+ ```
70
+
71
+ ## API Reference
72
+
73
+ ### GitStorage
74
+
75
+ ```typescript
76
+ class GitStorage {
77
+ constructor(options: GitStorageOptions);
78
+ async createRepo(options?: CreateRepoOptions): Promise<Repo>;
79
+ async findOne(options: FindOneOptions): Promise<Repo | null>;
80
+ getConfig(): GitStorageOptions;
81
+ }
82
+ ```
83
+
84
+ ### Interfaces
85
+
86
+ ```typescript
87
+ interface GitStorageOptions {
88
+ name: string; // Your identifier
89
+ key: string; // Your API key
90
+ }
91
+
92
+ interface CreateRepoOptions {
93
+ id?: string; // Optional custom repository ID
94
+ }
95
+
96
+ interface FindOneOptions {
97
+ id: string; // Repository ID to find
98
+ }
99
+
100
+ interface Repo {
101
+ id: string;
102
+ getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
103
+ }
104
+
105
+ interface GetRemoteURLOptions {
106
+ permissions?: ('git:write' | 'git:read' | 'repo:write')[];
107
+ ttl?: number; // Time to live in seconds (default: 31536000 = 1 year)
108
+ }
109
+ ```
110
+
111
+ ## Authentication
112
+
113
+ The SDK uses JWT (JSON Web Tokens) for authentication. When you call `getRemoteURL()`, it:
114
+
115
+ 1. Creates a JWT with your name, repository ID, and requested permissions
116
+ 2. Signs it with your key
117
+ 3. Embeds it in the Git remote URL as the password
118
+
119
+ The generated URLs are compatible with standard Git clients and include all necessary
120
+ authentication.
121
+
122
+ ## Error Handling
123
+
124
+ The SDK validates inputs and provides helpful error messages:
125
+
126
+ ```typescript
127
+ try {
128
+ const store = new GitStorage({ name: '', key: 'key' });
129
+ } catch (error) {
130
+ // Error: GitStorage name must be a non-empty string.
131
+ }
132
+
133
+ try {
134
+ const store = new GitStorage({ name: 'v0', key: '' });
135
+ } catch (error) {
136
+ // Error: GitStorage key must be a non-empty string.
137
+ }
138
+ ```
139
+
140
+ ## Development
141
+
142
+ This package is part of the Pierre monorepo. To work on it locally:
143
+
144
+ ```bash
145
+ # Install dependencies
146
+ pnpm install
147
+
148
+ # Build the package
149
+ moon git-storage-sdk:build
150
+
151
+ # Run tests
152
+ moon git-storage-sdk:test
153
+
154
+ # Run in watch mode
155
+ moon git-storage-sdk:dev
156
+
157
+ # Format code
158
+ moon git-storage-sdk:format-write
159
+ ```
160
+
161
+ ## License
162
+
163
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,110 @@
1
+ 'use strict';
2
+
3
+ var jose = require('jose');
4
+
5
+ // src/index.ts
6
+ var API_BASE_URL = "https://api.git.storage";
7
+ var STORAGE_BASE_URL = "git.storage";
8
+ var GitStorage = class {
9
+ options;
10
+ constructor(options) {
11
+ if (!options || options.name === void 0 || options.key === void 0 || options.name === null || options.key === null) {
12
+ throw new Error(
13
+ "GitStorage requires a name and key. Please check your configuration and try again."
14
+ );
15
+ }
16
+ if (typeof options.name !== "string" || options.name.trim() === "") {
17
+ throw new Error("GitStorage name must be a non-empty string.");
18
+ }
19
+ if (typeof options.key !== "string" || options.key.trim() === "") {
20
+ throw new Error("GitStorage key must be a non-empty string.");
21
+ }
22
+ this.options = {
23
+ key: options.key,
24
+ name: options.name
25
+ };
26
+ }
27
+ /**
28
+ * Create a new repository
29
+ * @returns The created repository
30
+ */
31
+ async createRepo(options) {
32
+ const repoId = options?.id || crypto.randomUUID();
33
+ const jwt = await this.generateJWT(repoId, {
34
+ permissions: ["repo:write"],
35
+ ttl: 1 * 60 * 60
36
+ // 1hr in seconds
37
+ });
38
+ const response = await fetch(`${API_BASE_URL}/api/v1/repos`, {
39
+ method: "POST",
40
+ headers: {
41
+ Authorization: `Bearer ${jwt}`
42
+ }
43
+ });
44
+ if (!response.ok) {
45
+ throw new Error(`Failed to create repository: ${response.statusText}`);
46
+ }
47
+ return {
48
+ id: repoId,
49
+ getRemoteURL: async (urlOptions) => {
50
+ const url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${repoId}.git`);
51
+ url.username = `t`;
52
+ url.password = await this.generateJWT(repoId, urlOptions);
53
+ return url.toString();
54
+ }
55
+ };
56
+ }
57
+ /**
58
+ * Find a repository by ID
59
+ * @param options The search options
60
+ * @returns The found repository
61
+ */
62
+ async findOne(options) {
63
+ return {
64
+ id: options.id,
65
+ getRemoteURL: async (urlOptions) => {
66
+ const url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${options.id}.git`);
67
+ url.username = `t`;
68
+ url.password = await this.generateJWT(options.id, urlOptions);
69
+ return url.toString();
70
+ }
71
+ };
72
+ }
73
+ /**
74
+ * Get the current configuration
75
+ * @returns The client configuration
76
+ */
77
+ getConfig() {
78
+ return { ...this.options };
79
+ }
80
+ /**
81
+ * Generate a JWT token for git storage URL authentication
82
+ * @private
83
+ */
84
+ async generateJWT(repoId, options) {
85
+ const permissions = options?.permissions || ["git:write", "git:read"];
86
+ const ttl = options?.ttl || 365 * 24 * 60 * 60;
87
+ const now = Math.floor(Date.now() / 1e3);
88
+ const payload = {
89
+ aud: "git.pierre.co",
90
+ // todo this should be updated to git.storage
91
+ iss: this.options.name,
92
+ sub: "@pierre/storage",
93
+ repo: repoId,
94
+ scopes: permissions,
95
+ iat: now,
96
+ exp: now + ttl
97
+ };
98
+ const key = await jose.importPKCS8(this.options.key, "ES256");
99
+ const jwt = await new jose.SignJWT(payload).setProtectedHeader({ alg: "ES256", typ: "JWT" }).sign(key);
100
+ return jwt;
101
+ }
102
+ };
103
+ function createClient(options) {
104
+ return new GitStorage(options);
105
+ }
106
+
107
+ exports.GitStorage = GitStorage;
108
+ exports.createClient = createClient;
109
+ //# sourceMappingURL=index.cjs.map
110
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["importPKCS8","SignJWT"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Pierre Git Storage SDK\n *\n * A TypeScript SDK for interacting with Pierre's git storage system\n */\n\nimport { importPKCS8, SignJWT } from 'jose';\n\n/**\n * Type definitions for Pierre Git Storage SDK\n */\n\nexport interface GitStorageOptions {\n\tkey: string;\n\tname: string;\n}\n\nexport interface GetRemoteURLOptions {\n\tpermissions?: ('git:write' | 'git:read' | 'repo:write')[];\n\tttl?: number;\n}\n\nexport interface Repo {\n\tid: string;\n\tgetRemoteURL(options?: GetRemoteURLOptions): Promise<string>;\n}\n\nexport interface FindOneOptions {\n\tid: string;\n}\n\nexport interface CreateRepoOptions {\n\tid?: string;\n}\n\nexport interface CreateRepoResponse {\n\trepo_id: string;\n\turl: string;\n}\n\n/**\n * Git Storage API\n */\ndeclare const __API_BASE_URL__: string;\ndeclare const __STORAGE_BASE_URL__: string;\n\nconst API_BASE_URL = __API_BASE_URL__;\nconst STORAGE_BASE_URL = __STORAGE_BASE_URL__;\n\nexport class GitStorage {\n\tprivate options: GitStorageOptions;\n\n\tconstructor(options: GitStorageOptions) {\n\t\tif (\n\t\t\t!options ||\n\t\t\toptions.name === undefined ||\n\t\t\toptions.key === undefined ||\n\t\t\toptions.name === null ||\n\t\t\toptions.key === null\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t'GitStorage requires a name and key. Please check your configuration and try again.',\n\t\t\t);\n\t\t}\n\n\t\tif (typeof options.name !== 'string' || options.name.trim() === '') {\n\t\t\tthrow new Error('GitStorage name must be a non-empty string.');\n\t\t}\n\n\t\tif (typeof options.key !== 'string' || options.key.trim() === '') {\n\t\t\tthrow new Error('GitStorage key must be a non-empty string.');\n\t\t}\n\n\t\tthis.options = {\n\t\t\tkey: options.key,\n\t\t\tname: options.name,\n\t\t};\n\t}\n\n\t/**\n\t * Create a new repository\n\t * @returns The created repository\n\t */\n\tasync createRepo(options?: CreateRepoOptions): Promise<Repo> {\n\t\tconst repoId = options?.id || crypto.randomUUID();\n\n\t\tconst jwt = await this.generateJWT(repoId, {\n\t\t\tpermissions: ['repo:write'],\n\t\t\tttl: 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst response = await fetch(`${API_BASE_URL}/api/v1/repos`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${jwt}`,\n\t\t\t},\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Failed to create repository: ${response.statusText}`);\n\t\t}\n\n\t\treturn {\n\t\t\tid: repoId,\n\t\t\tgetRemoteURL: async (urlOptions?: GetRemoteURLOptions): Promise<string> => {\n\t\t\t\tconst url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${repoId}.git`);\n\t\t\t\turl.username = `t`;\n\t\t\t\turl.password = await this.generateJWT(repoId, urlOptions);\n\t\t\t\treturn url.toString();\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Find a repository by ID\n\t * @param options The search options\n\t * @returns The found repository\n\t */\n\tasync findOne(options: FindOneOptions): Promise<Repo | null> {\n\t\treturn {\n\t\t\tid: options.id,\n\t\t\tgetRemoteURL: async (urlOptions?: GetRemoteURLOptions): Promise<string> => {\n\t\t\t\tconst url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${options.id}.git`);\n\t\t\t\turl.username = `t`;\n\t\t\t\turl.password = await this.generateJWT(options.id, urlOptions);\n\t\t\t\treturn url.toString();\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Get the current configuration\n\t * @returns The client configuration\n\t */\n\tgetConfig(): GitStorageOptions {\n\t\treturn { ...this.options };\n\t}\n\n\t/**\n\t * Generate a JWT token for git storage URL authentication\n\t * @private\n\t */\n\tprivate async generateJWT(repoId: string, options?: GetRemoteURLOptions): Promise<string> {\n\t\t// Default permissions and TTL\n\t\tconst permissions = options?.permissions || ['git:write', 'git:read'];\n\t\tconst ttl = options?.ttl || 365 * 24 * 60 * 60; // 1 year in seconds\n\n\t\t// Create the JWT payload\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst payload = {\n\t\t\taud: 'git.pierre.co', // todo this should be updated to git.storage\n\t\t\tiss: this.options.name,\n\t\t\tsub: '@pierre/storage',\n\t\t\trepo: repoId,\n\t\t\tscopes: permissions,\n\t\t\tiat: now,\n\t\t\texp: now + ttl,\n\t\t};\n\n\t\t// Sign the JWT with the key as the secret\n\t\t// Using HS256 for symmetric signing with the key\n\t\tconst key = await importPKCS8(this.options.key, 'ES256');\n\t\t// Sign the JWT with the key as the secret\n\t\tconst jwt = await new SignJWT(payload)\n\t\t\t.setProtectedHeader({ alg: 'ES256', typ: 'JWT' })\n\t\t\t.sign(key);\n\n\t\treturn jwt;\n\t}\n}\n\n// Export a default client factory\nexport function createClient(options: GitStorageOptions): GitStorage {\n\treturn new GitStorage(options);\n}\n\n// Type alias for backward compatibility\nexport type StorageOptions = GitStorageOptions;\n"]}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Pierre Git Storage SDK
3
+ *
4
+ * A TypeScript SDK for interacting with Pierre's git storage system
5
+ */
6
+ /**
7
+ * Type definitions for Pierre Git Storage SDK
8
+ */
9
+ interface GitStorageOptions {
10
+ key: string;
11
+ name: string;
12
+ }
13
+ interface GetRemoteURLOptions {
14
+ permissions?: ('git:write' | 'git:read' | 'repo:write')[];
15
+ ttl?: number;
16
+ }
17
+ interface Repo {
18
+ id: string;
19
+ getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
20
+ }
21
+ interface FindOneOptions {
22
+ id: string;
23
+ }
24
+ interface CreateRepoOptions {
25
+ id?: string;
26
+ }
27
+ interface CreateRepoResponse {
28
+ repo_id: string;
29
+ url: string;
30
+ }
31
+ declare class GitStorage {
32
+ private options;
33
+ constructor(options: GitStorageOptions);
34
+ /**
35
+ * Create a new repository
36
+ * @returns The created repository
37
+ */
38
+ createRepo(options?: CreateRepoOptions): Promise<Repo>;
39
+ /**
40
+ * Find a repository by ID
41
+ * @param options The search options
42
+ * @returns The found repository
43
+ */
44
+ findOne(options: FindOneOptions): Promise<Repo | null>;
45
+ /**
46
+ * Get the current configuration
47
+ * @returns The client configuration
48
+ */
49
+ getConfig(): GitStorageOptions;
50
+ /**
51
+ * Generate a JWT token for git storage URL authentication
52
+ * @private
53
+ */
54
+ private generateJWT;
55
+ }
56
+ declare function createClient(options: GitStorageOptions): GitStorage;
57
+ type StorageOptions = GitStorageOptions;
58
+
59
+ export { type CreateRepoOptions, type CreateRepoResponse, type FindOneOptions, type GetRemoteURLOptions, GitStorage, type GitStorageOptions, type Repo, type StorageOptions, createClient };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Pierre Git Storage SDK
3
+ *
4
+ * A TypeScript SDK for interacting with Pierre's git storage system
5
+ */
6
+ /**
7
+ * Type definitions for Pierre Git Storage SDK
8
+ */
9
+ interface GitStorageOptions {
10
+ key: string;
11
+ name: string;
12
+ }
13
+ interface GetRemoteURLOptions {
14
+ permissions?: ('git:write' | 'git:read' | 'repo:write')[];
15
+ ttl?: number;
16
+ }
17
+ interface Repo {
18
+ id: string;
19
+ getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
20
+ }
21
+ interface FindOneOptions {
22
+ id: string;
23
+ }
24
+ interface CreateRepoOptions {
25
+ id?: string;
26
+ }
27
+ interface CreateRepoResponse {
28
+ repo_id: string;
29
+ url: string;
30
+ }
31
+ declare class GitStorage {
32
+ private options;
33
+ constructor(options: GitStorageOptions);
34
+ /**
35
+ * Create a new repository
36
+ * @returns The created repository
37
+ */
38
+ createRepo(options?: CreateRepoOptions): Promise<Repo>;
39
+ /**
40
+ * Find a repository by ID
41
+ * @param options The search options
42
+ * @returns The found repository
43
+ */
44
+ findOne(options: FindOneOptions): Promise<Repo | null>;
45
+ /**
46
+ * Get the current configuration
47
+ * @returns The client configuration
48
+ */
49
+ getConfig(): GitStorageOptions;
50
+ /**
51
+ * Generate a JWT token for git storage URL authentication
52
+ * @private
53
+ */
54
+ private generateJWT;
55
+ }
56
+ declare function createClient(options: GitStorageOptions): GitStorage;
57
+ type StorageOptions = GitStorageOptions;
58
+
59
+ export { type CreateRepoOptions, type CreateRepoResponse, type FindOneOptions, type GetRemoteURLOptions, GitStorage, type GitStorageOptions, type Repo, type StorageOptions, createClient };
package/dist/index.js ADDED
@@ -0,0 +1,107 @@
1
+ import { importPKCS8, SignJWT } from 'jose';
2
+
3
+ // src/index.ts
4
+ var API_BASE_URL = "https://api.git.storage";
5
+ var STORAGE_BASE_URL = "git.storage";
6
+ var GitStorage = class {
7
+ options;
8
+ constructor(options) {
9
+ if (!options || options.name === void 0 || options.key === void 0 || options.name === null || options.key === null) {
10
+ throw new Error(
11
+ "GitStorage requires a name and key. Please check your configuration and try again."
12
+ );
13
+ }
14
+ if (typeof options.name !== "string" || options.name.trim() === "") {
15
+ throw new Error("GitStorage name must be a non-empty string.");
16
+ }
17
+ if (typeof options.key !== "string" || options.key.trim() === "") {
18
+ throw new Error("GitStorage key must be a non-empty string.");
19
+ }
20
+ this.options = {
21
+ key: options.key,
22
+ name: options.name
23
+ };
24
+ }
25
+ /**
26
+ * Create a new repository
27
+ * @returns The created repository
28
+ */
29
+ async createRepo(options) {
30
+ const repoId = options?.id || crypto.randomUUID();
31
+ const jwt = await this.generateJWT(repoId, {
32
+ permissions: ["repo:write"],
33
+ ttl: 1 * 60 * 60
34
+ // 1hr in seconds
35
+ });
36
+ const response = await fetch(`${API_BASE_URL}/api/v1/repos`, {
37
+ method: "POST",
38
+ headers: {
39
+ Authorization: `Bearer ${jwt}`
40
+ }
41
+ });
42
+ if (!response.ok) {
43
+ throw new Error(`Failed to create repository: ${response.statusText}`);
44
+ }
45
+ return {
46
+ id: repoId,
47
+ getRemoteURL: async (urlOptions) => {
48
+ const url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${repoId}.git`);
49
+ url.username = `t`;
50
+ url.password = await this.generateJWT(repoId, urlOptions);
51
+ return url.toString();
52
+ }
53
+ };
54
+ }
55
+ /**
56
+ * Find a repository by ID
57
+ * @param options The search options
58
+ * @returns The found repository
59
+ */
60
+ async findOne(options) {
61
+ return {
62
+ id: options.id,
63
+ getRemoteURL: async (urlOptions) => {
64
+ const url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${options.id}.git`);
65
+ url.username = `t`;
66
+ url.password = await this.generateJWT(options.id, urlOptions);
67
+ return url.toString();
68
+ }
69
+ };
70
+ }
71
+ /**
72
+ * Get the current configuration
73
+ * @returns The client configuration
74
+ */
75
+ getConfig() {
76
+ return { ...this.options };
77
+ }
78
+ /**
79
+ * Generate a JWT token for git storage URL authentication
80
+ * @private
81
+ */
82
+ async generateJWT(repoId, options) {
83
+ const permissions = options?.permissions || ["git:write", "git:read"];
84
+ const ttl = options?.ttl || 365 * 24 * 60 * 60;
85
+ const now = Math.floor(Date.now() / 1e3);
86
+ const payload = {
87
+ aud: "git.pierre.co",
88
+ // todo this should be updated to git.storage
89
+ iss: this.options.name,
90
+ sub: "@pierre/storage",
91
+ repo: repoId,
92
+ scopes: permissions,
93
+ iat: now,
94
+ exp: now + ttl
95
+ };
96
+ const key = await importPKCS8(this.options.key, "ES256");
97
+ const jwt = await new SignJWT(payload).setProtectedHeader({ alg: "ES256", typ: "JWT" }).sign(key);
98
+ return jwt;
99
+ }
100
+ };
101
+ function createClient(options) {
102
+ return new GitStorage(options);
103
+ }
104
+
105
+ export { GitStorage, createClient };
106
+ //# sourceMappingURL=index.js.map
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Pierre Git Storage SDK\n *\n * A TypeScript SDK for interacting with Pierre's git storage system\n */\n\nimport { importPKCS8, SignJWT } from 'jose';\n\n/**\n * Type definitions for Pierre Git Storage SDK\n */\n\nexport interface GitStorageOptions {\n\tkey: string;\n\tname: string;\n}\n\nexport interface GetRemoteURLOptions {\n\tpermissions?: ('git:write' | 'git:read' | 'repo:write')[];\n\tttl?: number;\n}\n\nexport interface Repo {\n\tid: string;\n\tgetRemoteURL(options?: GetRemoteURLOptions): Promise<string>;\n}\n\nexport interface FindOneOptions {\n\tid: string;\n}\n\nexport interface CreateRepoOptions {\n\tid?: string;\n}\n\nexport interface CreateRepoResponse {\n\trepo_id: string;\n\turl: string;\n}\n\n/**\n * Git Storage API\n */\ndeclare const __API_BASE_URL__: string;\ndeclare const __STORAGE_BASE_URL__: string;\n\nconst API_BASE_URL = __API_BASE_URL__;\nconst STORAGE_BASE_URL = __STORAGE_BASE_URL__;\n\nexport class GitStorage {\n\tprivate options: GitStorageOptions;\n\n\tconstructor(options: GitStorageOptions) {\n\t\tif (\n\t\t\t!options ||\n\t\t\toptions.name === undefined ||\n\t\t\toptions.key === undefined ||\n\t\t\toptions.name === null ||\n\t\t\toptions.key === null\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t'GitStorage requires a name and key. Please check your configuration and try again.',\n\t\t\t);\n\t\t}\n\n\t\tif (typeof options.name !== 'string' || options.name.trim() === '') {\n\t\t\tthrow new Error('GitStorage name must be a non-empty string.');\n\t\t}\n\n\t\tif (typeof options.key !== 'string' || options.key.trim() === '') {\n\t\t\tthrow new Error('GitStorage key must be a non-empty string.');\n\t\t}\n\n\t\tthis.options = {\n\t\t\tkey: options.key,\n\t\t\tname: options.name,\n\t\t};\n\t}\n\n\t/**\n\t * Create a new repository\n\t * @returns The created repository\n\t */\n\tasync createRepo(options?: CreateRepoOptions): Promise<Repo> {\n\t\tconst repoId = options?.id || crypto.randomUUID();\n\n\t\tconst jwt = await this.generateJWT(repoId, {\n\t\t\tpermissions: ['repo:write'],\n\t\t\tttl: 1 * 60 * 60, // 1hr in seconds\n\t\t});\n\n\t\tconst response = await fetch(`${API_BASE_URL}/api/v1/repos`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${jwt}`,\n\t\t\t},\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Failed to create repository: ${response.statusText}`);\n\t\t}\n\n\t\treturn {\n\t\t\tid: repoId,\n\t\t\tgetRemoteURL: async (urlOptions?: GetRemoteURLOptions): Promise<string> => {\n\t\t\t\tconst url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${repoId}.git`);\n\t\t\t\turl.username = `t`;\n\t\t\t\turl.password = await this.generateJWT(repoId, urlOptions);\n\t\t\t\treturn url.toString();\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Find a repository by ID\n\t * @param options The search options\n\t * @returns The found repository\n\t */\n\tasync findOne(options: FindOneOptions): Promise<Repo | null> {\n\t\treturn {\n\t\t\tid: options.id,\n\t\t\tgetRemoteURL: async (urlOptions?: GetRemoteURLOptions): Promise<string> => {\n\t\t\t\tconst url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${options.id}.git`);\n\t\t\t\turl.username = `t`;\n\t\t\t\turl.password = await this.generateJWT(options.id, urlOptions);\n\t\t\t\treturn url.toString();\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Get the current configuration\n\t * @returns The client configuration\n\t */\n\tgetConfig(): GitStorageOptions {\n\t\treturn { ...this.options };\n\t}\n\n\t/**\n\t * Generate a JWT token for git storage URL authentication\n\t * @private\n\t */\n\tprivate async generateJWT(repoId: string, options?: GetRemoteURLOptions): Promise<string> {\n\t\t// Default permissions and TTL\n\t\tconst permissions = options?.permissions || ['git:write', 'git:read'];\n\t\tconst ttl = options?.ttl || 365 * 24 * 60 * 60; // 1 year in seconds\n\n\t\t// Create the JWT payload\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\tconst payload = {\n\t\t\taud: 'git.pierre.co', // todo this should be updated to git.storage\n\t\t\tiss: this.options.name,\n\t\t\tsub: '@pierre/storage',\n\t\t\trepo: repoId,\n\t\t\tscopes: permissions,\n\t\t\tiat: now,\n\t\t\texp: now + ttl,\n\t\t};\n\n\t\t// Sign the JWT with the key as the secret\n\t\t// Using HS256 for symmetric signing with the key\n\t\tconst key = await importPKCS8(this.options.key, 'ES256');\n\t\t// Sign the JWT with the key as the secret\n\t\tconst jwt = await new SignJWT(payload)\n\t\t\t.setProtectedHeader({ alg: 'ES256', typ: 'JWT' })\n\t\t\t.sign(key);\n\n\t\treturn jwt;\n\t}\n}\n\n// Export a default client factory\nexport function createClient(options: GitStorageOptions): GitStorage {\n\treturn new GitStorage(options);\n}\n\n// Type alias for backward compatibility\nexport type StorageOptions = GitStorageOptions;\n"]}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@pierre/storage",
3
+ "version": "0.0.1",
4
+ "description": "Pierre Git Storage SDK",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "dev": "tsup --watch",
25
+ "prepublishOnly": "BUILD_ENV=production pnpm build"
26
+ },
27
+ "dependencies": {
28
+ "jose": "catalog:"
29
+ },
30
+ "devDependencies": {
31
+ "tsup": "catalog:",
32
+ "typescript": "catalog:",
33
+ "vitest": "catalog:"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ }
38
+ }
package/src/index.ts ADDED
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Pierre Git Storage SDK
3
+ *
4
+ * A TypeScript SDK for interacting with Pierre's git storage system
5
+ */
6
+
7
+ import { importPKCS8, SignJWT } from 'jose';
8
+
9
+ /**
10
+ * Type definitions for Pierre Git Storage SDK
11
+ */
12
+
13
+ export interface GitStorageOptions {
14
+ key: string;
15
+ name: string;
16
+ }
17
+
18
+ export interface GetRemoteURLOptions {
19
+ permissions?: ('git:write' | 'git:read' | 'repo:write')[];
20
+ ttl?: number;
21
+ }
22
+
23
+ export interface Repo {
24
+ id: string;
25
+ getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
26
+ }
27
+
28
+ export interface FindOneOptions {
29
+ id: string;
30
+ }
31
+
32
+ export interface CreateRepoOptions {
33
+ id?: string;
34
+ }
35
+
36
+ export interface CreateRepoResponse {
37
+ repo_id: string;
38
+ url: string;
39
+ }
40
+
41
+ /**
42
+ * Git Storage API
43
+ */
44
+ declare const __API_BASE_URL__: string;
45
+ declare const __STORAGE_BASE_URL__: string;
46
+
47
+ const API_BASE_URL = __API_BASE_URL__;
48
+ const STORAGE_BASE_URL = __STORAGE_BASE_URL__;
49
+
50
+ export class GitStorage {
51
+ private options: GitStorageOptions;
52
+
53
+ constructor(options: GitStorageOptions) {
54
+ if (
55
+ !options ||
56
+ options.name === undefined ||
57
+ options.key === undefined ||
58
+ options.name === null ||
59
+ options.key === null
60
+ ) {
61
+ throw new Error(
62
+ 'GitStorage requires a name and key. Please check your configuration and try again.',
63
+ );
64
+ }
65
+
66
+ if (typeof options.name !== 'string' || options.name.trim() === '') {
67
+ throw new Error('GitStorage name must be a non-empty string.');
68
+ }
69
+
70
+ if (typeof options.key !== 'string' || options.key.trim() === '') {
71
+ throw new Error('GitStorage key must be a non-empty string.');
72
+ }
73
+
74
+ this.options = {
75
+ key: options.key,
76
+ name: options.name,
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Create a new repository
82
+ * @returns The created repository
83
+ */
84
+ async createRepo(options?: CreateRepoOptions): Promise<Repo> {
85
+ const repoId = options?.id || crypto.randomUUID();
86
+
87
+ const jwt = await this.generateJWT(repoId, {
88
+ permissions: ['repo:write'],
89
+ ttl: 1 * 60 * 60, // 1hr in seconds
90
+ });
91
+
92
+ const response = await fetch(`${API_BASE_URL}/api/v1/repos`, {
93
+ method: 'POST',
94
+ headers: {
95
+ Authorization: `Bearer ${jwt}`,
96
+ },
97
+ });
98
+
99
+ if (!response.ok) {
100
+ throw new Error(`Failed to create repository: ${response.statusText}`);
101
+ }
102
+
103
+ return {
104
+ id: repoId,
105
+ getRemoteURL: async (urlOptions?: GetRemoteURLOptions): Promise<string> => {
106
+ const url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${repoId}.git`);
107
+ url.username = `t`;
108
+ url.password = await this.generateJWT(repoId, urlOptions);
109
+ return url.toString();
110
+ },
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Find a repository by ID
116
+ * @param options The search options
117
+ * @returns The found repository
118
+ */
119
+ async findOne(options: FindOneOptions): Promise<Repo | null> {
120
+ return {
121
+ id: options.id,
122
+ getRemoteURL: async (urlOptions?: GetRemoteURLOptions): Promise<string> => {
123
+ const url = new URL(`https://${this.options.name}.${STORAGE_BASE_URL}/${options.id}.git`);
124
+ url.username = `t`;
125
+ url.password = await this.generateJWT(options.id, urlOptions);
126
+ return url.toString();
127
+ },
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Get the current configuration
133
+ * @returns The client configuration
134
+ */
135
+ getConfig(): GitStorageOptions {
136
+ return { ...this.options };
137
+ }
138
+
139
+ /**
140
+ * Generate a JWT token for git storage URL authentication
141
+ * @private
142
+ */
143
+ private async generateJWT(repoId: string, options?: GetRemoteURLOptions): Promise<string> {
144
+ // Default permissions and TTL
145
+ const permissions = options?.permissions || ['git:write', 'git:read'];
146
+ const ttl = options?.ttl || 365 * 24 * 60 * 60; // 1 year in seconds
147
+
148
+ // Create the JWT payload
149
+ const now = Math.floor(Date.now() / 1000);
150
+ const payload = {
151
+ aud: 'git.pierre.co', // todo this should be updated to git.storage
152
+ iss: this.options.name,
153
+ sub: '@pierre/storage',
154
+ repo: repoId,
155
+ scopes: permissions,
156
+ iat: now,
157
+ exp: now + ttl,
158
+ };
159
+
160
+ // Sign the JWT with the key as the secret
161
+ // Using HS256 for symmetric signing with the key
162
+ const key = await importPKCS8(this.options.key, 'ES256');
163
+ // Sign the JWT with the key as the secret
164
+ const jwt = await new SignJWT(payload)
165
+ .setProtectedHeader({ alg: 'ES256', typ: 'JWT' })
166
+ .sign(key);
167
+
168
+ return jwt;
169
+ }
170
+ }
171
+
172
+ // Export a default client factory
173
+ export function createClient(options: GitStorageOptions): GitStorage {
174
+ return new GitStorage(options);
175
+ }
176
+
177
+ // Type alias for backward compatibility
178
+ export type StorageOptions = GitStorageOptions;
package/src/types.ts ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Type definitions for Pierre Git Storage SDK
3
+ */
4
+
5
+ export interface GitStorageOptions {
6
+ key: string;
7
+ name: string;
8
+ }
9
+
10
+ export interface GetRemoteURLOptions {
11
+ permissions?: ('git:write' | 'git:read' | 'repo:write')[];
12
+ ttl?: number;
13
+ }
14
+
15
+ export interface Repo {
16
+ id: string;
17
+ getRemoteURL(options?: GetRemoteURLOptions): Promise<string>;
18
+ }
19
+
20
+ export interface FindOneOptions {
21
+ id: string;
22
+ }
23
+
24
+ export interface CreateRepoOptions {
25
+ id?: string;
26
+ }
27
+
28
+ export interface CreateRepoResponse {
29
+ repo_id: string;
30
+ url: string;
31
+ }