@lobu/connector-sdk 7.2.0 → 9.0.0
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/connector-runtime.d.ts +23 -11
- package/dist/connector-runtime.d.ts.map +1 -1
- package/dist/connector-runtime.js +32 -8
- package/dist/connector-runtime.js.map +1 -1
- package/dist/connector-types.d.ts +27 -15
- package/dist/connector-types.d.ts.map +1 -1
- package/dist/connector-types.js +0 -7
- package/dist/connector-types.js.map +1 -1
- package/dist/file-source.d.ts +112 -0
- package/dist/file-source.d.ts.map +1 -0
- package/dist/file-source.js +40 -0
- package/dist/file-source.js.map +1 -0
- package/dist/identity-normalize.d.ts +12 -0
- package/dist/identity-normalize.d.ts.map +1 -1
- package/dist/identity-normalize.js +12 -0
- package/dist/identity-normalize.js.map +1 -1
- package/dist/index.d.ts +15 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -5
- package/dist/index.js.map +1 -1
- package/dist/reaction-client-types.d.ts +126 -0
- package/dist/reaction-client-types.d.ts.map +1 -0
- package/dist/reaction-client-types.js +2 -0
- package/dist/reaction-client-types.js.map +1 -0
- package/dist/sources/cache.d.ts +82 -0
- package/dist/sources/cache.d.ts.map +1 -0
- package/dist/sources/cache.js +169 -0
- package/dist/sources/cache.js.map +1 -0
- package/dist/sources/git-file-source.d.ts +33 -0
- package/dist/sources/git-file-source.d.ts.map +1 -0
- package/dist/sources/git-file-source.js +207 -0
- package/dist/sources/git-file-source.js.map +1 -0
- package/dist/sources/git-http.d.ts +48 -0
- package/dist/sources/git-http.d.ts.map +1 -0
- package/dist/sources/git-http.js +179 -0
- package/dist/sources/git-http.js.map +1 -0
- package/dist/sources/git-snapshot.d.ts +14 -0
- package/dist/sources/git-snapshot.d.ts.map +1 -0
- package/dist/sources/git-snapshot.js +96 -0
- package/dist/sources/git-snapshot.js.map +1 -0
- package/dist/sources/glob.d.ts +31 -0
- package/dist/sources/glob.d.ts.map +1 -0
- package/dist/sources/glob.js +129 -0
- package/dist/sources/glob.js.map +1 -0
- package/dist/sources/local-file-source.d.ts +29 -0
- package/dist/sources/local-file-source.d.ts.map +1 -0
- package/dist/sources/local-file-source.js +343 -0
- package/dist/sources/local-file-source.js.map +1 -0
- package/dist/sources/resolver.d.ts +6 -0
- package/dist/sources/resolver.d.ts.map +1 -0
- package/dist/sources/resolver.js +47 -0
- package/dist/sources/resolver.js.map +1 -0
- package/dist/sources/snapshot.d.ts +19 -0
- package/dist/sources/snapshot.d.ts.map +1 -0
- package/dist/sources/snapshot.js +91 -0
- package/dist/sources/snapshot.js.map +1 -0
- package/dist/sources/tarball-file-source.d.ts +28 -0
- package/dist/sources/tarball-file-source.d.ts.map +1 -0
- package/dist/sources/tarball-file-source.js +273 -0
- package/dist/sources/tarball-file-source.js.map +1 -0
- package/dist/types.d.ts +3 -65
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -3
- package/dist/event-taxonomy.d.ts +0 -3
- package/dist/event-taxonomy.d.ts.map +0 -1
- package/dist/event-taxonomy.js +0 -30
- package/dist/event-taxonomy.js.map +0 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitFileSource — shallow git clone backed by `isomorphic-git`.
|
|
3
|
+
*
|
|
4
|
+
* - URI shape: `git+https://github.com/owner/repo.git[@<ref>]`. Ref may be
|
|
5
|
+
* a branch name, tag, or full commit SHA. If omitted, defaults to `main`.
|
|
6
|
+
* - Initial fetch: shallow clone (`depth: 1`, `singleBranch: true`).
|
|
7
|
+
* - Subsequent fetch: `git.fetch` against the same single branch with
|
|
8
|
+
* `depth: 1` — pulls only the new tip if upstream advanced.
|
|
9
|
+
* - `ref` = `resolveRef('HEAD')` (full commit SHA).
|
|
10
|
+
* - `diffSinceRef(prevRef)` walks two trees with `git.walk` and classifies
|
|
11
|
+
* each path by OID equality (`added`/`modified`/`removed`).
|
|
12
|
+
*
|
|
13
|
+
* Caveats called out in JSDoc rather than hidden:
|
|
14
|
+
*
|
|
15
|
+
* - With `depth: 1`, history before the current tip is NOT in the local
|
|
16
|
+
* repo. `git.walk` requires both trees to be reachable; if the caller
|
|
17
|
+
* passes a `prevRef` we no longer have on disk we throw a clear error.
|
|
18
|
+
* - Snapshot reads point at the working tree inside the cache. Git itself
|
|
19
|
+
* is not exposed.
|
|
20
|
+
*/
|
|
21
|
+
import { mkdir, readFile } from 'node:fs/promises';
|
|
22
|
+
import { join } from 'node:path';
|
|
23
|
+
import * as git from 'isomorphic-git';
|
|
24
|
+
// `fs` is passed as a plain Node fs module — isomorphic-git accepts it.
|
|
25
|
+
// We import the callback-style module so isomorphic-git's promisified
|
|
26
|
+
// adapter works out of the box (it auto-detects promises if present).
|
|
27
|
+
import nodeFs from 'node:fs';
|
|
28
|
+
import { cachePathsFor, readAndVerifyMeta, requireMeta, withSourceLock, writeMeta, } from './cache.js';
|
|
29
|
+
import { GitSnapshot } from './git-snapshot.js';
|
|
30
|
+
// Custom https-only http client — rejects plaintext redirects that the
|
|
31
|
+
// stock `isomorphic-git/http/node` (simple-get under the hood) would
|
|
32
|
+
// silently follow.
|
|
33
|
+
import { gitHttpsOnlyClient as http } from './git-http.js';
|
|
34
|
+
const DEFAULT_BRANCH = 'main';
|
|
35
|
+
export function parseGitUri(uri) {
|
|
36
|
+
if (uri.startsWith('git+http://')) {
|
|
37
|
+
throw new Error('GitFileSource: plaintext HTTP rejected, use git+https://');
|
|
38
|
+
}
|
|
39
|
+
if (!uri.startsWith('git+https://')) {
|
|
40
|
+
throw new Error(`GitFileSource: expected git+https:// URI, got ${uri}`);
|
|
41
|
+
}
|
|
42
|
+
const stripped = uri.slice('git+'.length); // → https://...
|
|
43
|
+
// Split on the LAST `@` that follows the host's `/`, not the user@host form.
|
|
44
|
+
const slashIdx = stripped.indexOf('/', stripped.indexOf('://') + 3);
|
|
45
|
+
const atIdx = slashIdx === -1 ? -1 : stripped.lastIndexOf('@');
|
|
46
|
+
if (atIdx > slashIdx) {
|
|
47
|
+
return {
|
|
48
|
+
url: stripped.slice(0, atIdx),
|
|
49
|
+
ref: stripped.slice(atIdx + 1) || DEFAULT_BRANCH,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return { url: stripped, ref: DEFAULT_BRANCH };
|
|
53
|
+
}
|
|
54
|
+
export class GitFileSource {
|
|
55
|
+
#uri;
|
|
56
|
+
#parsed;
|
|
57
|
+
#paths;
|
|
58
|
+
constructor(uri) {
|
|
59
|
+
this.#uri = uri;
|
|
60
|
+
this.#parsed = parseGitUri(uri);
|
|
61
|
+
this.#paths = cachePathsFor(uri);
|
|
62
|
+
}
|
|
63
|
+
fetch() {
|
|
64
|
+
return withSourceLock(this.#uri, () => this.#fetchLocked());
|
|
65
|
+
}
|
|
66
|
+
async #fetchLocked() {
|
|
67
|
+
await mkdir(this.#paths.root, { recursive: true });
|
|
68
|
+
await readAndVerifyMeta(this.#paths.metaPath, this.#uri);
|
|
69
|
+
const dir = this.#paths.snapshotDir;
|
|
70
|
+
// Detect whether we already have a clone.
|
|
71
|
+
const alreadyCloned = await pathExists(join(dir, '.git'));
|
|
72
|
+
if (!alreadyCloned) {
|
|
73
|
+
await mkdir(dir, { recursive: true });
|
|
74
|
+
await git.clone({
|
|
75
|
+
fs: nodeFs,
|
|
76
|
+
http,
|
|
77
|
+
dir,
|
|
78
|
+
url: this.#parsed.url,
|
|
79
|
+
ref: this.#parsed.ref,
|
|
80
|
+
singleBranch: true,
|
|
81
|
+
depth: 1,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Existing repo — fetch the same branch shallow.
|
|
86
|
+
await git.fetch({
|
|
87
|
+
fs: nodeFs,
|
|
88
|
+
http,
|
|
89
|
+
dir,
|
|
90
|
+
ref: this.#parsed.ref,
|
|
91
|
+
singleBranch: true,
|
|
92
|
+
depth: 1,
|
|
93
|
+
tags: false,
|
|
94
|
+
});
|
|
95
|
+
// Move HEAD/working tree to the fetched tip.
|
|
96
|
+
await git.checkout({
|
|
97
|
+
fs: nodeFs,
|
|
98
|
+
dir,
|
|
99
|
+
ref: this.#parsed.ref,
|
|
100
|
+
force: true,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
const ref = await git.resolveRef({ fs: nodeFs, dir, ref: 'HEAD' });
|
|
104
|
+
await writeMeta(this.#paths.metaPath, { uri: this.#uri, kind: 'git' });
|
|
105
|
+
// Read from the captured commit's tree/blobs — immutable view even if a
|
|
106
|
+
// later fetch() moves HEAD or rewrites the working tree on disk.
|
|
107
|
+
return new GitSnapshot(dir, ref, nodeFs, { exclude: isGitInternalPath });
|
|
108
|
+
}
|
|
109
|
+
diffSinceRef(prevRef) {
|
|
110
|
+
return withSourceLock(this.#uri, () => this.#diffLocked(prevRef));
|
|
111
|
+
}
|
|
112
|
+
async #diffLocked(prevRef) {
|
|
113
|
+
await requireMeta(this.#paths.metaPath, this.#uri);
|
|
114
|
+
const dir = this.#paths.snapshotDir;
|
|
115
|
+
const currentRef = await git.resolveRef({ fs: nodeFs, dir, ref: 'HEAD' });
|
|
116
|
+
if (currentRef === prevRef)
|
|
117
|
+
return { added: [], modified: [], removed: [] };
|
|
118
|
+
// If `prevRef` isn't reachable in the local (shallow) repo, return a
|
|
119
|
+
// full-reingest delta — every current file as `added`. Matches the
|
|
120
|
+
// tarball and local-source contract: an unknown prevRef yields a
|
|
121
|
+
// re-ingest, never a thrown error.
|
|
122
|
+
let prevReachable = true;
|
|
123
|
+
try {
|
|
124
|
+
await git.readCommit({ fs: nodeFs, dir, oid: prevRef });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
prevReachable = false;
|
|
128
|
+
}
|
|
129
|
+
if (!prevReachable) {
|
|
130
|
+
const allFiles = await listCurrentFiles(dir, currentRef);
|
|
131
|
+
return { added: allFiles, modified: [], removed: [] };
|
|
132
|
+
}
|
|
133
|
+
const added = [];
|
|
134
|
+
const modified = [];
|
|
135
|
+
const removed = [];
|
|
136
|
+
await git.walk({
|
|
137
|
+
fs: nodeFs,
|
|
138
|
+
dir,
|
|
139
|
+
trees: [git.TREE({ ref: prevRef }), git.TREE({ ref: currentRef })],
|
|
140
|
+
map: async (filepath, entries) => {
|
|
141
|
+
// The root entry has filepath '.'. Don't classify it but DO let the
|
|
142
|
+
// walk descend (returning null prunes the subtree).
|
|
143
|
+
if (filepath === '.')
|
|
144
|
+
return undefined;
|
|
145
|
+
if (!entries)
|
|
146
|
+
return undefined;
|
|
147
|
+
const [a, b] = entries;
|
|
148
|
+
// Skip directories — they're emitted as their own map() calls; we
|
|
149
|
+
// only classify file (blob) entries.
|
|
150
|
+
const aType = a ? await a.type() : null;
|
|
151
|
+
const bType = b ? await b.type() : null;
|
|
152
|
+
if (aType === 'tree' || bType === 'tree')
|
|
153
|
+
return undefined;
|
|
154
|
+
const aOid = aType ? await a.oid() : null;
|
|
155
|
+
const bOid = bType ? await b.oid() : null;
|
|
156
|
+
if (aOid === null && bOid !== null)
|
|
157
|
+
added.push(filepath);
|
|
158
|
+
else if (aOid !== null && bOid === null)
|
|
159
|
+
removed.push(filepath);
|
|
160
|
+
else if (aOid !== null && bOid !== null && aOid !== bOid)
|
|
161
|
+
modified.push(filepath);
|
|
162
|
+
return undefined;
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
return { added, modified, removed };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/** Walk a commit's tree and return every blob path (POSIX-separated). */
|
|
169
|
+
async function listCurrentFiles(dir, ref) {
|
|
170
|
+
const collected = [];
|
|
171
|
+
await git.walk({
|
|
172
|
+
fs: nodeFs,
|
|
173
|
+
dir,
|
|
174
|
+
trees: [git.TREE({ ref })],
|
|
175
|
+
map: async (filepath, entries) => {
|
|
176
|
+
if (filepath === '.')
|
|
177
|
+
return undefined;
|
|
178
|
+
if (!entries)
|
|
179
|
+
return undefined;
|
|
180
|
+
const [entry] = entries;
|
|
181
|
+
if (!entry)
|
|
182
|
+
return undefined;
|
|
183
|
+
const type = await entry.type();
|
|
184
|
+
if (type === 'blob')
|
|
185
|
+
collected.push(filepath);
|
|
186
|
+
return undefined;
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
return collected;
|
|
190
|
+
}
|
|
191
|
+
/** Filter for git internals — matches `.git` itself and anything under it. */
|
|
192
|
+
function isGitInternalPath(rel) {
|
|
193
|
+
return rel === '.git' || rel.startsWith('.git/');
|
|
194
|
+
}
|
|
195
|
+
async function pathExists(p) {
|
|
196
|
+
try {
|
|
197
|
+
await readFile(p).catch(async () => {
|
|
198
|
+
const { stat } = await import('node:fs/promises');
|
|
199
|
+
await stat(p);
|
|
200
|
+
});
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=git-file-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-file-source.js","sourceRoot":"","sources":["../../src/sources/git-file-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HttpClient for isomorphic-git that:
|
|
3
|
+
*
|
|
4
|
+
* - Talks https only — refuses to issue any request whose URL is not
|
|
5
|
+
* `https://...`.
|
|
6
|
+
* - Follows redirects manually (max 5 hops). Every `Location` is re-validated
|
|
7
|
+
* https before the next request — closes the https-to-http downgrade hole
|
|
8
|
+
* that an https endpoint replying with `Location: http://...` would
|
|
9
|
+
* otherwise open against the default `isomorphic-git/http/node` impl
|
|
10
|
+
* (which uses `simple-get`'s built-in redirect follower and does NOT
|
|
11
|
+
* enforce a scheme on the next hop).
|
|
12
|
+
*
|
|
13
|
+
* Implemented on top of Node's `https.request` so the SDK doesn't pull in
|
|
14
|
+
* an extra HTTP client. The body-as-async-iterator contract matches
|
|
15
|
+
* isomorphic-git's `GitHttpRequest` / `GitHttpResponse` types.
|
|
16
|
+
*/
|
|
17
|
+
interface GitHttpRequest {
|
|
18
|
+
url: string;
|
|
19
|
+
method?: string;
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
body?: AsyncIterable<Uint8Array> | Uint8Array | Buffer;
|
|
22
|
+
}
|
|
23
|
+
interface GitHttpResponse {
|
|
24
|
+
url: string;
|
|
25
|
+
method: string;
|
|
26
|
+
statusCode: number;
|
|
27
|
+
statusMessage: string;
|
|
28
|
+
headers: Record<string, string>;
|
|
29
|
+
body: AsyncIterableIterator<Uint8Array>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Send `req`, manually following 3xx redirects up to MAX_REDIRECTS. Every
|
|
33
|
+
* hop validates the next URL is https. On a 30x→non-https Location, throws.
|
|
34
|
+
*
|
|
35
|
+
* Per RFC 7231 §6.4: 301/302/303 turn POST into GET and drop the request
|
|
36
|
+
* body; 307/308 preserve the method and body. isomorphic-git's traffic is
|
|
37
|
+
* GET (info/refs) and POST (upload-pack / receive-pack). For a POST that
|
|
38
|
+
* gets redirected with a method-changing status we drop the body — git
|
|
39
|
+
* smart servers don't typically issue method-changing redirects mid-flow,
|
|
40
|
+
* but if they did, the resulting GET would surface as a server-side error
|
|
41
|
+
* rather than silently completing.
|
|
42
|
+
*/
|
|
43
|
+
export declare function gitHttpRequest(req: GitHttpRequest): Promise<GitHttpResponse>;
|
|
44
|
+
export declare const gitHttpsOnlyClient: {
|
|
45
|
+
request: typeof gitHttpRequest;
|
|
46
|
+
};
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=git-http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-http.d.ts","sourceRoot":"","sources":["../../src/sources/git-http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,MAAM,CAAC;CACxD;AAED,UAAU,eAAe;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAC;CACzC;AAgGD;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAkElF;AAED,eAAO,MAAM,kBAAkB;;CAA8B,CAAC"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HttpClient for isomorphic-git that:
|
|
3
|
+
*
|
|
4
|
+
* - Talks https only — refuses to issue any request whose URL is not
|
|
5
|
+
* `https://...`.
|
|
6
|
+
* - Follows redirects manually (max 5 hops). Every `Location` is re-validated
|
|
7
|
+
* https before the next request — closes the https-to-http downgrade hole
|
|
8
|
+
* that an https endpoint replying with `Location: http://...` would
|
|
9
|
+
* otherwise open against the default `isomorphic-git/http/node` impl
|
|
10
|
+
* (which uses `simple-get`'s built-in redirect follower and does NOT
|
|
11
|
+
* enforce a scheme on the next hop).
|
|
12
|
+
*
|
|
13
|
+
* Implemented on top of Node's `https.request` so the SDK doesn't pull in
|
|
14
|
+
* an extra HTTP client. The body-as-async-iterator contract matches
|
|
15
|
+
* isomorphic-git's `GitHttpRequest` / `GitHttpResponse` types.
|
|
16
|
+
*/
|
|
17
|
+
import { request as httpsRequest } from 'node:https';
|
|
18
|
+
import { Readable } from 'node:stream';
|
|
19
|
+
const MAX_REDIRECTS = 5;
|
|
20
|
+
async function bodyToBuffer(body) {
|
|
21
|
+
if (!body)
|
|
22
|
+
return undefined;
|
|
23
|
+
if (Buffer.isBuffer(body))
|
|
24
|
+
return body;
|
|
25
|
+
if (body instanceof Uint8Array)
|
|
26
|
+
return Buffer.from(body);
|
|
27
|
+
const chunks = [];
|
|
28
|
+
for await (const chunk of body) {
|
|
29
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
30
|
+
}
|
|
31
|
+
return Buffer.concat(chunks);
|
|
32
|
+
}
|
|
33
|
+
function flattenHeaders(raw) {
|
|
34
|
+
const out = {};
|
|
35
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
36
|
+
if (v === undefined)
|
|
37
|
+
continue;
|
|
38
|
+
out[k] = Array.isArray(v) ? v.join(', ') : v;
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
function nodeStreamToAsyncIterableIterator(stream) {
|
|
43
|
+
// IncomingMessage is already AsyncIterable<Buffer>. Wrap it as an
|
|
44
|
+
// AsyncIterableIterator since that's what isomorphic-git's type
|
|
45
|
+
// demands (it has a `next()` method).
|
|
46
|
+
const iter = stream[Symbol.asyncIterator]();
|
|
47
|
+
return {
|
|
48
|
+
next: () => iter.next(),
|
|
49
|
+
return: iter.return ? (v) => iter.return(v) : undefined,
|
|
50
|
+
throw: iter.throw ? (e) => iter.throw(e) : undefined,
|
|
51
|
+
[Symbol.asyncIterator]() {
|
|
52
|
+
return this;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function singleRequest(req) {
|
|
57
|
+
if (!req.url.startsWith('https://')) {
|
|
58
|
+
throw new Error(`GitFileSource: refusing non-https request: ${req.url}`);
|
|
59
|
+
}
|
|
60
|
+
const parsed = new URL(req.url);
|
|
61
|
+
const bodyBuf = await bodyToBuffer(req.body);
|
|
62
|
+
const method = (req.method ?? 'GET').toUpperCase();
|
|
63
|
+
const headers = { ...(req.headers ?? {}) };
|
|
64
|
+
if (bodyBuf) {
|
|
65
|
+
headers['content-length'] = bodyBuf.length;
|
|
66
|
+
}
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const r = httpsRequest({
|
|
69
|
+
protocol: parsed.protocol,
|
|
70
|
+
hostname: parsed.hostname,
|
|
71
|
+
port: parsed.port || undefined,
|
|
72
|
+
path: `${parsed.pathname}${parsed.search}`,
|
|
73
|
+
method,
|
|
74
|
+
headers,
|
|
75
|
+
}, (res) => {
|
|
76
|
+
resolve({
|
|
77
|
+
statusCode: res.statusCode ?? 0,
|
|
78
|
+
statusMessage: res.statusMessage ?? '',
|
|
79
|
+
headers: flattenHeaders(res.headers),
|
|
80
|
+
bodyStream: res,
|
|
81
|
+
url: req.url,
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
r.on('error', reject);
|
|
85
|
+
if (bodyBuf)
|
|
86
|
+
r.write(bodyBuf);
|
|
87
|
+
r.end();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async function drain(stream) {
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
stream.on('data', () => undefined);
|
|
93
|
+
stream.on('end', () => resolve());
|
|
94
|
+
stream.on('error', () => resolve());
|
|
95
|
+
stream.resume();
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Send `req`, manually following 3xx redirects up to MAX_REDIRECTS. Every
|
|
100
|
+
* hop validates the next URL is https. On a 30x→non-https Location, throws.
|
|
101
|
+
*
|
|
102
|
+
* Per RFC 7231 §6.4: 301/302/303 turn POST into GET and drop the request
|
|
103
|
+
* body; 307/308 preserve the method and body. isomorphic-git's traffic is
|
|
104
|
+
* GET (info/refs) and POST (upload-pack / receive-pack). For a POST that
|
|
105
|
+
* gets redirected with a method-changing status we drop the body — git
|
|
106
|
+
* smart servers don't typically issue method-changing redirects mid-flow,
|
|
107
|
+
* but if they did, the resulting GET would surface as a server-side error
|
|
108
|
+
* rather than silently completing.
|
|
109
|
+
*/
|
|
110
|
+
export async function gitHttpRequest(req) {
|
|
111
|
+
let cur = req;
|
|
112
|
+
let lastBuffered;
|
|
113
|
+
for (let i = 0; i <= MAX_REDIRECTS; i++) {
|
|
114
|
+
if (cur.body && !Buffer.isBuffer(cur.body) && !(cur.body instanceof Uint8Array)) {
|
|
115
|
+
// Eagerly buffer the body so a redirect can replay it without
|
|
116
|
+
// re-consuming an already-iterated source.
|
|
117
|
+
lastBuffered = await bodyToBuffer(cur.body);
|
|
118
|
+
cur = { ...cur, body: lastBuffered };
|
|
119
|
+
}
|
|
120
|
+
const res = await singleRequest(cur);
|
|
121
|
+
const status = res.statusCode;
|
|
122
|
+
const isRedirect = status >= 300 && status < 400 && res.headers['location'];
|
|
123
|
+
if (!isRedirect) {
|
|
124
|
+
return {
|
|
125
|
+
url: res.url,
|
|
126
|
+
method: cur.method ?? 'GET',
|
|
127
|
+
statusCode: status,
|
|
128
|
+
statusMessage: res.statusMessage,
|
|
129
|
+
headers: res.headers,
|
|
130
|
+
body: nodeStreamToAsyncIterableIterator(res.bodyStream),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const locHeader = res.headers['location'];
|
|
134
|
+
if (!locHeader) {
|
|
135
|
+
return {
|
|
136
|
+
url: res.url,
|
|
137
|
+
method: cur.method ?? 'GET',
|
|
138
|
+
statusCode: status,
|
|
139
|
+
statusMessage: res.statusMessage,
|
|
140
|
+
headers: res.headers,
|
|
141
|
+
body: nodeStreamToAsyncIterableIterator(res.bodyStream),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
let nextUrl;
|
|
145
|
+
try {
|
|
146
|
+
nextUrl = new URL(locHeader, cur.url).toString();
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
throw new Error(`GitFileSource: invalid redirect location: ${locHeader}`);
|
|
150
|
+
}
|
|
151
|
+
if (!nextUrl.startsWith('https://')) {
|
|
152
|
+
throw new Error(`GitFileSource: redirect to plaintext URL rejected: ${nextUrl}`);
|
|
153
|
+
}
|
|
154
|
+
// Drain the redirect's body so the socket can be reused.
|
|
155
|
+
await drain(res.bodyStream);
|
|
156
|
+
// RFC 7231 §6.4.2/6.4.3: 301/302/303 strip the body and change the
|
|
157
|
+
// method to GET. 307/308 preserve method + body.
|
|
158
|
+
let nextMethod = cur.method ?? 'GET';
|
|
159
|
+
let nextBody = lastBuffered;
|
|
160
|
+
if (status === 301 || status === 302 || status === 303) {
|
|
161
|
+
if (nextMethod !== 'GET' && nextMethod !== 'HEAD') {
|
|
162
|
+
nextMethod = 'GET';
|
|
163
|
+
nextBody = undefined;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
cur = {
|
|
167
|
+
url: nextUrl,
|
|
168
|
+
method: nextMethod,
|
|
169
|
+
headers: { ...(cur.headers ?? {}) },
|
|
170
|
+
body: nextBody,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
throw new Error(`GitFileSource: too many redirects (>${MAX_REDIRECTS}) for ${req.url}`);
|
|
174
|
+
}
|
|
175
|
+
export const gitHttpsOnlyClient = { request: gitHttpRequest };
|
|
176
|
+
// Force Readable import to be retained (avoids unused-import elision and
|
|
177
|
+
// keeps the contract explicit for future stream-conversion changes).
|
|
178
|
+
void Readable;
|
|
179
|
+
//# sourceMappingURL=git-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-http.js","sourceRoot":"","sources":["../../src/sources/git-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type nodeFsType from 'node:fs';
|
|
2
|
+
import type { Snapshot } from '../file-source.js';
|
|
3
|
+
export interface GitSnapshotOptions {
|
|
4
|
+
exclude?: (relativePath: string) => boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare class GitSnapshot implements Snapshot {
|
|
7
|
+
#private;
|
|
8
|
+
readonly ref: string;
|
|
9
|
+
constructor(dir: string, ref: string, fs: typeof nodeFsType, options?: GitSnapshotOptions);
|
|
10
|
+
walkFiles(glob: string): AsyncIterable<string>;
|
|
11
|
+
readFile(relativePath: string): Promise<Buffer>;
|
|
12
|
+
readText(relativePath: string): Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=git-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-snapshot.d.ts","sourceRoot":"","sources":["../../src/sources/git-snapshot.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,UAAU,MAAM,SAAS,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;CAC7C;AAED,qBAAa,WAAY,YAAW,QAAQ;;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;gBAMnB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,OAAO,UAAU,EACrB,OAAO,GAAE,kBAAuB;IAQ3B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC;IAsB/C,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAW/C,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAuBtD"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitSnapshot — Snapshot backed by an immutable git commit OID.
|
|
3
|
+
*
|
|
4
|
+
* Unlike `DirectorySnapshot`, this snapshot reads file contents via
|
|
5
|
+
* `git.readBlob({oid, filepath})` against the captured commit, NOT from
|
|
6
|
+
* the on-disk working tree. That gives us true immutability: a later
|
|
7
|
+
* `fetch()` may move HEAD or rewrite the working tree, but blob OIDs for
|
|
8
|
+
* the captured commit stay reachable in the shallow clone's object DB.
|
|
9
|
+
*
|
|
10
|
+
* Caveats:
|
|
11
|
+
* - `walkFiles` walks the captured commit's tree (`git.walk` with a single
|
|
12
|
+
* `TREE({ref})`). Result: files-as-they-existed-at-the-commit, not
|
|
13
|
+
* files-as-they-are-on-disk-right-now.
|
|
14
|
+
* - `readFile` / `readText` extract blob bytes from the object DB.
|
|
15
|
+
* - Path-security primitives mirror `DirectorySnapshot` lexically (absolute
|
|
16
|
+
* paths rejected, `..` escapes rejected, exclude predicate enforced).
|
|
17
|
+
* - No realpath/symlink defense — git's object model has no symlinks-as-
|
|
18
|
+
* filesystem-pointers. A blob with mode 120000 IS the link contents, not
|
|
19
|
+
* a follow-able pointer.
|
|
20
|
+
*/
|
|
21
|
+
import * as git from 'isomorphic-git';
|
|
22
|
+
import { isAbsolute, join, normalize, relative, sep } from 'node:path';
|
|
23
|
+
import { matchesGlob } from './glob.js';
|
|
24
|
+
export class GitSnapshot {
|
|
25
|
+
ref;
|
|
26
|
+
#dir;
|
|
27
|
+
#fs;
|
|
28
|
+
#exclude;
|
|
29
|
+
constructor(dir, ref, fs, options = {}) {
|
|
30
|
+
this.#dir = dir;
|
|
31
|
+
this.ref = ref;
|
|
32
|
+
this.#fs = fs;
|
|
33
|
+
this.#exclude = options.exclude ?? (() => false);
|
|
34
|
+
}
|
|
35
|
+
async *walkFiles(glob) {
|
|
36
|
+
const collected = [];
|
|
37
|
+
await git.walk({
|
|
38
|
+
fs: this.#fs,
|
|
39
|
+
dir: this.#dir,
|
|
40
|
+
trees: [git.TREE({ ref: this.ref })],
|
|
41
|
+
map: async (filepath, entries) => {
|
|
42
|
+
if (filepath === '.')
|
|
43
|
+
return undefined;
|
|
44
|
+
if (!entries)
|
|
45
|
+
return undefined;
|
|
46
|
+
const [entry] = entries;
|
|
47
|
+
if (!entry)
|
|
48
|
+
return undefined;
|
|
49
|
+
const type = await entry.type();
|
|
50
|
+
if (type !== 'blob')
|
|
51
|
+
return undefined;
|
|
52
|
+
const posix = filepath.split(sep).join('/');
|
|
53
|
+
if (this.#exclude(posix))
|
|
54
|
+
return undefined;
|
|
55
|
+
if (matchesGlob(posix, glob))
|
|
56
|
+
collected.push(posix);
|
|
57
|
+
return undefined;
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
for (const p of collected)
|
|
61
|
+
yield p;
|
|
62
|
+
}
|
|
63
|
+
async readFile(relativePath) {
|
|
64
|
+
const posix = this.#validateRel(relativePath);
|
|
65
|
+
const { blob } = await git.readBlob({
|
|
66
|
+
fs: this.#fs,
|
|
67
|
+
dir: this.#dir,
|
|
68
|
+
oid: this.ref,
|
|
69
|
+
filepath: posix,
|
|
70
|
+
});
|
|
71
|
+
return Buffer.from(blob);
|
|
72
|
+
}
|
|
73
|
+
async readText(relativePath) {
|
|
74
|
+
const buf = await this.readFile(relativePath);
|
|
75
|
+
return buf.toString('utf8');
|
|
76
|
+
}
|
|
77
|
+
#validateRel(relativePath) {
|
|
78
|
+
if (isAbsolute(relativePath)) {
|
|
79
|
+
throw new Error(`Snapshot.readFile: absolute paths are not allowed (${relativePath})`);
|
|
80
|
+
}
|
|
81
|
+
// Use a virtual root so `normalize`/`relative` behave consistently across
|
|
82
|
+
// platforms without touching the real fs.
|
|
83
|
+
const virtualRoot = '/__snap__';
|
|
84
|
+
const joined = normalize(join(virtualRoot, relativePath));
|
|
85
|
+
const rel = relative(virtualRoot, joined);
|
|
86
|
+
if (rel.startsWith('..') || isAbsolute(rel) || rel.split(sep).includes('..')) {
|
|
87
|
+
throw new Error(`Snapshot.readFile: path escapes snapshot root (${relativePath})`);
|
|
88
|
+
}
|
|
89
|
+
const posix = sep === '/' ? rel : rel.split(sep).join('/');
|
|
90
|
+
if (this.#exclude(posix)) {
|
|
91
|
+
throw new Error(`Snapshot.readFile: path is excluded from the snapshot (${relativePath})`);
|
|
92
|
+
}
|
|
93
|
+
return posix;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=git-snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-snapshot.js","sourceRoot":"","sources":["../../src/sources/git-snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal glob matcher + recursive directory walk.
|
|
3
|
+
*
|
|
4
|
+
* Supports the subset of glob syntax connectors actually need:
|
|
5
|
+
* - `*` matches any run of characters except `/`
|
|
6
|
+
* - `**` matches any run of characters including `/`
|
|
7
|
+
* - `?` matches exactly one character except `/`
|
|
8
|
+
* - Literal `.` `/` `_` `-` segments
|
|
9
|
+
*
|
|
10
|
+
* No brace-expansion, no `!` negation, no `[ ]` character classes. If a
|
|
11
|
+
* connector needs more, it can iterate `walkFiles("**\/*")` and filter in
|
|
12
|
+
* its own code — keeping the SDK surface small.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Recursive walk yielding POSIX-style relative paths (forward-slash).
|
|
16
|
+
* Skips dot-directories of the cache itself (`.lobu-cache`) but otherwise
|
|
17
|
+
* includes hidden files — git's `.git/` is excluded by callers that need
|
|
18
|
+
* to (git source uses a separate snapshot dir without `.git`).
|
|
19
|
+
*/
|
|
20
|
+
export declare function walkDirectoryRelative(root: string): AsyncIterable<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Compile a glob to a RegExp. Anchored on both ends.
|
|
23
|
+
*
|
|
24
|
+
* Implementation note: we walk the glob char-by-char rather than splitting on
|
|
25
|
+
* `*` so we can distinguish `*` from `**` without ambiguity, and so literal
|
|
26
|
+
* regex metacharacters get escaped exactly once.
|
|
27
|
+
*/
|
|
28
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
29
|
+
/** Test a POSIX-style relative path against `glob`. */
|
|
30
|
+
export declare function matchesGlob(relativePath: string, glob: string): boolean;
|
|
31
|
+
//# sourceMappingURL=glob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/sources/glob.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH;;;;;GAKG;AACH,wBAAuB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAwBhF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkDjD;AAYD,uDAAuD;AACvD,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKvE"}
|