@actana/sdk 0.2.2 → 0.3.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/README.md +54 -0
- package/dist/core-client.d.ts +99 -1
- package/dist/core-client.d.ts.map +1 -1
- package/dist/core-client.js +138 -2
- package/dist/core-client.js.map +1 -1
- package/dist/core-files-http.d.ts +94 -0
- package/dist/core-files-http.d.ts.map +1 -0
- package/dist/core-files-http.js +198 -0
- package/dist/core-files-http.js.map +1 -0
- package/dist/core-files.d.ts +227 -0
- package/dist/core-files.d.ts.map +1 -0
- package/dist/core-files.js +410 -0
- package/dist/core-files.js.map +1 -0
- package/dist/core-link-frames.d.ts +59 -0
- package/dist/core-link-frames.d.ts.map +1 -1
- package/dist/core-link-frames.js +35 -0
- package/dist/core-link-frames.js.map +1 -1
- package/dist/core-link-transport.d.ts.map +1 -1
- package/dist/core-link-transport.js +6 -0
- package/dist/core-link-transport.js.map +1 -1
- package/dist/core-project.d.ts +19 -0
- package/dist/core-project.d.ts.map +1 -0
- package/dist/core-project.js +38 -0
- package/dist/core-project.js.map +1 -0
- package/dist/core-registration-blob.d.ts +11 -0
- package/dist/core-registration-blob.d.ts.map +1 -1
- package/dist/core-registration-blob.js +5 -1
- package/dist/core-registration-blob.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { CoreLinkTlsMaterial } from "./core-link-socket.ts";
|
|
2
|
+
/** The refusal codes the Core's file routes answer with (`docs/external-api.md`). */
|
|
3
|
+
export type CoreFilesErrorCode = "unauthorized" | "not-found" | "project-not-found" | "method-not-allowed" | "bad-request" | "absolute-path" | "dot-dot-segment" | "outside-project-root" | "malformed-path" | "transfer-in-progress" | "insufficient-storage" | "corrupt-archive" | "absolute-entry-path" | "dot-dot-entry-path" | "root-entry-path" | "entry-outside-root" | "unsupported-entry-type" | "hardlink-outside-root" | "symlink-outside-root" | "directory-in-the-way" | "write-failed" | "read-failed";
|
|
4
|
+
/** Base class for everything `project.files.*` throws, so one `catch` can name it. */
|
|
5
|
+
export declare class CoreFilesError extends Error {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* This Core has no file surface (F9, #165's `files` capability).
|
|
10
|
+
*
|
|
11
|
+
* Thrown *before any request goes out*, which is the point: a client that
|
|
12
|
+
* called the route anyway would read a `404` off a Core that simply predates the
|
|
13
|
+
* surface and report it as an outage. The `reason` is prose for an operator
|
|
14
|
+
* because "unavailable" on its own sends somebody to check their network.
|
|
15
|
+
*/
|
|
16
|
+
export declare class CoreFilesUnavailableError extends CoreFilesError {
|
|
17
|
+
readonly reason: string;
|
|
18
|
+
constructor(reason: string);
|
|
19
|
+
}
|
|
20
|
+
/** A refusal with a status line: the Core answered, and said no. */
|
|
21
|
+
export declare class CoreFilesRequestError extends CoreFilesError {
|
|
22
|
+
readonly status: number;
|
|
23
|
+
readonly code: CoreFilesErrorCode | string;
|
|
24
|
+
constructor(status: number, code: CoreFilesErrorCode | string, message: string);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The one-write-per-Project rule (F8), as an error and **never as a retry**.
|
|
28
|
+
*
|
|
29
|
+
* `409 transfer-in-progress` is a conflict a human has to resolve — some other
|
|
30
|
+
* transfer is running on this Project right now, possibly a multi-gigabyte one
|
|
31
|
+
* with twenty minutes left. A client that retried under the hood would convert
|
|
32
|
+
* the Core's clear, immediate refusal into a hang with no output, which is
|
|
33
|
+
* strictly worse than the error: the operator loses both the reason and the
|
|
34
|
+
* chance to decide. So nothing in this package sleeps, backs off or re-sends —
|
|
35
|
+
* this class *is* the handling, and the decision is the caller's.
|
|
36
|
+
*
|
|
37
|
+
* `directory-in-the-way` shares the status and the same rule: it is a refusal
|
|
38
|
+
* to delete a tree, and it will still be a directory on the next attempt.
|
|
39
|
+
*/
|
|
40
|
+
export declare class CoreFilesConflictError extends CoreFilesRequestError {
|
|
41
|
+
constructor(status: number, code: CoreFilesErrorCode | string, message: string);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A failure that arrived as the **last line of a progress stream** rather than
|
|
45
|
+
* as a status code, because the `200` was spent on the first entry.
|
|
46
|
+
*
|
|
47
|
+
* This is why the progress stream is NDJSON and not a JSON document: a document
|
|
48
|
+
* would have to be well-formed to be read at all, and this one stops in the
|
|
49
|
+
* middle by design.
|
|
50
|
+
*/
|
|
51
|
+
export declare class CoreFilesStreamError extends CoreFilesError {
|
|
52
|
+
readonly code: CoreFilesErrorCode | string;
|
|
53
|
+
constructor(code: CoreFilesErrorCode | string, message: string);
|
|
54
|
+
}
|
|
55
|
+
/** One request, in the terms this surface actually uses. */
|
|
56
|
+
export type CoreFilesRequest = {
|
|
57
|
+
method: "GET" | "HEAD" | "PUT";
|
|
58
|
+
url: string;
|
|
59
|
+
headers: Record<string, string>;
|
|
60
|
+
/** A stream, never a buffer — see {@link CoreFiles.upload}. */
|
|
61
|
+
body?: ReadableStream<Uint8Array> | null;
|
|
62
|
+
signal?: AbortSignal;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* How a file request is actually sent.
|
|
66
|
+
*
|
|
67
|
+
* Injected rather than reached for, on the same terms as
|
|
68
|
+
* {@link CoreLinkSocketFactory}: it is what lets a suite drive this surface
|
|
69
|
+
* over a plain loopback server, and what lets a runtime with its own
|
|
70
|
+
* dispatcher — a proxy, a recorder, a browser — supply one. The default is
|
|
71
|
+
* {@link createCoreFilesFetch}.
|
|
72
|
+
*/
|
|
73
|
+
export type CoreFilesFetch = (req: CoreFilesRequest) => Promise<Response>;
|
|
74
|
+
/**
|
|
75
|
+
* The default sender: `fetch`, with the client certificate carried in on a
|
|
76
|
+
* dispatcher.
|
|
77
|
+
*
|
|
78
|
+
* The `Agent` is built **once, lazily, and only when there is TLS material** —
|
|
79
|
+
* a `http://` loopback Core needs no dispatcher, and building one per request
|
|
80
|
+
* would open a fresh connection pool for every upload.
|
|
81
|
+
*/
|
|
82
|
+
export declare function createCoreFilesFetch(tls: CoreLinkTlsMaterial | null): CoreFilesFetch;
|
|
83
|
+
/**
|
|
84
|
+
* Turn a non-2xx answer into the right error class, reading the `code` beside
|
|
85
|
+
* the prose rather than the prose.
|
|
86
|
+
*
|
|
87
|
+
* A client branches on `code` because a message is a sentence somebody will
|
|
88
|
+
* reword — and `transfer-in-progress` in particular *has* to stay
|
|
89
|
+
* distinguishable (F8). The body is read to completion here, and only here: a
|
|
90
|
+
* refusal body is a short JSON object, which is why buffering it does not
|
|
91
|
+
* violate the streaming rule the success paths keep.
|
|
92
|
+
*/
|
|
93
|
+
export declare function refusalFrom(res: Response, what: string): Promise<CoreFilesRequestError>;
|
|
94
|
+
//# sourceMappingURL=core-files-http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-files-http.d.ts","sourceRoot":"","sources":["../src/core-files-http.ts"],"names":[],"mappings":"AA2DA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,qFAAqF;AACrF,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,WAAW,GACX,mBAAmB,GACnB,oBAAoB,GACpB,aAAa,GACb,eAAe,GACf,iBAAiB,GACjB,sBAAsB,GACtB,gBAAgB,GAChB,sBAAsB,GACtB,sBAAsB,GACtB,iBAAiB,GACjB,qBAAqB,GACrB,oBAAoB,GACpB,iBAAiB,GACjB,oBAAoB,GACpB,wBAAwB,GACxB,uBAAuB,GACvB,sBAAsB,GACtB,sBAAsB,GACtB,cAAc,GACd,aAAa,CAAC;AAElB,sFAAsF;AACtF,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;GAOG;AACH,qBAAa,yBAA0B,SAAQ,cAAc;IAC3D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,MAAM;CAK3B;AAED,oEAAoE;AACpE,qBAAa,qBAAsB,SAAQ,cAAc;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAAC;gBAE/B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM;CAM/E;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,sBAAuB,SAAQ,qBAAqB;gBACnD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM;CAI/E;AAED;;;;;;;GAOG;AACH,qBAAa,oBAAqB,SAAQ,cAAc;IACtD,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAAC;gBAE/B,IAAI,EAAE,kBAAkB,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM;CAK/D;AAED,4DAA4D;AAC5D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,+DAA+D;IAC/D,IAAI,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE1E;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,mBAAmB,GAAG,IAAI,GAAG,cAAc,CA8BpF;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAe7F"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// The SDK's first HTTPS surface (#167, F12) — how a file request reaches a
|
|
2
|
+
// Core, and what a refusal from one means.
|
|
3
|
+
//
|
|
4
|
+
// Everything in this package before this module spoke one protocol: the
|
|
5
|
+
// core-link WebSocket. File bytes deliberately do not cross it (ADR 0028), so
|
|
6
|
+
// `project.files.*` dials the *same* mTLS server on the *same* port with the
|
|
7
|
+
// *same* certificate and bearer, over HTTP instead of a WebSocket upgrade.
|
|
8
|
+
// `CoreConnection.httpsBaseUrl` has named that origin since phase 1 precisely
|
|
9
|
+
// so this module would not be the thing that changed a published shape.
|
|
10
|
+
//
|
|
11
|
+
// ## The `fetch` shape is frozen, not chosen here
|
|
12
|
+
//
|
|
13
|
+
// The phase-1 spike (#151, PR 189) settled how a client certificate reaches
|
|
14
|
+
// `fetch` and its verdict is reused verbatim rather than rediscovered:
|
|
15
|
+
//
|
|
16
|
+
// const agent = new Agent({ connect: { ca, cert, key } });
|
|
17
|
+
// await fetch(url, { dispatcher: agent });
|
|
18
|
+
//
|
|
19
|
+
// **`fetch` is undici and ignores `options.cert` / `options.key`.** There is no
|
|
20
|
+
// option bag on `fetch` that reaches TLS at all — the dispatcher is the only
|
|
21
|
+
// seam. A client built the `https.request` way silently makes an *anonymous*
|
|
22
|
+
// connection, which a Core with `requestCert: true, rejectUnauthorized: true`
|
|
23
|
+
// refuses at the handshake with an error that names no certificate; that is a
|
|
24
|
+
// long debugging session, and it is the whole reason the spike exists. The
|
|
25
|
+
// spike's leg 2b is the control that makes the shape mean anything: the same
|
|
26
|
+
// `fetch` through a CA-only `Agent` is refused at the TLS layer. D12 also held
|
|
27
|
+
// — both legs pass on Node 22 — so this package's `engines: ">=22"` stands.
|
|
28
|
+
//
|
|
29
|
+
// ### One thing the spike could not have found, and this had to
|
|
30
|
+
//
|
|
31
|
+
// **The `fetch` above is undici's own, not the global one**, and the two are
|
|
32
|
+
// not interchangeable. Node embeds a *copy* of undici for its global `fetch`,
|
|
33
|
+
// and a `Dispatcher` only satisfies the implementation it came from: handing a
|
|
34
|
+
// dispatcher from the `undici` package to Node 24's built-in `fetch` fails with
|
|
35
|
+
// `InvalidArgumentError: invalid onRequestStart method`, because undici 8
|
|
36
|
+
// changed the handler interface that the embedded copy still expects. The
|
|
37
|
+
// spike never met this — it loaded `ws` and `undici` as a matching pair from
|
|
38
|
+
// one directory and used the global `fetch`, which happened to agree at those
|
|
39
|
+
// versions.
|
|
40
|
+
//
|
|
41
|
+
// Importing both halves from the same package is what makes that class of skew
|
|
42
|
+
// impossible rather than merely absent today: this package's `fetch` and its
|
|
43
|
+
// `Agent` are the same implementation, whatever Node bundles underneath. The
|
|
44
|
+
// frozen finding is untouched — the dispatcher is still the only seam, and the
|
|
45
|
+
// CA-only control still has to be refused — and `core-files-mtls.test.ts` holds
|
|
46
|
+
// both against a real handshake.
|
|
47
|
+
//
|
|
48
|
+
// ## Why `undici` is this package's second dependency
|
|
49
|
+
//
|
|
50
|
+
// `ws` is here because Node's global `WebSocket` cannot present a client
|
|
51
|
+
// certificate. `undici` is here for the identical reason one layer up: Node's
|
|
52
|
+
// global `fetch` cannot either, and the `Agent` that lets it is not exposed by
|
|
53
|
+
// any builtin. It is a public package on the registry, so unlike `@actana/shared`
|
|
54
|
+
// it is resolvable by everyone who installs this SDK — the boundary ADR 0025 D4
|
|
55
|
+
// draws is around *private workspace* packages, not around dependencies as such.
|
|
56
|
+
// A caller who never dials `https://` never constructs an `Agent`: the dispatcher
|
|
57
|
+
// is built lazily, on the first request that needs one.
|
|
58
|
+
import { Agent, fetch as undiciFetch } from "undici";
|
|
59
|
+
/** Base class for everything `project.files.*` throws, so one `catch` can name it. */
|
|
60
|
+
export class CoreFilesError extends Error {
|
|
61
|
+
constructor(message) {
|
|
62
|
+
super(message);
|
|
63
|
+
this.name = "CoreFilesError";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* This Core has no file surface (F9, #165's `files` capability).
|
|
68
|
+
*
|
|
69
|
+
* Thrown *before any request goes out*, which is the point: a client that
|
|
70
|
+
* called the route anyway would read a `404` off a Core that simply predates the
|
|
71
|
+
* surface and report it as an outage. The `reason` is prose for an operator
|
|
72
|
+
* because "unavailable" on its own sends somebody to check their network.
|
|
73
|
+
*/
|
|
74
|
+
export class CoreFilesUnavailableError extends CoreFilesError {
|
|
75
|
+
reason;
|
|
76
|
+
constructor(reason) {
|
|
77
|
+
super(reason);
|
|
78
|
+
this.name = "CoreFilesUnavailableError";
|
|
79
|
+
this.reason = reason;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** A refusal with a status line: the Core answered, and said no. */
|
|
83
|
+
export class CoreFilesRequestError extends CoreFilesError {
|
|
84
|
+
status;
|
|
85
|
+
code;
|
|
86
|
+
constructor(status, code, message) {
|
|
87
|
+
super(message);
|
|
88
|
+
this.name = "CoreFilesRequestError";
|
|
89
|
+
this.status = status;
|
|
90
|
+
this.code = code;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The one-write-per-Project rule (F8), as an error and **never as a retry**.
|
|
95
|
+
*
|
|
96
|
+
* `409 transfer-in-progress` is a conflict a human has to resolve — some other
|
|
97
|
+
* transfer is running on this Project right now, possibly a multi-gigabyte one
|
|
98
|
+
* with twenty minutes left. A client that retried under the hood would convert
|
|
99
|
+
* the Core's clear, immediate refusal into a hang with no output, which is
|
|
100
|
+
* strictly worse than the error: the operator loses both the reason and the
|
|
101
|
+
* chance to decide. So nothing in this package sleeps, backs off or re-sends —
|
|
102
|
+
* this class *is* the handling, and the decision is the caller's.
|
|
103
|
+
*
|
|
104
|
+
* `directory-in-the-way` shares the status and the same rule: it is a refusal
|
|
105
|
+
* to delete a tree, and it will still be a directory on the next attempt.
|
|
106
|
+
*/
|
|
107
|
+
export class CoreFilesConflictError extends CoreFilesRequestError {
|
|
108
|
+
constructor(status, code, message) {
|
|
109
|
+
super(status, code, message);
|
|
110
|
+
this.name = "CoreFilesConflictError";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A failure that arrived as the **last line of a progress stream** rather than
|
|
115
|
+
* as a status code, because the `200` was spent on the first entry.
|
|
116
|
+
*
|
|
117
|
+
* This is why the progress stream is NDJSON and not a JSON document: a document
|
|
118
|
+
* would have to be well-formed to be read at all, and this one stops in the
|
|
119
|
+
* middle by design.
|
|
120
|
+
*/
|
|
121
|
+
export class CoreFilesStreamError extends CoreFilesError {
|
|
122
|
+
code;
|
|
123
|
+
constructor(code, message) {
|
|
124
|
+
super(message);
|
|
125
|
+
this.name = "CoreFilesStreamError";
|
|
126
|
+
this.code = code;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The default sender: `fetch`, with the client certificate carried in on a
|
|
131
|
+
* dispatcher.
|
|
132
|
+
*
|
|
133
|
+
* The `Agent` is built **once, lazily, and only when there is TLS material** —
|
|
134
|
+
* a `http://` loopback Core needs no dispatcher, and building one per request
|
|
135
|
+
* would open a fresh connection pool for every upload.
|
|
136
|
+
*/
|
|
137
|
+
export function createCoreFilesFetch(tls) {
|
|
138
|
+
let dispatcher = null;
|
|
139
|
+
return async (req) => {
|
|
140
|
+
if (tls && !dispatcher) {
|
|
141
|
+
dispatcher = new Agent({ connect: { ca: tls.ca, cert: tls.cert, key: tls.key } });
|
|
142
|
+
}
|
|
143
|
+
// `duplex: "half"` is mandatory for a streamed request body and is not a
|
|
144
|
+
// detail that can be left out: without it `fetch` rejects the body outright,
|
|
145
|
+
// which would take this surface straight back to buffering an upload in
|
|
146
|
+
// memory — the one thing #167 exists to not do.
|
|
147
|
+
//
|
|
148
|
+
// The casts are the type-level shadow of the same two-copies problem the
|
|
149
|
+
// header describes: `@types/node` declares the global `fetch` with its own
|
|
150
|
+
// bundled `undici-types`, and this module deliberately uses the real
|
|
151
|
+
// package's `fetch` instead. The two `Response` and `RequestInit`
|
|
152
|
+
// declarations are structurally near-identical and neither is wrong — they
|
|
153
|
+
// are simply not the same declaration. Everything this package reads off a
|
|
154
|
+
// response (`ok`, `status`, `headers.get`, `json`, `body`) is common to
|
|
155
|
+
// both, and the global `Response` is what callers and tests hold, so that
|
|
156
|
+
// is the type this surface promises.
|
|
157
|
+
const init = {
|
|
158
|
+
method: req.method,
|
|
159
|
+
headers: req.headers,
|
|
160
|
+
...(req.body ? { body: req.body, duplex: "half" } : {}),
|
|
161
|
+
...(req.signal ? { signal: req.signal } : {}),
|
|
162
|
+
...(dispatcher ? { dispatcher } : {}),
|
|
163
|
+
};
|
|
164
|
+
const res = await undiciFetch(req.url, init);
|
|
165
|
+
return res;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Turn a non-2xx answer into the right error class, reading the `code` beside
|
|
170
|
+
* the prose rather than the prose.
|
|
171
|
+
*
|
|
172
|
+
* A client branches on `code` because a message is a sentence somebody will
|
|
173
|
+
* reword — and `transfer-in-progress` in particular *has* to stay
|
|
174
|
+
* distinguishable (F8). The body is read to completion here, and only here: a
|
|
175
|
+
* refusal body is a short JSON object, which is why buffering it does not
|
|
176
|
+
* violate the streaming rule the success paths keep.
|
|
177
|
+
*/
|
|
178
|
+
export async function refusalFrom(res, what) {
|
|
179
|
+
let code = "";
|
|
180
|
+
let message = "";
|
|
181
|
+
try {
|
|
182
|
+
const body = (await res.json());
|
|
183
|
+
if (typeof body.code === "string")
|
|
184
|
+
code = body.code;
|
|
185
|
+
if (typeof body.error === "string")
|
|
186
|
+
message = body.error;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// A refusal that is not the Core's JSON shape — a proxy's HTML error page,
|
|
190
|
+
// a truncated body. Say what is actually known rather than inventing a code.
|
|
191
|
+
}
|
|
192
|
+
const described = message || `${what} was refused with HTTP ${res.status}`;
|
|
193
|
+
const withCode = code ? `${described} (${code})` : described;
|
|
194
|
+
if (res.status === 409)
|
|
195
|
+
return new CoreFilesConflictError(res.status, code || "conflict", withCode);
|
|
196
|
+
return new CoreFilesRequestError(res.status, code || `http-${res.status}`, withCode);
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=core-files-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-files-http.js","sourceRoot":"","sources":["../src/core-files-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { type CoreFilesFetch } from "./core-files-http.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Whether this Core's file surface may be used at all, and — when it may not —
|
|
4
|
+
* why, in words an operator can act on (F9).
|
|
5
|
+
*/
|
|
6
|
+
export type CoreFilesAvailability = {
|
|
7
|
+
available: true;
|
|
8
|
+
} | {
|
|
9
|
+
available: false;
|
|
10
|
+
reason: string;
|
|
11
|
+
};
|
|
12
|
+
/** How a written entry landed. `overwritten` names a file that was already there (F5). */
|
|
13
|
+
export type CoreFileWriteResult = "written" | "overwritten";
|
|
14
|
+
/**
|
|
15
|
+
* One entry of a listing, in the manifest shape PR 215 established: `{path,
|
|
16
|
+
* size, mtime, mode, sha256}`.
|
|
17
|
+
*
|
|
18
|
+
* `path` is **Project-relative**, which is the address space F1 gives the
|
|
19
|
+
* operator — the same string that goes back to `download`.
|
|
20
|
+
*
|
|
21
|
+
* `sha256` is nullable on purpose, and the Core settled which way it means:
|
|
22
|
+
* hashing every entry of a large tree is expensive, so a listing computes
|
|
23
|
+
* digests **on request** ({@link CoreFileListOptions.sha256}) and a transfer
|
|
24
|
+
* computes them eagerly, the bytes being already in hand. So `null` reads as
|
|
25
|
+
* "no bytes" for a directory and "nobody asked" for anything else.
|
|
26
|
+
*/
|
|
27
|
+
export type CoreFileEntry = {
|
|
28
|
+
path: string;
|
|
29
|
+
size: number;
|
|
30
|
+
mtime: number;
|
|
31
|
+
mode: number;
|
|
32
|
+
sha256: string | null;
|
|
33
|
+
/** Present when the listing distinguishes them; absent listings read as files. */
|
|
34
|
+
kind?: "file" | "directory" | "symlink";
|
|
35
|
+
};
|
|
36
|
+
/** One line of a write's NDJSON progress stream. */
|
|
37
|
+
export type CoreFileProgress = ({
|
|
38
|
+
type: "entry";
|
|
39
|
+
result: CoreFileWriteResult;
|
|
40
|
+
} & CoreFileEntry) | {
|
|
41
|
+
type: "done";
|
|
42
|
+
entries: number;
|
|
43
|
+
bytes: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* What a read hands back: metadata, and **a stream**.
|
|
47
|
+
*
|
|
48
|
+
* There is no `bytes` or `buffer` field here and that absence is the feature.
|
|
49
|
+
* A gigabyte file must not materialise in memory, so the only way to get at the
|
|
50
|
+
* content is to consume `stream` — a caller who wants it whole has to write
|
|
51
|
+
* that themselves and own the decision. `size` is what the Core declared, which
|
|
52
|
+
* is `null` for a folder, whose tar length is not known until it has been walked.
|
|
53
|
+
*/
|
|
54
|
+
export type CoreFileDownload = {
|
|
55
|
+
/** `file` for raw bytes, `tar` for a folder crossing as one archive (ADR 0029). */
|
|
56
|
+
kind: "file" | "tar";
|
|
57
|
+
size: number | null;
|
|
58
|
+
mode: number | null;
|
|
59
|
+
mtime: number | null;
|
|
60
|
+
stream: ReadableStream<Uint8Array>;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Anything a caller can upload.
|
|
64
|
+
*
|
|
65
|
+
* A Node `Readable` — `fs.createReadStream(…)` — is an async iterable of
|
|
66
|
+
* `Buffer`, so it is accepted directly and without this package importing
|
|
67
|
+
* `node:stream` to say so. A web `ReadableStream` passes through untouched.
|
|
68
|
+
*/
|
|
69
|
+
export type CoreFileSource = ReadableStream<Uint8Array> | AsyncIterable<Uint8Array | string>;
|
|
70
|
+
export type CoreFileUploadOptions = {
|
|
71
|
+
/** Project-relative destination. `""` is the Project root, which only a tar may target. */
|
|
72
|
+
path: string;
|
|
73
|
+
body: CoreFileSource;
|
|
74
|
+
/**
|
|
75
|
+
* `file` writes one file at `path`; `tar` unpacks an archive into it
|
|
76
|
+
* (ADR 0029). Default `file`.
|
|
77
|
+
*/
|
|
78
|
+
kind?: "file" | "tar";
|
|
79
|
+
/** Unix permission bits for a single-file write. The Core defaults to `0o644`. */
|
|
80
|
+
mode?: number;
|
|
81
|
+
/** Modification time in epoch milliseconds, preserved across the wire. */
|
|
82
|
+
mtime?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Declared body length, when the caller knows it.
|
|
85
|
+
*
|
|
86
|
+
* Worth passing: it is what lets the Core run its free-space precheck and
|
|
87
|
+
* refuse `507 insufficient-storage` before the transfer rather than fail with
|
|
88
|
+
* `ENOSPC` half-way through. Omitted, the upload is chunked and there is
|
|
89
|
+
* nothing to check against.
|
|
90
|
+
*/
|
|
91
|
+
contentLength?: number;
|
|
92
|
+
signal?: AbortSignal;
|
|
93
|
+
};
|
|
94
|
+
export type CoreFileDownloadOptions = {
|
|
95
|
+
/** Project-relative path. A directory comes back as one streamed tar. */
|
|
96
|
+
path: string;
|
|
97
|
+
signal?: AbortSignal;
|
|
98
|
+
};
|
|
99
|
+
export type CoreFileListOptions = {
|
|
100
|
+
/** Subtree to list, Project-relative. Default: the whole Project. */
|
|
101
|
+
path?: string;
|
|
102
|
+
/** Maximum depth to descend. `1` is the immediate children. Default: the whole tree. */
|
|
103
|
+
depth?: number;
|
|
104
|
+
/**
|
|
105
|
+
* Ask the Core to compute {@link CoreFileEntry.sha256} for every file and
|
|
106
|
+
* symlink under the path. **Off by default, and not free**: a listing does not
|
|
107
|
+
* have the bytes in hand, so digests mean reading every one of them (ADR 0027
|
|
108
|
+
* D6). Left off, every `sha256` comes back `null`.
|
|
109
|
+
*/
|
|
110
|
+
sha256?: boolean;
|
|
111
|
+
signal?: AbortSignal;
|
|
112
|
+
};
|
|
113
|
+
export type CoreFilesOptions = {
|
|
114
|
+
projectId: string;
|
|
115
|
+
/** The Core's HTTPS origin — `CoreConnection.httpsBaseUrl`. No trailing slash. */
|
|
116
|
+
baseUrl: string;
|
|
117
|
+
/** The same signed bearer the core link's `auth` frame presents, or null on a loopback rig. */
|
|
118
|
+
bearer: string | null;
|
|
119
|
+
/**
|
|
120
|
+
* Read at the top of every call rather than once at construction: a Core can
|
|
121
|
+
* be downgraded and a client survives reconnects, so the answer belongs to
|
|
122
|
+
* the *current* connection and a remembered one would send a caller at a route
|
|
123
|
+
* that is no longer there.
|
|
124
|
+
*/
|
|
125
|
+
availability: () => CoreFilesAvailability;
|
|
126
|
+
fetch: CoreFilesFetch;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* A Project's files, over the Core's HTTPS routes.
|
|
130
|
+
*
|
|
131
|
+
* Reached as `client.project(id).files` rather than constructed directly.
|
|
132
|
+
*/
|
|
133
|
+
export declare class CoreFiles {
|
|
134
|
+
private readonly opts;
|
|
135
|
+
constructor(opts: CoreFilesOptions);
|
|
136
|
+
/**
|
|
137
|
+
* The Project's tree, one entry at a time.
|
|
138
|
+
*
|
|
139
|
+
* Reads the Core's real listing route — `GET …/files/list`, see
|
|
140
|
+
* {@link listUrl} — which streams `{path, kind, size, mtime, mode, sha256}`
|
|
141
|
+
* per entry as NDJSON. `core-files-list-contract.test.ts` drives this method
|
|
142
|
+
* against that route in process and runs in **both** packages' suites, so the
|
|
143
|
+
* two halves of the URL cannot drift apart again without a red test (#218).
|
|
144
|
+
*
|
|
145
|
+
* Both line shapes are accepted — a bare manifest entry and one wrapped as
|
|
146
|
+
* `{type: "entry", …}`, which is what the Core's listing and its write route
|
|
147
|
+
* both emit. `skipped` lines are passed over: a path the walk could not read
|
|
148
|
+
* is a fact about the tree, not an entry in it, and not a reason to stop.
|
|
149
|
+
*/
|
|
150
|
+
list(opts?: CoreFileListOptions): AsyncGenerator<CoreFileEntry, void, undefined>;
|
|
151
|
+
/**
|
|
152
|
+
* Write a stream into the Project, and watch it land.
|
|
153
|
+
*
|
|
154
|
+
* The returned iterable is the Core's NDJSON progress stream, parsed: one
|
|
155
|
+
* `entry` line per file — each carrying `result: "written" | "overwritten"`,
|
|
156
|
+
* so **every overwrite is named** rather than inferred — then one `done` line
|
|
157
|
+
* with the totals.
|
|
158
|
+
*
|
|
159
|
+
* **Lazy, like everything else here.** Calling `upload` sends nothing; the
|
|
160
|
+
* request goes out on the first `next()`. A caller who does not care about
|
|
161
|
+
* progress still has to drain the iterable, and that is the honest shape: the
|
|
162
|
+
* alternative is a method that returns a promise and quietly buffers a
|
|
163
|
+
* gigabyte of progress nobody read.
|
|
164
|
+
*
|
|
165
|
+
* Throws {@link CoreFilesConflictError} when another write already holds this
|
|
166
|
+
* Project's lease (F8) — immediately, and without retrying. Throws
|
|
167
|
+
* {@link CoreFilesStreamError} when the write fails part-way through, which
|
|
168
|
+
* arrives as the stream's last line rather than as a status code, the `200`
|
|
169
|
+
* having been spent on the first entry.
|
|
170
|
+
*/
|
|
171
|
+
upload(opts: CoreFileUploadOptions): AsyncGenerator<CoreFileProgress, void, undefined>;
|
|
172
|
+
/**
|
|
173
|
+
* Read a file — or a folder, as one streamed tar — **as a stream**.
|
|
174
|
+
*
|
|
175
|
+
* The response body is handed through untouched. Nothing on this path calls
|
|
176
|
+
* `arrayBuffer`, `text` or `blob`, so a gigabyte file crosses in whatever
|
|
177
|
+
* chunks the socket delivers and only ever occupies what the consumer has not
|
|
178
|
+
* yet read. `core-files-streaming.test.ts` holds that claim to a real
|
|
179
|
+
* gigabyte and watches the heap while it crosses.
|
|
180
|
+
*
|
|
181
|
+
* The metadata comes off headers the Core already had — `stat` on the file it
|
|
182
|
+
* was about to open — so nothing is read twice to produce it.
|
|
183
|
+
*/
|
|
184
|
+
download(opts: CoreFileDownloadOptions): Promise<CoreFileDownload>;
|
|
185
|
+
/**
|
|
186
|
+
* `…/v1/projects/:projectId/files/list?path=<relative>` — a route of its own.
|
|
187
|
+
*
|
|
188
|
+
* This module used to send `?list=1` on the read route instead, and argued for
|
|
189
|
+
* it on cost: the Core's `parseRoute` matched `/v1/projects/:id/files` on an
|
|
190
|
+
* exact four-segment split, so a `…/files/list` leaf was a change to that
|
|
191
|
+
* parser and a query parameter was not. That cost is now paid — #216 shipped a
|
|
192
|
+
* parser that reads the fifth segment — and what is left is the Core's
|
|
193
|
+
* argument, which was never about cost: a listing and a read of the same
|
|
194
|
+
* folder answer with completely different things, one a manifest and one a
|
|
195
|
+
* tar. A query parameter that a proxy, a redirect or a hand-edited URL can
|
|
196
|
+
* drop turns "list this folder" into "download this folder", which for a
|
|
197
|
+
* `node_modules` is a mistake measured in gigabytes rather than in a 400. A
|
|
198
|
+
* path segment cannot be dropped silently. See issue 218.
|
|
199
|
+
*
|
|
200
|
+
* Still `protected`: a caller pinned to an older Core can subclass rather than
|
|
201
|
+
* wait for a release.
|
|
202
|
+
*/
|
|
203
|
+
protected listUrl(opts: CoreFileListOptions): string;
|
|
204
|
+
/** `…/v1/projects/:projectId/files?path=<relative>` — the read and write route. */
|
|
205
|
+
protected fileUrl(filePath: string): string;
|
|
206
|
+
/**
|
|
207
|
+
* `<baseUrl>/v1/projects/:projectId/<leaf>`, with the Project id escaped.
|
|
208
|
+
*
|
|
209
|
+
* The two routes above differ by their leaf and by nothing else, and that is
|
|
210
|
+
* worth having in one place: the day this surface gains a third, the origin,
|
|
211
|
+
* the version prefix and the escaping should not be a third opportunity to get
|
|
212
|
+
* one of them subtly wrong.
|
|
213
|
+
*/
|
|
214
|
+
private routeUrl;
|
|
215
|
+
private authHeaders;
|
|
216
|
+
/**
|
|
217
|
+
* The F9 gate, checked before every call and *before any byte leaves*.
|
|
218
|
+
*
|
|
219
|
+
* The reason is carried into the error rather than flattened to a boolean,
|
|
220
|
+
* because the two ways this fails want different actions from an operator: a
|
|
221
|
+
* Core that has not finished connecting is a wait, and a Core that announced
|
|
222
|
+
* no `files` capability is a Core that predates the surface — which is a
|
|
223
|
+
* supported state, not a fault and not a needs-update.
|
|
224
|
+
*/
|
|
225
|
+
private requireAvailable;
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=core-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-files.d.ts","sourceRoot":"","sources":["../src/core-files.ts"],"names":[],"mappings":"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"}
|