@degallery/node 0.2.2 → 0.4.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 +98 -6
- package/dist/lib/node.d.ts +9 -4
- package/dist/lib/node.d.ts.map +1 -1
- package/dist/lib/node.js +37 -2
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,11 +1,103 @@
|
|
|
1
|
-
# node
|
|
1
|
+
# `@degallery/node`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Node.js helpers for trusted DeGallery integrations. Use this package at a server boundary when you need the framework-neutral `@degallery/sdk` client plus Node-specific signing utilities.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This package is not a browser UI library and must not be included in a public client bundle.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Product and developer links
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- [DeGallery landing page](https://degallery.dev)
|
|
10
|
+
- [Developer documentation](https://docs.degallery.dev)
|
|
11
|
+
- [JavaScript installation](https://docs.degallery.dev/docs/javascript/installation)
|
|
12
|
+
- [Production readiness](https://docs.degallery.dev/docs/guides/production-readiness)
|
|
13
|
+
- [Private gallery authorization](https://docs.degallery.dev/docs/how-to/authorize-a-private-gallery)
|
|
14
|
+
- [Image delivery guide](https://docs.degallery.dev/docs/how-to/track-delivery)
|
|
15
|
+
- [Live demo](https://demo.degallery.dev)
|
|
16
|
+
- [Dashboard](https://app.degallery.dev)
|
|
17
|
+
- [Source repository](https://github.com/mmpotulo28/thegallery)
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add @degallery/node
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The package re-exports `GalleryClient` and selected public SDK types:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { GalleryClient, type GallerySummary } from '@degallery/node';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Configure a server client
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { GalleryClient } from '@degallery/node';
|
|
35
|
+
|
|
36
|
+
const client = new GalleryClient({
|
|
37
|
+
apiUrl: process.env.DEGALLERY_API_URL ?? 'https://api.degallery.dev',
|
|
38
|
+
apiKey: process.env.DEGALLERY_API_KEY,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const gallery = await client.getGallery('gallery-id-or-slug');
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Keep `DEGALLERY_API_KEY` in the server secret manager. Never use a `NEXT_PUBLIC_*` variable for a private credential and never return the credential to a browser.
|
|
45
|
+
|
|
46
|
+
For the full client surface, see the [`@degallery/sdk` README](../sdk/README.md) and the [JavaScript client documentation](https://docs.degallery.dev/docs/javascript/get-started).
|
|
47
|
+
|
|
48
|
+
## Create a delivery token
|
|
49
|
+
|
|
50
|
+
`createDeliveryToken` creates a signed token for a delivery resource. Keep the signing secret private and issue tokens only after your server has authorized the requested resource:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { createDeliveryToken } from '@degallery/node';
|
|
54
|
+
|
|
55
|
+
const token = createDeliveryToken(
|
|
56
|
+
{
|
|
57
|
+
organizationId: 'organization-id',
|
|
58
|
+
environmentId: 'environment-id',
|
|
59
|
+
resource: 'asset-id',
|
|
60
|
+
revision: 3,
|
|
61
|
+
preset: 'large',
|
|
62
|
+
expiresAt: Math.floor(Date.now() / 1000) + 300,
|
|
63
|
+
keyId: 'v1',
|
|
64
|
+
},
|
|
65
|
+
process.env.DEGALLERY_DELIVERY_SECRET!,
|
|
66
|
+
);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The helper signs the Worker-compatible claims (`iss`, `aud`, `org`, `env`, `resource`, `revision`, `preset`, `iat`, `exp`, and `kid`) with HMAC-SHA256. `expiresAt` is a Unix timestamp in seconds and the lifetime cannot exceed 15 minutes. The token is not an authorization policy by itself: validate ownership, visibility, expiry, and requested transformations before issuing it. Never issue a private delivery token in browser code.
|
|
70
|
+
|
|
71
|
+
## What this package exports
|
|
72
|
+
|
|
73
|
+
- `GalleryClient` from `@degallery/sdk`
|
|
74
|
+
- `Asset`, `GalleryDetail`, `GalleryLinkPayload`, and `GallerySummary` types
|
|
75
|
+
- `createDeliveryToken`
|
|
76
|
+
- `node`, the package health-check export
|
|
77
|
+
|
|
78
|
+
For uploads, use the SDK intent flow from the server:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const intent = await client.createUpload({
|
|
82
|
+
filename: 'image.jpg',
|
|
83
|
+
contentType: 'image/jpeg',
|
|
84
|
+
size: bytes.byteLength,
|
|
85
|
+
visibility: 'private',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await fetch(intent.uploadUrl, {
|
|
89
|
+
method: intent.method ?? 'PUT',
|
|
90
|
+
headers: { 'Content-Type': intent.contentType ?? 'image/jpeg' },
|
|
91
|
+
body: bytes,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await client.completeUpload(intent.intentId);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Runtime guidance
|
|
98
|
+
|
|
99
|
+
- Run this package only in Node.js or another trusted server runtime.
|
|
100
|
+
- Store API and delivery secrets in a managed secret store.
|
|
101
|
+
- Keep delivery tokens short-lived.
|
|
102
|
+
- Do not log signed URLs, API keys, or delivery tokens.
|
|
103
|
+
- Treat client-provided asset IDs and presets as untrusted input.
|
package/dist/lib/node.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
export { GalleryClient } from '@degallery/sdk';
|
|
2
2
|
export type { Asset, GalleryDetail, GalleryLinkPayload, GallerySummary, } from '@degallery/sdk';
|
|
3
3
|
export declare function node(): string;
|
|
4
|
-
export
|
|
5
|
-
|
|
4
|
+
export type DeliveryTokenInput = Readonly<{
|
|
5
|
+
organizationId: string;
|
|
6
6
|
environmentId: string;
|
|
7
|
-
|
|
7
|
+
resource: string;
|
|
8
|
+
revision: number;
|
|
9
|
+
preset: 'original' | 'thumbnail' | 'large';
|
|
8
10
|
expiresAt: number;
|
|
9
|
-
|
|
11
|
+
issuedAt?: number;
|
|
12
|
+
keyId?: string;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function createDeliveryToken(input: DeliveryTokenInput, secret: string): string;
|
|
10
15
|
//# sourceMappingURL=node.d.ts.map
|
package/dist/lib/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/lib/node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EACV,KAAK,EACL,aAAa,EACb,kBAAkB,EAClB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/lib/node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EACV,KAAK,EACL,aAAa,EACb,kBAAkB,EAClB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,UA0C5E"}
|
package/dist/lib/node.js
CHANGED
|
@@ -10,6 +10,41 @@ function node() {
|
|
|
10
10
|
return 'node';
|
|
11
11
|
}
|
|
12
12
|
function createDeliveryToken(input, secret) {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
if (!secret)
|
|
14
|
+
throw new TypeError('A delivery signing secret is required.');
|
|
15
|
+
const issuedAt = input.issuedAt ?? Math.floor(Date.now() / 1000);
|
|
16
|
+
const lifetime = input.expiresAt - issuedAt;
|
|
17
|
+
const keyId = input.keyId ?? 'v1';
|
|
18
|
+
if (!input.organizationId ||
|
|
19
|
+
input.organizationId.length > 128 ||
|
|
20
|
+
!input.environmentId ||
|
|
21
|
+
input.environmentId.length > 128 ||
|
|
22
|
+
!input.resource ||
|
|
23
|
+
input.resource.length > 128 ||
|
|
24
|
+
!Number.isSafeInteger(input.revision) ||
|
|
25
|
+
input.revision < 1 ||
|
|
26
|
+
!['original', 'thumbnail', 'large'].includes(input.preset) ||
|
|
27
|
+
!Number.isSafeInteger(issuedAt) ||
|
|
28
|
+
!Number.isSafeInteger(input.expiresAt) ||
|
|
29
|
+
!keyId ||
|
|
30
|
+
keyId.length > 128 ||
|
|
31
|
+
lifetime < 1 ||
|
|
32
|
+
lifetime > 900)
|
|
33
|
+
throw new TypeError('Delivery token claims are invalid.');
|
|
34
|
+
const payload = Buffer.from(JSON.stringify({
|
|
35
|
+
iss: 'thegallery',
|
|
36
|
+
aud: 'media-delivery',
|
|
37
|
+
org: input.organizationId,
|
|
38
|
+
env: input.environmentId,
|
|
39
|
+
resource: input.resource,
|
|
40
|
+
revision: input.revision,
|
|
41
|
+
preset: input.preset,
|
|
42
|
+
iat: issuedAt,
|
|
43
|
+
exp: input.expiresAt,
|
|
44
|
+
kid: keyId,
|
|
45
|
+
})).toString('base64url');
|
|
46
|
+
const signature = (0, node_crypto_1.createHmac)('sha256', secret)
|
|
47
|
+
.update(payload)
|
|
48
|
+
.digest('base64url');
|
|
49
|
+
return `${payload}.${signature}`;
|
|
15
50
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@degallery/node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"lib:publish": "npm publish --access public"
|
|
9
|
-
},
|
|
10
7
|
"exports": {
|
|
11
8
|
"./package.json": "./package.json",
|
|
12
9
|
".": {
|
|
@@ -22,6 +19,9 @@
|
|
|
22
19
|
],
|
|
23
20
|
"dependencies": {
|
|
24
21
|
"tslib": "^2.3.0",
|
|
25
|
-
"@degallery/sdk": "
|
|
22
|
+
"@degallery/sdk": "0.4.0"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"lib:publish": "pnpm publish --access public"
|
|
26
26
|
}
|
|
27
|
-
}
|
|
27
|
+
}
|