@geniee-inc/sfa-kit 1.14.1 → 1.17.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/GUIDE.md +131 -12
- package/package.json +19 -2
- package/src/bin/sfa-kit-bundle.d.ts +13 -0
- package/src/bin/sfa-kit-bundle.js +142 -0
- package/src/bundle.d.ts +26 -0
- package/src/bundle.js +1 -0
- package/src/lib/auth/ObjectKeyGuard.d.ts +12 -0
- package/src/lib/auth/ObjectKeyGuard.js +61 -0
- package/src/lib/auth/SfaLoginGate.js +5 -4
- package/src/lib/bundle/build-static-bundle.d.ts +45 -0
- package/src/lib/bundle/build-static-bundle.js +263 -0
- package/src/lib/bundle/esbuild-loader.d.ts +25 -0
- package/src/lib/bundle/esbuild-loader.js +27 -0
- package/src/lib/bundle/index.d.ts +2 -0
- package/src/lib/bundle/index.js +1 -0
- package/src/lib/bundle/request-signature.d.ts +22 -0
- package/src/lib/bundle/request-signature.js +81 -0
- package/src/lib/hooks/splitBulkRows.d.ts +8 -4
- package/src/lib/hooks/splitBulkRows.js +17 -4
- package/src/lib/hooks/useBulkCreateRecords.d.ts +8 -3
- package/src/lib/hooks/useBulkCreateRecords.js +5 -2
- package/src/lib/hooks/useBulkDeleteRecords.d.ts +14 -1
- package/src/lib/hooks/useBulkDeleteRecords.js +4 -0
- package/src/lib/hooks/useBulkUpdateRecords.d.ts +8 -2
- package/src/lib/hooks/useBulkUpdateRecords.js +3 -1
- package/src/lib/provider/SfaClient.d.ts +1 -0
- package/src/lib/provider/SfaClient.js +18 -5
- package/src/lib/provider/types.d.ts +19 -3
- package/src/lib/signing/compute-content-hash.d.ts +1 -1
- package/src/lib/signing/compute-signature.d.ts +17 -0
- package/src/lib/signing/compute-signature.js +17 -0
- package/src/lib/signing/create-manifest-from-directory.d.ts +13 -3
- package/src/lib/signing/create-manifest-from-directory.js +15 -28
- package/src/lib/signing/create-manifest.d.ts +7 -1
- package/src/lib/signing/create-manifest.js +8 -2
- package/src/lib/signing/index.d.ts +6 -5
- package/src/lib/signing/index.js +5 -4
- package/src/lib/signing/read-bundle-files.d.ts +19 -0
- package/src/lib/signing/read-bundle-files.js +41 -0
- package/src/lib/version.d.ts +1 -1
- package/src/lib/version.js +1 -1
- package/src/signing.d.ts +9 -4
- package/src/signing.js +1 -1
|
@@ -59,6 +59,7 @@ export class SfaClient {
|
|
|
59
59
|
/** In-memory cache for describe results, keyed by objectKey. Stores Promises
|
|
60
60
|
* so concurrent callers share a single in-flight request. */
|
|
61
61
|
this.describeCache = new Map();
|
|
62
|
+
this.listObjectsCache = null;
|
|
62
63
|
this.apiBase = this.resolveBase(config.apiBase.replace(/\/+$/, ''), config.mode);
|
|
63
64
|
this.auth = config.auth;
|
|
64
65
|
this.mode = config.mode;
|
|
@@ -174,11 +175,21 @@ export class SfaClient {
|
|
|
174
175
|
}
|
|
175
176
|
listObjects() {
|
|
176
177
|
return __awaiter(this, void 0, void 0, function* () {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
178
|
+
if (this.listObjectsCache)
|
|
179
|
+
return this.listObjectsCache;
|
|
180
|
+
const promise = this.fetchGet(this.objectsPath())
|
|
181
|
+
.then(raw => {
|
|
182
|
+
var _a;
|
|
183
|
+
const data = raw;
|
|
184
|
+
const objects = ((_a = data.objects) !== null && _a !== void 0 ? _a : []).map(o => normalizeObjectSummary(o));
|
|
185
|
+
return { objects };
|
|
186
|
+
})
|
|
187
|
+
.catch((err) => {
|
|
188
|
+
this.listObjectsCache = null;
|
|
189
|
+
throw err;
|
|
190
|
+
});
|
|
191
|
+
this.listObjectsCache = promise;
|
|
192
|
+
return promise;
|
|
182
193
|
});
|
|
183
194
|
}
|
|
184
195
|
listFieldTypes() {
|
|
@@ -1040,6 +1051,8 @@ function readBulkRowStatus(raw) {
|
|
|
1040
1051
|
conflict: 'conflict',
|
|
1041
1052
|
invalid: 'invalid',
|
|
1042
1053
|
not_attempted: 'not_attempted',
|
|
1054
|
+
not_found: 'not_found',
|
|
1055
|
+
not_permitted: 'not_permitted',
|
|
1043
1056
|
indeterminate: 'indeterminate',
|
|
1044
1057
|
};
|
|
1045
1058
|
return typeof raw === 'string' ? (_a = known[raw]) !== null && _a !== void 0 ? _a : 'unknown' : 'unknown';
|
|
@@ -103,13 +103,19 @@ export interface SfaFieldError {
|
|
|
103
103
|
* All are reported per row with HTTP 200 — a bulk call is best-effort and has
|
|
104
104
|
* no all-or-nothing mode.
|
|
105
105
|
*
|
|
106
|
+
* `not_found` and `not_permitted` are refusals of a row the call did reach:
|
|
107
|
+
* the record it named does not exist, or the caller may not write it. No write
|
|
108
|
+
* happened either way, so both are settled failures and reach the caller in
|
|
109
|
+
* `failed`. Sending them again is safe, but returns the same answer until the
|
|
110
|
+
* record or the permission changes — the decision belongs to the server.
|
|
111
|
+
*
|
|
106
112
|
* `unknown` is not sent by the API: it is what the kit reads an unrecognised
|
|
107
113
|
* status as, and what a claimed success it cannot make sense of becomes — no
|
|
108
114
|
* record, or no `version` for the next write to lock against. The row keeps
|
|
109
115
|
* its `id`, and reaches the caller in `unresolved`, never in `failed`:
|
|
110
116
|
* retrying a create that already landed writes a second record.
|
|
111
117
|
*/
|
|
112
|
-
export type SfaBulkRowStatus = 'created' | 'updated' | 'deleted' | 'conflict' | 'invalid' | 'not_attempted' | 'indeterminate' | 'unknown';
|
|
118
|
+
export type SfaBulkRowStatus = 'created' | 'updated' | 'deleted' | 'conflict' | 'invalid' | 'not_attempted' | 'not_found' | 'not_permitted' | 'indeterminate' | 'unknown';
|
|
113
119
|
/** @description One row of a bulk update: what to change and from which version. */
|
|
114
120
|
export interface SfaBulkUpdateRow {
|
|
115
121
|
readonly id: string;
|
|
@@ -146,12 +152,22 @@ export interface SfaBulkRowResult {
|
|
|
146
152
|
* against.
|
|
147
153
|
*/
|
|
148
154
|
readonly record: SfaRecord | null;
|
|
149
|
-
/**
|
|
155
|
+
/**
|
|
156
|
+
* The problem detail for this row. Set on the statuses that report one:
|
|
157
|
+
* `conflict`, `invalid`, `not_found` and `not_permitted`.
|
|
158
|
+
*/
|
|
150
159
|
readonly error: SfaBulkRowError | null;
|
|
151
160
|
}
|
|
152
161
|
/** @description Why one row failed, in the same shape single writes report. */
|
|
153
162
|
export interface SfaBulkRowError {
|
|
154
|
-
/**
|
|
163
|
+
/**
|
|
164
|
+
* Machine-readable problem code, e.g. `version_mismatch`.
|
|
165
|
+
*
|
|
166
|
+
* NOTE: empty when the response carried none. Keystone has not minted a code
|
|
167
|
+
* for `not_permitted` and widened that field of its contract to any string,
|
|
168
|
+
* so a caller that branches on `code` has to treat `''` as "not stated" and
|
|
169
|
+
* fall back to `status`, rather than assume every failure names itself.
|
|
170
|
+
*/
|
|
155
171
|
readonly code: string;
|
|
156
172
|
readonly message: string;
|
|
157
173
|
/** Per-field errors when the row failed validation. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FileEntry } from './types';
|
|
1
|
+
import type { FileEntry } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Computes the SHA-256 content hash matching Keystone's
|
|
4
4
|
* {@link https://github.com/chikyuinc/chikyu/blob/branch_main/keystone/src/keystone/features/pages/domain/page_bundle_integrity.py compute_content_hash}.
|
|
@@ -4,6 +4,23 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Signs the message `"{studioVersion}:{contentHash}"` with the given key.
|
|
6
6
|
*
|
|
7
|
+
* **The signing key lives only in Keystone (`KEYSTONE_STUDIO__SIGNING_KEY`),
|
|
8
|
+
* so a page build cannot call this.** Deploying the key to Studio as well was
|
|
9
|
+
* the original design and was dropped in SFAJAI-186: Studio's secret store is
|
|
10
|
+
* per project, while the key has to be identical across all of them. Keystone
|
|
11
|
+
* now signs on request, and a page build asks it:
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* const files = await readBundleFiles('dist');
|
|
15
|
+
* const contentHash = computeContentHash(files);
|
|
16
|
+
* // POST /v1/pages/sign { studio_version, content_hash } -> { signature }
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Reach for this only from a service that legitimately holds the key. Signing
|
|
20
|
+
* with a made-up one is not caught at upload time while the verifier runs in
|
|
21
|
+
* `disabled` mode — the bundle is accepted, and only starts failing once the
|
|
22
|
+
* mode is switched to `enforced`.
|
|
23
|
+
*
|
|
7
24
|
* @param studioVersion - Studio version stored as page metadata.
|
|
8
25
|
* @param contentHash - Hex-encoded SHA-256 from {@link computeContentHash}.
|
|
9
26
|
* @param signingKey - Signing key as a UTF-8 string or raw bytes.
|
|
@@ -5,6 +5,23 @@ import { createHmac } from 'node:crypto';
|
|
|
5
5
|
*
|
|
6
6
|
* Signs the message `"{studioVersion}:{contentHash}"` with the given key.
|
|
7
7
|
*
|
|
8
|
+
* **The signing key lives only in Keystone (`KEYSTONE_STUDIO__SIGNING_KEY`),
|
|
9
|
+
* so a page build cannot call this.** Deploying the key to Studio as well was
|
|
10
|
+
* the original design and was dropped in SFAJAI-186: Studio's secret store is
|
|
11
|
+
* per project, while the key has to be identical across all of them. Keystone
|
|
12
|
+
* now signs on request, and a page build asks it:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* const files = await readBundleFiles('dist');
|
|
16
|
+
* const contentHash = computeContentHash(files);
|
|
17
|
+
* // POST /v1/pages/sign { studio_version, content_hash } -> { signature }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Reach for this only from a service that legitimately holds the key. Signing
|
|
21
|
+
* with a made-up one is not caught at upload time while the verifier runs in
|
|
22
|
+
* `disabled` mode — the bundle is accepted, and only starts failing once the
|
|
23
|
+
* mode is switched to `enforced`.
|
|
24
|
+
*
|
|
8
25
|
* @param studioVersion - Studio version stored as page metadata.
|
|
9
26
|
* @param contentHash - Hex-encoded SHA-256 from {@link computeContentHash}.
|
|
10
27
|
* @param signingKey - Signing key as a UTF-8 string or raw bytes.
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import type { BundleManifest } from './types';
|
|
1
|
+
import type { BundleManifest } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Reads a dist directory and creates a signed {@link BundleManifest}.
|
|
4
4
|
*
|
|
5
|
-
* Walks the directory tree
|
|
6
|
-
*
|
|
5
|
+
* Walks the directory tree via {@link readBundleFiles} and delegates to
|
|
6
|
+
* {@link createManifest}.
|
|
7
|
+
*
|
|
8
|
+
* **Requires the shared signing key, which page builds do not have.** Keystone
|
|
9
|
+
* holds it and is the only party that signs: an earlier design deployed it to
|
|
10
|
+
* Studio as well, and was abandoned because Studio's secret store is per
|
|
11
|
+
* project while the key must be identical everywhere (SFAJAI-186). Use this
|
|
12
|
+
* only from a service that legitimately holds the key. A page build calls
|
|
13
|
+
* {@link readBundleFiles} + {@link computeContentHash} and posts the hash to
|
|
14
|
+
* `POST /v1/pages/sign` instead — signing with an invented key produces a
|
|
15
|
+
* bundle that uploads today, while the verifier runs in `disabled` mode, and
|
|
16
|
+
* starts failing the moment it is switched to `enforced`.
|
|
7
17
|
*
|
|
8
18
|
* This function is **Node.js-only** and must not be used in browser
|
|
9
19
|
* environments. It does NOT write the manifest file to disk; the caller
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { createManifest } from './create-manifest';
|
|
2
|
+
import { createManifest } from './create-manifest.js';
|
|
3
|
+
import { readBundleFiles } from './read-bundle-files.js';
|
|
5
4
|
/**
|
|
6
5
|
* Reads a dist directory and creates a signed {@link BundleManifest}.
|
|
7
6
|
*
|
|
8
|
-
* Walks the directory tree
|
|
9
|
-
*
|
|
7
|
+
* Walks the directory tree via {@link readBundleFiles} and delegates to
|
|
8
|
+
* {@link createManifest}.
|
|
9
|
+
*
|
|
10
|
+
* **Requires the shared signing key, which page builds do not have.** Keystone
|
|
11
|
+
* holds it and is the only party that signs: an earlier design deployed it to
|
|
12
|
+
* Studio as well, and was abandoned because Studio's secret store is per
|
|
13
|
+
* project while the key must be identical everywhere (SFAJAI-186). Use this
|
|
14
|
+
* only from a service that legitimately holds the key. A page build calls
|
|
15
|
+
* {@link readBundleFiles} + {@link computeContentHash} and posts the hash to
|
|
16
|
+
* `POST /v1/pages/sign` instead — signing with an invented key produces a
|
|
17
|
+
* bundle that uploads today, while the verifier runs in `disabled` mode, and
|
|
18
|
+
* starts failing the moment it is switched to `enforced`.
|
|
10
19
|
*
|
|
11
20
|
* This function is **Node.js-only** and must not be used in browser
|
|
12
21
|
* environments. It does NOT write the manifest file to disk; the caller
|
|
@@ -18,29 +27,7 @@ import { createManifest } from './create-manifest';
|
|
|
18
27
|
*/
|
|
19
28
|
export function createManifestFromDirectory(distDir, studioVersion, signingKey) {
|
|
20
29
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
-
const files = yield
|
|
30
|
+
const files = yield readBundleFiles(distDir);
|
|
22
31
|
return createManifest(studioVersion, files, signingKey);
|
|
23
32
|
});
|
|
24
33
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Recursively collects all files under a directory as {@link FileEntry} objects.
|
|
27
|
-
* Paths are normalized to POSIX forward slashes.
|
|
28
|
-
*/
|
|
29
|
-
function collectFiles(dir) {
|
|
30
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
-
var _a;
|
|
32
|
-
const entries = yield readdir(dir, { withFileTypes: true, recursive: true });
|
|
33
|
-
const files = [];
|
|
34
|
-
for (const entry of entries) {
|
|
35
|
-
if (!entry.isFile())
|
|
36
|
-
continue;
|
|
37
|
-
const parentPath = (_a = entry.parentPath) !== null && _a !== void 0 ? _a : entry.path;
|
|
38
|
-
const absolutePath = join(parentPath, entry.name);
|
|
39
|
-
const relativePath = relative(dir, absolutePath);
|
|
40
|
-
const posixPath = relativePath.split(/[\\/]/).join(posix.sep);
|
|
41
|
-
const content = yield readFile(absolutePath);
|
|
42
|
-
files.push({ path: posixPath, content });
|
|
43
|
-
}
|
|
44
|
-
return files;
|
|
45
|
-
});
|
|
46
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BundleManifest, FileEntry } from './types';
|
|
1
|
+
import type { BundleManifest, FileEntry } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Creates a signed {@link BundleManifest} from a list of bundle files.
|
|
4
4
|
*
|
|
@@ -6,6 +6,12 @@ import type { BundleManifest, FileEntry } from './types';
|
|
|
6
6
|
* Callers can spread decorative fields (e.g. `sfaKitVersion` for the npm
|
|
7
7
|
* package version, `name`, `displayName`) on top before writing to disk.
|
|
8
8
|
*
|
|
9
|
+
* **Requires the shared signing key, which page builds do not have** — see
|
|
10
|
+
* {@link computeSignature}. A page build computes `content_hash` with
|
|
11
|
+
* {@link computeContentHash} and gets the signature from Keystone's
|
|
12
|
+
* `POST /v1/pages/sign`, then writes the three fields as a
|
|
13
|
+
* {@link BundleManifest} literal.
|
|
14
|
+
*
|
|
9
15
|
* @param studioVersion - Studio version stored as page metadata.
|
|
10
16
|
* @param files - All files in the bundle (manifest.json is automatically excluded).
|
|
11
17
|
* @param signingKey - Signing key as a UTF-8 string or raw bytes.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { computeContentHash } from './compute-content-hash';
|
|
2
|
-
import { computeSignature } from './compute-signature';
|
|
1
|
+
import { computeContentHash } from './compute-content-hash.js';
|
|
2
|
+
import { computeSignature } from './compute-signature.js';
|
|
3
3
|
/**
|
|
4
4
|
* Creates a signed {@link BundleManifest} from a list of bundle files.
|
|
5
5
|
*
|
|
@@ -7,6 +7,12 @@ import { computeSignature } from './compute-signature';
|
|
|
7
7
|
* Callers can spread decorative fields (e.g. `sfaKitVersion` for the npm
|
|
8
8
|
* package version, `name`, `displayName`) on top before writing to disk.
|
|
9
9
|
*
|
|
10
|
+
* **Requires the shared signing key, which page builds do not have** — see
|
|
11
|
+
* {@link computeSignature}. A page build computes `content_hash` with
|
|
12
|
+
* {@link computeContentHash} and gets the signature from Keystone's
|
|
13
|
+
* `POST /v1/pages/sign`, then writes the three fields as a
|
|
14
|
+
* {@link BundleManifest} literal.
|
|
15
|
+
*
|
|
10
16
|
* @param studioVersion - Studio version stored as page metadata.
|
|
11
17
|
* @param files - All files in the bundle (manifest.json is automatically excluded).
|
|
12
18
|
* @param signingKey - Signing key as a UTF-8 string or raw bytes.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export type { BundleManifest, FileEntry } from './types';
|
|
2
|
-
export { computeContentHash } from './compute-content-hash';
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
1
|
+
export type { BundleManifest, FileEntry } from './types.js';
|
|
2
|
+
export { computeContentHash } from './compute-content-hash.js';
|
|
3
|
+
export { readBundleFiles } from './read-bundle-files.js';
|
|
4
|
+
export { computeSignature } from './compute-signature.js';
|
|
5
|
+
export { createManifest } from './create-manifest.js';
|
|
6
|
+
export { createManifestFromDirectory } from './create-manifest-from-directory.js';
|
package/src/lib/signing/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { computeContentHash } from './compute-content-hash';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
1
|
+
export { computeContentHash } from './compute-content-hash.js';
|
|
2
|
+
export { readBundleFiles } from './read-bundle-files.js';
|
|
3
|
+
export { computeSignature } from './compute-signature.js';
|
|
4
|
+
export { createManifest } from './create-manifest.js';
|
|
5
|
+
export { createManifestFromDirectory } from './create-manifest-from-directory.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FileEntry } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* @description Reads every file under a built bundle directory as a
|
|
4
|
+
* {@link FileEntry}, ready for {@link computeContentHash}.
|
|
5
|
+
*
|
|
6
|
+
* This is the key-free half of building a bundle manifest: it needs no signing
|
|
7
|
+
* key, so a page build can compute its own `content_hash` and ask Keystone for
|
|
8
|
+
* the signature (`POST /v1/pages/sign`) rather than holding the shared secret.
|
|
9
|
+
*
|
|
10
|
+
* Paths are relative to `bundleDir` and use forward slashes on every platform,
|
|
11
|
+
* because the content hash is computed over the path bytes — a Windows
|
|
12
|
+
* backslash would hash to a different value than the same bundle built on
|
|
13
|
+
* Linux, and Keystone would reject it.
|
|
14
|
+
*
|
|
15
|
+
* **Node.js only.** Uses `node:fs`, so it must not reach a browser bundle.
|
|
16
|
+
*
|
|
17
|
+
* @param bundleDir - Absolute or relative path to the built bundle (e.g. `dist`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function readBundleFiles(bundleDir: string): Promise<FileEntry[]>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
3
|
+
import { join, relative, posix } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* @description Reads every file under a built bundle directory as a
|
|
6
|
+
* {@link FileEntry}, ready for {@link computeContentHash}.
|
|
7
|
+
*
|
|
8
|
+
* This is the key-free half of building a bundle manifest: it needs no signing
|
|
9
|
+
* key, so a page build can compute its own `content_hash` and ask Keystone for
|
|
10
|
+
* the signature (`POST /v1/pages/sign`) rather than holding the shared secret.
|
|
11
|
+
*
|
|
12
|
+
* Paths are relative to `bundleDir` and use forward slashes on every platform,
|
|
13
|
+
* because the content hash is computed over the path bytes — a Windows
|
|
14
|
+
* backslash would hash to a different value than the same bundle built on
|
|
15
|
+
* Linux, and Keystone would reject it.
|
|
16
|
+
*
|
|
17
|
+
* **Node.js only.** Uses `node:fs`, so it must not reach a browser bundle.
|
|
18
|
+
*
|
|
19
|
+
* @param bundleDir - Absolute or relative path to the built bundle (e.g. `dist`).
|
|
20
|
+
*/
|
|
21
|
+
export function readBundleFiles(bundleDir) {
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
var _a;
|
|
24
|
+
const entries = yield readdir(bundleDir, {
|
|
25
|
+
withFileTypes: true,
|
|
26
|
+
recursive: true,
|
|
27
|
+
});
|
|
28
|
+
const files = [];
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
if (!entry.isFile())
|
|
31
|
+
continue;
|
|
32
|
+
const parentPath = (_a = entry.parentPath) !== null && _a !== void 0 ? _a : entry.path;
|
|
33
|
+
const absolutePath = join(parentPath, entry.name);
|
|
34
|
+
const relativePath = relative(bundleDir, absolutePath);
|
|
35
|
+
const posixPath = relativePath.split(/[\\/]/).join(posix.sep);
|
|
36
|
+
const content = yield readFile(absolutePath);
|
|
37
|
+
files.push({ path: posixPath, content });
|
|
38
|
+
}
|
|
39
|
+
return files;
|
|
40
|
+
});
|
|
41
|
+
}
|
package/src/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SFA_KIT_VERSION = "1.
|
|
1
|
+
export declare const SFA_KIT_VERSION = "1.17.0";
|
package/src/lib/version.js
CHANGED
package/src/signing.d.ts
CHANGED
|
@@ -5,14 +5,19 @@
|
|
|
5
5
|
* and should not be imported in browser environments. It uses `node:crypto`
|
|
6
6
|
* for SHA-256 and HMAC-SHA-256 operations.
|
|
7
7
|
*
|
|
8
|
+
* The signing key lives only in Keystone, so a page build computes the content
|
|
9
|
+
* hash here and asks Keystone for the signature. Only `readBundleFiles` and
|
|
10
|
+
* `computeContentHash` are usable without the key.
|
|
11
|
+
*
|
|
8
12
|
* @example
|
|
9
13
|
* ```ts
|
|
10
|
-
* import {
|
|
14
|
+
* import { readBundleFiles, computeContentHash } from '@geniee-inc/sfa-kit/signing';
|
|
11
15
|
*
|
|
12
|
-
* const
|
|
16
|
+
* const contentHash = computeContentHash(await readBundleFiles('./dist'));
|
|
17
|
+
* // POST /v1/pages/sign { studio_version, content_hash } -> { signature }
|
|
13
18
|
* ```
|
|
14
19
|
*
|
|
15
20
|
* @packageDocumentation
|
|
16
21
|
*/
|
|
17
|
-
export type { BundleManifest, FileEntry } from './lib/signing';
|
|
18
|
-
export { computeContentHash, computeSignature, createManifest, createManifestFromDirectory, } from './lib/signing';
|
|
22
|
+
export type { BundleManifest, FileEntry } from './lib/signing/index.js';
|
|
23
|
+
export { computeContentHash, readBundleFiles, computeSignature, createManifest, createManifestFromDirectory, } from './lib/signing/index.js';
|
package/src/signing.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { computeContentHash, computeSignature, createManifest, createManifestFromDirectory, } from './lib/signing';
|
|
1
|
+
export { computeContentHash, readBundleFiles, computeSignature, createManifest, createManifestFromDirectory, } from './lib/signing/index.js';
|