oblien 2.2.37 → 2.2.39
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 +2 -0
- package/dist/cdn.d.ts +135 -0
- package/dist/cdn.d.ts.map +1 -0
- package/dist/cdn.js +251 -0
- package/dist/cdn.js.map +1 -0
- package/dist/cli/commands/cdn.d.ts +3 -0
- package/dist/cli/commands/cdn.d.ts.map +1 -0
- package/dist/cli/commands/cdn.js +216 -0
- package/dist/cli/commands/cdn.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +17 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +113 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/tunnel.d.ts +1 -0
- package/dist/cli/commands/tunnel.d.ts.map +1 -1
- package/dist/cli/commands/tunnel.js +100 -3
- package/dist/cli/commands/tunnel.js.map +1 -1
- package/dist/cli/index.js +14 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/client.d.ts +5 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +7 -0
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +48 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/runtime/proxy.d.ts +55 -0
- package/dist/runtime/proxy.d.ts.map +1 -0
- package/dist/runtime/proxy.js +79 -0
- package/dist/runtime/proxy.js.map +1 -0
- package/dist/runtime.d.ts +16 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +18 -0
- package/dist/runtime.js.map +1 -1
- package/dist/server/static.d.ts +81 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +465 -0
- package/dist/server/static.js.map +1 -0
- package/dist/types/cdn.d.ts +368 -0
- package/dist/types/cdn.d.ts.map +1 -0
- package/dist/types/cdn.js +10 -0
- package/dist/types/cdn.js.map +1 -0
- package/dist/types/client.d.ts +10 -0
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/docs/cdn.md +119 -0
- package/docs/runtime.md +30 -0
- package/docs/serve.md +84 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -61,6 +61,7 @@ The client wraps every part of the platform. Each feature has a deep-dive page i
|
|
|
61
61
|
| **Webhooks** | `client.webhooks` | Subscribe to events; HMAC-signed, namespace-scopable | [docs/webhooks](./docs/webhooks.md) |
|
|
62
62
|
| **Analytics** | `client.analytics` | Edge traffic — requests, bandwidth, geo, live stream | [docs/analytics](./docs/analytics.md) |
|
|
63
63
|
| **Scoped Tokens** | `client.tokens` | Short-lived, per-tenant scoped JWTs | [docs/tokens](./docs/tokens.md) |
|
|
64
|
+
| **CDN** | `client.cdn` | Upload files, mint upload tokens, manage stored files (namespace-aware) | [docs/cdn](./docs/cdn.md) |
|
|
64
65
|
| **Errors** | `import { OblienError, … }` | Typed error classes for every HTTP status | [docs/errors](./docs/errors.md) |
|
|
65
66
|
|
|
66
67
|
### Map at a glance
|
|
@@ -84,6 +85,7 @@ client
|
|
|
84
85
|
### Also included
|
|
85
86
|
|
|
86
87
|
- **CLI** — `npx oblien …` (auth, workspaces, exec, scp, terminal, tunnels, …). See [CLI docs](https://oblien.com/docs/cli).
|
|
88
|
+
- **Static server** — `oblien serve ./public` serves a folder and puts it on a public URL through the edge tunnel; also exported as `startStaticServer()`. Zero dependencies. See [docs/serve](./docs/serve.md).
|
|
87
89
|
- **MCP server** — `oblien-mcp` exposes the SDK as Model Context Protocol tools for agents. See [MCP docs](https://oblien.com/docs/mcp).
|
|
88
90
|
|
|
89
91
|
---
|
package/dist/cdn.d.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { HttpClient } from './http.js';
|
|
2
|
+
import type { CdnTokenParams, CdnTokenResponse, CdnUploadInput, CdnUploadParams, CdnUploadResponse, CdnUploadManyResponse, CdnProcessUrlsParams, CdnProcessUrlsResponse, CdnLimitsResponse, CdnVariantOptionsResponse, CdnListParams, CdnListResponse, CdnStatsParams, CdnStatsResponse, CdnFileResponse, CdnUsageParams, CdnUsageResponse, CdnUsageSeriesParams, CdnUsageSeriesResponse, CdnDomainAddParams, CdnDomainAddResponse, CdnDomainListParams, CdnDomainListResponse, CdnDomainRemoveResponse } from './types/cdn.js';
|
|
3
|
+
import type { ApiResponse } from './types/common.js';
|
|
4
|
+
/**
|
|
5
|
+
* CDN — issue upload tokens, upload files, and manage stored files.
|
|
6
|
+
*
|
|
7
|
+
* The CDN spans two planes. Token issuance and file management go through the
|
|
8
|
+
* API host (`client._http`); uploads go directly to the CDN edge host with a
|
|
9
|
+
* short-lived token. Every operation is namespace-aware: pass `namespace` to
|
|
10
|
+
* scope a token/upload/listing, or omit it (admin/dashboard callers see all of
|
|
11
|
+
* their files). Namespace-scoped API keys are automatically pinned to their
|
|
12
|
+
* own namespace by the server.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import Oblien from 'oblien';
|
|
16
|
+
* import { readFileSync } from 'node:fs';
|
|
17
|
+
* const client = new Oblien({ clientId, clientSecret });
|
|
18
|
+
*
|
|
19
|
+
* // One-shot: mints a token and uploads, scoped to a namespace
|
|
20
|
+
* const { url } = await client.cdn.upload(
|
|
21
|
+
* { data: readFileSync('./logo.png'), filename: 'logo.png', contentType: 'image/png' },
|
|
22
|
+
* { namespace: 'tenant-a' },
|
|
23
|
+
* );
|
|
24
|
+
*
|
|
25
|
+
* // List / stats for that namespace
|
|
26
|
+
* const { data } = await client.cdn.list({ namespace: 'tenant-a' });
|
|
27
|
+
* await client.cdn.stats({ namespace: 'tenant-a' });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare class Cdn {
|
|
31
|
+
/** @internal */
|
|
32
|
+
readonly _http: HttpClient;
|
|
33
|
+
/** @internal — CDN edge base, incl. the `/api` mount (e.g. https://cdn.oblien.com/api). */
|
|
34
|
+
private readonly _cdnBaseUrl;
|
|
35
|
+
private readonly _base;
|
|
36
|
+
/** Manage custom delivery domains for the account's CDN hosts. */
|
|
37
|
+
readonly domains: CdnDomains;
|
|
38
|
+
constructor(client: {
|
|
39
|
+
_http: HttpClient;
|
|
40
|
+
_cdnBaseUrl: string;
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Mint a short-lived (1 min) USER-scope CDN token (upload + process).
|
|
44
|
+
* Requires an admin- or namespace-scoped API key.
|
|
45
|
+
*/
|
|
46
|
+
token(params?: CdnTokenParams): Promise<CdnTokenResponse>;
|
|
47
|
+
/**
|
|
48
|
+
* Mint a short-lived ADMIN-scope CDN token (full edge access incl. delete).
|
|
49
|
+
* Requires an admin API key.
|
|
50
|
+
*/
|
|
51
|
+
adminToken(params?: CdnTokenParams): Promise<CdnTokenResponse>;
|
|
52
|
+
/**
|
|
53
|
+
* Upload a single file to the CDN edge. Mints a user token automatically
|
|
54
|
+
* (bound to `params.namespace`, carrying `params.metadata` — variant/TTL
|
|
55
|
+
* options), or reuses `params.token` if given.
|
|
56
|
+
*/
|
|
57
|
+
upload(file: CdnUploadInput, params?: CdnUploadParams): Promise<CdnUploadResponse>;
|
|
58
|
+
/**
|
|
59
|
+
* Upload multiple files in one request (field `files`). Mints a single token
|
|
60
|
+
* for the batch, bound to `params.namespace` and carrying `params.metadata`.
|
|
61
|
+
*/
|
|
62
|
+
uploadMany(files: CdnUploadInput[], params?: CdnUploadParams): Promise<CdnUploadManyResponse>;
|
|
63
|
+
/**
|
|
64
|
+
* Ingest files from remote URLs (edge downloads + processes them). Variant
|
|
65
|
+
* options travel in the token metadata (the edge reads them from the permit),
|
|
66
|
+
* so `metadata` is baked into the auto-minted token; the request body only
|
|
67
|
+
* carries `urls` + batch controls.
|
|
68
|
+
*/
|
|
69
|
+
processUrls(params: CdnProcessUrlsParams): Promise<CdnProcessUrlsResponse>;
|
|
70
|
+
/** Get the edge upload size/count limits. Mints a user token if none given. */
|
|
71
|
+
getLimits(params?: {
|
|
72
|
+
token?: string;
|
|
73
|
+
namespace?: string;
|
|
74
|
+
}): Promise<CdnLimitsResponse>;
|
|
75
|
+
/** Get the available image variant configurations. Mints a user token if none given. */
|
|
76
|
+
getVariantOptions(params?: {
|
|
77
|
+
token?: string;
|
|
78
|
+
namespace?: string;
|
|
79
|
+
}): Promise<CdnVariantOptionsResponse>;
|
|
80
|
+
/** List logged files for the caller, optionally filtered by namespace. */
|
|
81
|
+
list(params?: CdnListParams): Promise<CdnListResponse>;
|
|
82
|
+
/** Storage statistics for the caller, optionally scoped to a namespace. */
|
|
83
|
+
stats(params?: CdnStatsParams): Promise<CdnStatsResponse>;
|
|
84
|
+
/**
|
|
85
|
+
* Per-namespace usage for a month: ingest (uploaded in the month, incl.
|
|
86
|
+
* variants) + current active footprint, and the configured caps.
|
|
87
|
+
*/
|
|
88
|
+
usage(params?: CdnUsageParams): Promise<CdnUsageResponse>;
|
|
89
|
+
/**
|
|
90
|
+
* Windowed ingest series (bytes/files uploaded per day or month), zero-filled
|
|
91
|
+
* over the window — for usage charts.
|
|
92
|
+
*/
|
|
93
|
+
usageSeries(params?: CdnUsageSeriesParams): Promise<CdnUsageSeriesResponse>;
|
|
94
|
+
/** Get a single logged file by its id. */
|
|
95
|
+
get(fileId: number | string): Promise<CdnFileResponse>;
|
|
96
|
+
/** Soft-delete a logged file. */
|
|
97
|
+
delete(fileId: number | string): Promise<ApiResponse>;
|
|
98
|
+
/** Restore a soft-deleted file. */
|
|
99
|
+
restore(fileId: number | string): Promise<ApiResponse>;
|
|
100
|
+
/**
|
|
101
|
+
* Call the CDN edge host with a Bearer token. Uploads pass a `FormData`
|
|
102
|
+
* body; JSON endpoints pass a plain object. Mirrors HttpClient's
|
|
103
|
+
* body-first error handling and reuses the shared error builder.
|
|
104
|
+
*/
|
|
105
|
+
private _edgeRequest;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Custom CDN delivery domains (`client.cdn.domains`).
|
|
109
|
+
*
|
|
110
|
+
* Connect your own domain (e.g. `cdn.yourbrand.com`) to a namespace and serve
|
|
111
|
+
* its files from it instead of the auto `<label>.cdn.oblien.com` subdomain.
|
|
112
|
+
* `add` runs the DNS-ownership + ACME pipeline; if DNS isn't pointed yet it
|
|
113
|
+
* returns the exact records to set (in `dns.required_records`) — point the
|
|
114
|
+
* domain (CNAME → `edge.oblien.com`, TXT `_opsh.<domain>` = `verify=<ns-id>`)
|
|
115
|
+
* and call `add` again.
|
|
116
|
+
*
|
|
117
|
+
* ```ts
|
|
118
|
+
* await client.cdn.domains.add({ namespace: 'tenant-a', domain: 'cdn.acme.com' });
|
|
119
|
+
* const { domains } = await client.cdn.domains.list({ namespace: 'tenant-a' });
|
|
120
|
+
* await client.cdn.domains.remove('cdn.acme.com');
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export declare class CdnDomains {
|
|
124
|
+
/** @internal */
|
|
125
|
+
readonly _http: HttpClient;
|
|
126
|
+
private readonly _base;
|
|
127
|
+
constructor(http: HttpClient);
|
|
128
|
+
/** Connect a custom delivery domain to a namespace (DNS verify + ACME + route). */
|
|
129
|
+
add(params: CdnDomainAddParams): Promise<CdnDomainAddResponse>;
|
|
130
|
+
/** List the account's CDN hosts (custom domains + the auto subdomain). */
|
|
131
|
+
list(params?: CdnDomainListParams): Promise<CdnDomainListResponse>;
|
|
132
|
+
/** Disconnect a custom CDN domain (the auto subdomain cannot be removed). */
|
|
133
|
+
remove(domain: string): Promise<CdnDomainRemoveResponse>;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=cdn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"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"}
|
package/dist/cdn.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { buildOblienError } from './http-error.js';
|
|
2
|
+
/** Coerce arbitrary file bytes into a Blob suitable for multipart upload. */
|
|
3
|
+
function toBlob(input) {
|
|
4
|
+
if (input.data instanceof Blob)
|
|
5
|
+
return input.data;
|
|
6
|
+
const type = input.contentType || 'application/octet-stream';
|
|
7
|
+
return new Blob([input.data], { type });
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* CDN — issue upload tokens, upload files, and manage stored files.
|
|
11
|
+
*
|
|
12
|
+
* The CDN spans two planes. Token issuance and file management go through the
|
|
13
|
+
* API host (`client._http`); uploads go directly to the CDN edge host with a
|
|
14
|
+
* short-lived token. Every operation is namespace-aware: pass `namespace` to
|
|
15
|
+
* scope a token/upload/listing, or omit it (admin/dashboard callers see all of
|
|
16
|
+
* their files). Namespace-scoped API keys are automatically pinned to their
|
|
17
|
+
* own namespace by the server.
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import Oblien from 'oblien';
|
|
21
|
+
* import { readFileSync } from 'node:fs';
|
|
22
|
+
* const client = new Oblien({ clientId, clientSecret });
|
|
23
|
+
*
|
|
24
|
+
* // One-shot: mints a token and uploads, scoped to a namespace
|
|
25
|
+
* const { url } = await client.cdn.upload(
|
|
26
|
+
* { data: readFileSync('./logo.png'), filename: 'logo.png', contentType: 'image/png' },
|
|
27
|
+
* { namespace: 'tenant-a' },
|
|
28
|
+
* );
|
|
29
|
+
*
|
|
30
|
+
* // List / stats for that namespace
|
|
31
|
+
* const { data } = await client.cdn.list({ namespace: 'tenant-a' });
|
|
32
|
+
* await client.cdn.stats({ namespace: 'tenant-a' });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class Cdn {
|
|
36
|
+
/** @internal */
|
|
37
|
+
_http;
|
|
38
|
+
/** @internal — CDN edge base, incl. the `/api` mount (e.g. https://cdn.oblien.com/api). */
|
|
39
|
+
_cdnBaseUrl;
|
|
40
|
+
_base = '/cdn';
|
|
41
|
+
/** Manage custom delivery domains for the account's CDN hosts. */
|
|
42
|
+
domains;
|
|
43
|
+
constructor(client) {
|
|
44
|
+
this._http = client._http;
|
|
45
|
+
this._cdnBaseUrl = client._cdnBaseUrl;
|
|
46
|
+
this.domains = new CdnDomains(client._http);
|
|
47
|
+
}
|
|
48
|
+
// ── Token issuance (API plane) ─────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* Mint a short-lived (1 min) USER-scope CDN token (upload + process).
|
|
51
|
+
* Requires an admin- or namespace-scoped API key.
|
|
52
|
+
*/
|
|
53
|
+
async token(params = {}) {
|
|
54
|
+
return this._http.request({
|
|
55
|
+
method: 'POST',
|
|
56
|
+
path: `${this._base}/token`,
|
|
57
|
+
body: params,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Mint a short-lived ADMIN-scope CDN token (full edge access incl. delete).
|
|
62
|
+
* Requires an admin API key.
|
|
63
|
+
*/
|
|
64
|
+
async adminToken(params = {}) {
|
|
65
|
+
return this._http.request({
|
|
66
|
+
method: 'POST',
|
|
67
|
+
path: `${this._base}/token/admin`,
|
|
68
|
+
body: params,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// ── Upload (edge plane) ────────────────────────────────────────────
|
|
72
|
+
/**
|
|
73
|
+
* Upload a single file to the CDN edge. Mints a user token automatically
|
|
74
|
+
* (bound to `params.namespace`, carrying `params.metadata` — variant/TTL
|
|
75
|
+
* options), or reuses `params.token` if given.
|
|
76
|
+
*/
|
|
77
|
+
async upload(file, params = {}) {
|
|
78
|
+
const token = params.token ?? (await this.token({ namespace: params.namespace, variants: params.variants, metadata: params.metadata })).token;
|
|
79
|
+
const form = new FormData();
|
|
80
|
+
form.append('file', toBlob(file), file.filename);
|
|
81
|
+
return this._edgeRequest('POST', '/', token, form);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Upload multiple files in one request (field `files`). Mints a single token
|
|
85
|
+
* for the batch, bound to `params.namespace` and carrying `params.metadata`.
|
|
86
|
+
*/
|
|
87
|
+
async uploadMany(files, params = {}) {
|
|
88
|
+
const token = params.token ?? (await this.token({ namespace: params.namespace, variants: params.variants, metadata: params.metadata })).token;
|
|
89
|
+
const form = new FormData();
|
|
90
|
+
for (const file of files) {
|
|
91
|
+
form.append('files', toBlob(file), file.filename);
|
|
92
|
+
}
|
|
93
|
+
return this._edgeRequest('POST', '/multiple', token, form);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Ingest files from remote URLs (edge downloads + processes them). Variant
|
|
97
|
+
* options travel in the token metadata (the edge reads them from the permit),
|
|
98
|
+
* so `metadata` is baked into the auto-minted token; the request body only
|
|
99
|
+
* carries `urls` + batch controls.
|
|
100
|
+
*/
|
|
101
|
+
async processUrls(params) {
|
|
102
|
+
const { token: reuse, namespace, variants, metadata, urls, maxBatch, concurrency } = params;
|
|
103
|
+
const token = reuse ?? (await this.token({ namespace, variants, metadata })).token;
|
|
104
|
+
return this._edgeRequest('POST', '/process-urls', token, { urls, maxBatch, concurrency });
|
|
105
|
+
}
|
|
106
|
+
/** Get the edge upload size/count limits. Mints a user token if none given. */
|
|
107
|
+
async getLimits(params = {}) {
|
|
108
|
+
const token = params.token ?? (await this.token({ namespace: params.namespace })).token;
|
|
109
|
+
return this._edgeRequest('GET', '/limits', token);
|
|
110
|
+
}
|
|
111
|
+
/** Get the available image variant configurations. Mints a user token if none given. */
|
|
112
|
+
async getVariantOptions(params = {}) {
|
|
113
|
+
const token = params.token ?? (await this.token({ namespace: params.namespace })).token;
|
|
114
|
+
return this._edgeRequest('GET', '/variants', token);
|
|
115
|
+
}
|
|
116
|
+
// ── File management (API plane) ────────────────────────────────────
|
|
117
|
+
/** List logged files for the caller, optionally filtered by namespace. */
|
|
118
|
+
async list(params = {}) {
|
|
119
|
+
return this._http.request({
|
|
120
|
+
method: 'GET',
|
|
121
|
+
path: `${this._base}/files`,
|
|
122
|
+
query: params,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/** Storage statistics for the caller, optionally scoped to a namespace. */
|
|
126
|
+
async stats(params = {}) {
|
|
127
|
+
return this._http.request({
|
|
128
|
+
method: 'GET',
|
|
129
|
+
path: `${this._base}/stats`,
|
|
130
|
+
query: params,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Per-namespace usage for a month: ingest (uploaded in the month, incl.
|
|
135
|
+
* variants) + current active footprint, and the configured caps.
|
|
136
|
+
*/
|
|
137
|
+
async usage(params = {}) {
|
|
138
|
+
return this._http.request({
|
|
139
|
+
method: 'GET',
|
|
140
|
+
path: `${this._base}/usage`,
|
|
141
|
+
query: params,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Windowed ingest series (bytes/files uploaded per day or month), zero-filled
|
|
146
|
+
* over the window — for usage charts.
|
|
147
|
+
*/
|
|
148
|
+
async usageSeries(params = {}) {
|
|
149
|
+
return this._http.request({
|
|
150
|
+
method: 'GET',
|
|
151
|
+
path: `${this._base}/usage/series`,
|
|
152
|
+
query: params,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/** Get a single logged file by its id. */
|
|
156
|
+
async get(fileId) {
|
|
157
|
+
return this._http.request({
|
|
158
|
+
method: 'GET',
|
|
159
|
+
path: `${this._base}/files/${fileId}`,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/** Soft-delete a logged file. */
|
|
163
|
+
async delete(fileId) {
|
|
164
|
+
return this._http.request({
|
|
165
|
+
method: 'DELETE',
|
|
166
|
+
path: `${this._base}/files/${fileId}`,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/** Restore a soft-deleted file. */
|
|
170
|
+
async restore(fileId) {
|
|
171
|
+
return this._http.request({
|
|
172
|
+
method: 'POST',
|
|
173
|
+
path: `${this._base}/files/${fileId}/restore`,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// ── Internals ──────────────────────────────────────────────────────
|
|
177
|
+
/**
|
|
178
|
+
* Call the CDN edge host with a Bearer token. Uploads pass a `FormData`
|
|
179
|
+
* body; JSON endpoints pass a plain object. Mirrors HttpClient's
|
|
180
|
+
* body-first error handling and reuses the shared error builder.
|
|
181
|
+
*/
|
|
182
|
+
async _edgeRequest(method, path, token, body) {
|
|
183
|
+
const url = `${this._cdnBaseUrl}${path}`;
|
|
184
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
185
|
+
const init = { method, headers };
|
|
186
|
+
if (body instanceof FormData) {
|
|
187
|
+
init.body = body; // fetch sets the multipart boundary content-type
|
|
188
|
+
}
|
|
189
|
+
else if (body !== undefined) {
|
|
190
|
+
headers['Content-Type'] = 'application/json';
|
|
191
|
+
init.body = JSON.stringify(body);
|
|
192
|
+
}
|
|
193
|
+
const res = await fetch(url, init);
|
|
194
|
+
const parsed = await res.json().catch(() => null);
|
|
195
|
+
if (parsed && typeof parsed === 'object' && parsed.success === false) {
|
|
196
|
+
throw buildOblienError(res.status, parsed);
|
|
197
|
+
}
|
|
198
|
+
if (!res.ok && res.status >= 400) {
|
|
199
|
+
throw buildOblienError(res.status, parsed);
|
|
200
|
+
}
|
|
201
|
+
return parsed;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Custom CDN delivery domains (`client.cdn.domains`).
|
|
206
|
+
*
|
|
207
|
+
* Connect your own domain (e.g. `cdn.yourbrand.com`) to a namespace and serve
|
|
208
|
+
* its files from it instead of the auto `<label>.cdn.oblien.com` subdomain.
|
|
209
|
+
* `add` runs the DNS-ownership + ACME pipeline; if DNS isn't pointed yet it
|
|
210
|
+
* returns the exact records to set (in `dns.required_records`) — point the
|
|
211
|
+
* domain (CNAME → `edge.oblien.com`, TXT `_opsh.<domain>` = `verify=<ns-id>`)
|
|
212
|
+
* and call `add` again.
|
|
213
|
+
*
|
|
214
|
+
* ```ts
|
|
215
|
+
* await client.cdn.domains.add({ namespace: 'tenant-a', domain: 'cdn.acme.com' });
|
|
216
|
+
* const { domains } = await client.cdn.domains.list({ namespace: 'tenant-a' });
|
|
217
|
+
* await client.cdn.domains.remove('cdn.acme.com');
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
export class CdnDomains {
|
|
221
|
+
/** @internal */
|
|
222
|
+
_http;
|
|
223
|
+
_base = '/cdn/domains';
|
|
224
|
+
constructor(http) {
|
|
225
|
+
this._http = http;
|
|
226
|
+
}
|
|
227
|
+
/** Connect a custom delivery domain to a namespace (DNS verify + ACME + route). */
|
|
228
|
+
async add(params) {
|
|
229
|
+
return this._http.request({
|
|
230
|
+
method: 'POST',
|
|
231
|
+
path: this._base,
|
|
232
|
+
body: params,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/** List the account's CDN hosts (custom domains + the auto subdomain). */
|
|
236
|
+
async list(params = {}) {
|
|
237
|
+
return this._http.request({
|
|
238
|
+
method: 'GET',
|
|
239
|
+
path: this._base,
|
|
240
|
+
query: params,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/** Disconnect a custom CDN domain (the auto subdomain cannot be removed). */
|
|
244
|
+
async remove(domain) {
|
|
245
|
+
return this._http.request({
|
|
246
|
+
method: 'DELETE',
|
|
247
|
+
path: `${this._base}/${encodeURIComponent(domain)}`,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=cdn.js.map
|
package/dist/cdn.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.js","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/cdn.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAwD3C,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA6C3E"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { basename, extname } from 'node:path';
|
|
3
|
+
import { buildClient } from '../auth.js';
|
|
4
|
+
import { printResult, printSuccess } from '../output.js';
|
|
5
|
+
import { parseFlag, parseNumber, requireId, isHelp } from './helpers.js';
|
|
6
|
+
/** Minimal extension → MIME map so uploads declare a sensible content type. */
|
|
7
|
+
const MIME_BY_EXT = {
|
|
8
|
+
'.png': 'image/png',
|
|
9
|
+
'.jpg': 'image/jpeg',
|
|
10
|
+
'.jpeg': 'image/jpeg',
|
|
11
|
+
'.gif': 'image/gif',
|
|
12
|
+
'.webp': 'image/webp',
|
|
13
|
+
'.svg': 'image/svg+xml',
|
|
14
|
+
'.pdf': 'application/pdf',
|
|
15
|
+
'.json': 'application/json',
|
|
16
|
+
'.txt': 'text/plain',
|
|
17
|
+
'.csv': 'text/csv',
|
|
18
|
+
'.mp4': 'video/mp4',
|
|
19
|
+
'.webm': 'video/webm',
|
|
20
|
+
'.mp3': 'audio/mpeg',
|
|
21
|
+
};
|
|
22
|
+
function inferContentType(filename) {
|
|
23
|
+
return MIME_BY_EXT[extname(filename).toLowerCase()] || 'application/octet-stream';
|
|
24
|
+
}
|
|
25
|
+
function parseJsonObjectFlag(args, flag) {
|
|
26
|
+
const raw = parseFlag(args, flag);
|
|
27
|
+
if (!raw)
|
|
28
|
+
return undefined;
|
|
29
|
+
try {
|
|
30
|
+
const v = JSON.parse(raw);
|
|
31
|
+
if (v && typeof v === 'object' && !Array.isArray(v))
|
|
32
|
+
return v;
|
|
33
|
+
}
|
|
34
|
+
catch { /* fall through to the error below */ }
|
|
35
|
+
console.error(`${flag} must be a JSON object`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build the API-issued variant directives from flags: `--variants <json>` is the
|
|
40
|
+
* full object (incl. customVariants); `--names`, `--ttl`, `--primary` are
|
|
41
|
+
* convenience overlays on top of it.
|
|
42
|
+
*/
|
|
43
|
+
function buildVariants(args) {
|
|
44
|
+
const v = { ...(parseJsonObjectFlag(args, '--variants') ?? {}) };
|
|
45
|
+
const names = parseFlag(args, '--names');
|
|
46
|
+
if (names)
|
|
47
|
+
v.variantNames = names.split(',').map(s => s.trim()).filter(Boolean);
|
|
48
|
+
const ttl = parseNumber(args, '--ttl');
|
|
49
|
+
if (ttl !== undefined)
|
|
50
|
+
v.ttl = ttl;
|
|
51
|
+
const primary = parseFlag(args, '--primary');
|
|
52
|
+
if (primary)
|
|
53
|
+
v.primary = primary;
|
|
54
|
+
return Object.keys(v).length ? v : undefined;
|
|
55
|
+
}
|
|
56
|
+
/** Opaque customer metadata from `--meta <json>` (stored + echoed, not interpreted). */
|
|
57
|
+
function buildMeta(args) {
|
|
58
|
+
return parseJsonObjectFlag(args, '--meta');
|
|
59
|
+
}
|
|
60
|
+
export async function cdnCmd(args, flags) {
|
|
61
|
+
const sub = args[0];
|
|
62
|
+
switch (sub) {
|
|
63
|
+
case 'token': return cdnToken(args.slice(1), flags, 'user');
|
|
64
|
+
case 'admin-token': return cdnToken(args.slice(1), flags, 'admin');
|
|
65
|
+
case 'upload': return cdnUpload(args.slice(1), flags);
|
|
66
|
+
case 'list': return cdnList(args.slice(1), flags);
|
|
67
|
+
case 'stats': return cdnStats(args.slice(1), flags);
|
|
68
|
+
case 'limits': return cdnLimits(args.slice(1), flags);
|
|
69
|
+
case 'get': return cdnGet(args.slice(1), flags);
|
|
70
|
+
case 'delete': return cdnDelete(args.slice(1), flags);
|
|
71
|
+
case 'restore': return cdnRestore(args.slice(1), flags);
|
|
72
|
+
default:
|
|
73
|
+
if (!isHelp(sub))
|
|
74
|
+
console.error(`Unknown cdn subcommand: ${sub}\n`);
|
|
75
|
+
console.log(`
|
|
76
|
+
oblien cdn - CDN uploads and file management (namespace-aware)
|
|
77
|
+
|
|
78
|
+
Usage:
|
|
79
|
+
oblien cdn upload <file> [--namespace <slug>] [--content-type <type>]
|
|
80
|
+
[--names a,b] [--variants <json>] [--ttl <sec>] [--primary <name>] [--meta <json>]
|
|
81
|
+
oblien cdn token [--namespace <slug>] [--names a,b] [--variants <json>] [--ttl <sec>]
|
|
82
|
+
oblien cdn admin-token [--namespace <slug>] Mint an ADMIN-scope token
|
|
83
|
+
oblien cdn list [--namespace <slug>] [--limit <n>] [--page <n>] [--include-deleted]
|
|
84
|
+
oblien cdn stats [--namespace <slug>]
|
|
85
|
+
oblien cdn limits
|
|
86
|
+
oblien cdn get <file-id>
|
|
87
|
+
oblien cdn delete <file-id>
|
|
88
|
+
oblien cdn restore <file-id>
|
|
89
|
+
|
|
90
|
+
Variants are API-issued into the token (chosen per request; no server presets):
|
|
91
|
+
--names a,b variant names to generate (default sizes for known names)
|
|
92
|
+
--variants '<json>' full directives, incl. customVariants, e.g.
|
|
93
|
+
'{"variantNames":["hero"],"customVariants":{"hero":{"width":800,"height":400}}}'
|
|
94
|
+
--ttl <sec> auto-delete the upload after N seconds
|
|
95
|
+
--meta '<json>' OPAQUE customer metadata (stored + echoed, not interpreted)
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
oblien cdn upload ./logo.png --namespace tenant-a --names thumb,medium
|
|
99
|
+
oblien cdn upload ./a.png --variants '{"variantNames":["sq"],"customVariants":{"sq":{"width":200,"height":200}}}'
|
|
100
|
+
oblien cdn upload ./tmp.png --ttl 3600 --meta '{"orderId":"abc123"}'
|
|
101
|
+
oblien cdn list --namespace tenant-a --json
|
|
102
|
+
oblien cdn delete 42
|
|
103
|
+
`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function cdnToken(args, flags, scope) {
|
|
107
|
+
const namespace = parseFlag(args, '--namespace');
|
|
108
|
+
const variants = buildVariants(args);
|
|
109
|
+
const metadata = buildMeta(args);
|
|
110
|
+
const client = buildClient(flags);
|
|
111
|
+
const res = scope === 'admin'
|
|
112
|
+
? await client.cdn.adminToken({ namespace, variants, metadata })
|
|
113
|
+
: await client.cdn.token({ namespace, variants, metadata });
|
|
114
|
+
if (flags.json) {
|
|
115
|
+
printResult(res, true);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
printSuccess(`CDN ${res.scope} token minted${res.namespace ? ` (namespace: ${res.namespace})` : ''}, expires in ${res.expiresIn}`);
|
|
119
|
+
console.log(`\nToken:\n${res.token}\n`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function cdnUpload(args, flags) {
|
|
123
|
+
// Find the file positional, skipping value-taking flags and their values so
|
|
124
|
+
// `cdn upload --namespace ns ./file` works, not just `cdn upload ./file ...`.
|
|
125
|
+
const valueFlags = new Set(['--namespace', '--content-type', '--variants', '--names', '--meta', '--ttl', '--primary']);
|
|
126
|
+
let filePath;
|
|
127
|
+
for (let i = 0; i < args.length; i++) {
|
|
128
|
+
if (valueFlags.has(args[i])) {
|
|
129
|
+
i++;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (!args[i].startsWith('-')) {
|
|
133
|
+
filePath = args[i];
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (!filePath) {
|
|
138
|
+
console.error('Usage: oblien cdn upload <file> [--namespace <slug>] [--content-type <type>] [--names a,b] [--variants <json>] [--ttl <sec>] [--meta <json>]');
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
const namespace = parseFlag(args, '--namespace');
|
|
142
|
+
const filename = basename(filePath);
|
|
143
|
+
const contentType = parseFlag(args, '--content-type') || inferContentType(filename);
|
|
144
|
+
const variants = buildVariants(args);
|
|
145
|
+
const metadata = buildMeta(args);
|
|
146
|
+
const data = readFileSync(filePath);
|
|
147
|
+
const client = buildClient(flags);
|
|
148
|
+
const res = await client.cdn.upload({ data, filename, contentType }, { namespace, variants, metadata });
|
|
149
|
+
if (flags.json) {
|
|
150
|
+
printResult(res, true);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
printSuccess(`Uploaded ${filename}${namespace ? ` to namespace ${namespace}` : ''}`);
|
|
154
|
+
console.log(`\nURL: ${res.url}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function cdnList(args, flags) {
|
|
158
|
+
const client = buildClient(flags);
|
|
159
|
+
const res = await client.cdn.list({
|
|
160
|
+
namespace: parseFlag(args, '--namespace'),
|
|
161
|
+
page: parseNumber(args, '--page'),
|
|
162
|
+
limit: parseNumber(args, '--limit'),
|
|
163
|
+
include_deleted: args.includes('--include-deleted') || undefined,
|
|
164
|
+
upload_type: parseFlag(args, '--upload-type'),
|
|
165
|
+
});
|
|
166
|
+
if (flags.json) {
|
|
167
|
+
printResult(res, true);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const files = res.data?.files ?? [];
|
|
171
|
+
printResult(files.map(f => ({
|
|
172
|
+
id: f.id,
|
|
173
|
+
namespace: f.namespace ?? '-',
|
|
174
|
+
filename: f.filename,
|
|
175
|
+
size: f.size,
|
|
176
|
+
type: f.upload_type,
|
|
177
|
+
deleted: f.is_deleted,
|
|
178
|
+
url: f.cdn_url,
|
|
179
|
+
})), false);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function cdnStats(args, flags) {
|
|
183
|
+
const client = buildClient(flags);
|
|
184
|
+
const res = await client.cdn.stats({ namespace: parseFlag(args, '--namespace') });
|
|
185
|
+
printResult(flags.json ? res : res.data, flags.json);
|
|
186
|
+
}
|
|
187
|
+
async function cdnLimits(_args, flags) {
|
|
188
|
+
const client = buildClient(flags);
|
|
189
|
+
const res = await client.cdn.getLimits();
|
|
190
|
+
printResult(res, flags.json);
|
|
191
|
+
}
|
|
192
|
+
async function cdnGet(args, flags) {
|
|
193
|
+
const fileId = requireId(args[0], 'cdn get <file-id>');
|
|
194
|
+
const client = buildClient(flags);
|
|
195
|
+
const res = await client.cdn.get(fileId);
|
|
196
|
+
printResult(flags.json ? res : res.data, flags.json);
|
|
197
|
+
}
|
|
198
|
+
async function cdnDelete(args, flags) {
|
|
199
|
+
const fileId = requireId(args[0], 'cdn delete <file-id>');
|
|
200
|
+
const client = buildClient(flags);
|
|
201
|
+
const res = await client.cdn.delete(fileId);
|
|
202
|
+
if (flags.json)
|
|
203
|
+
printResult(res, true);
|
|
204
|
+
else
|
|
205
|
+
printSuccess(`File ${fileId} deleted`);
|
|
206
|
+
}
|
|
207
|
+
async function cdnRestore(args, flags) {
|
|
208
|
+
const fileId = requireId(args[0], 'cdn restore <file-id>');
|
|
209
|
+
const client = buildClient(flags);
|
|
210
|
+
const res = await client.cdn.restore(fileId);
|
|
211
|
+
if (flags.json)
|
|
212
|
+
printResult(res, true);
|
|
213
|
+
else
|
|
214
|
+
printSuccess(`File ${fileId} restored`);
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=cdn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.js","sourceRoot":"","sources":["../../../src/cli/commands/cdn.ts"],"names":[],"mappings":"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"}
|