@geniee-inc/sfa-kit 1.18.0 → 1.19.2

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.
Files changed (40) hide show
  1. package/GUIDE.md +35 -15
  2. package/package.json +1 -1
  3. package/src/bin/sfa-kit-bundle.js +16 -8
  4. package/src/bundle.d.ts +1 -2
  5. package/src/lib/auth/DevToolbar.js +3 -6
  6. package/src/lib/auth/SfaLoginGate.js +17 -8
  7. package/src/lib/auth/StandalonePreviewContext.d.ts +3 -3
  8. package/src/lib/auth/StandalonePreviewContext.js +1 -1
  9. package/src/lib/auth/useEmbedContext.d.ts +3 -1
  10. package/src/lib/auth/useEmbedContext.js +3 -1
  11. package/src/lib/bundle/build-static-bundle.d.ts +37 -11
  12. package/src/lib/bundle/build-static-bundle.js +75 -35
  13. package/src/lib/bundle/request-signature.d.ts +13 -1
  14. package/src/lib/bundle/request-signature.js +21 -6
  15. package/src/lib/components/FieldRenderer.d.ts +2 -1
  16. package/src/lib/components/FieldRenderer.js +32 -19
  17. package/src/lib/components/RecordList.js +32 -4
  18. package/src/lib/components/RecordView.js +27 -7
  19. package/src/lib/components/fieldDisplayText.d.ts +11 -0
  20. package/src/lib/components/fieldDisplayText.js +51 -0
  21. package/src/lib/hooks/useFieldTypes.d.ts +5 -0
  22. package/src/lib/hooks/useFieldTypes.js +5 -0
  23. package/src/lib/hooks/useObjectCatalog.d.ts +6 -0
  24. package/src/lib/hooks/useObjectCatalog.js +6 -0
  25. package/src/lib/hooks/useRecord.d.ts +20 -0
  26. package/src/lib/hooks/useRecord.js +53 -0
  27. package/src/lib/hooks/useRecordList.d.ts +7 -1
  28. package/src/lib/hooks/useRecordList.js +3 -3
  29. package/src/lib/hooks/useRelatedRecords.d.ts +5 -1
  30. package/src/lib/provider/SfaClient.js +13 -8
  31. package/src/lib/provider/types.d.ts +7 -1
  32. package/src/lib/signing/compute-signature.d.ts +4 -2
  33. package/src/lib/signing/compute-signature.js +4 -2
  34. package/src/lib/signing/create-manifest.d.ts +8 -6
  35. package/src/lib/signing/create-manifest.js +8 -6
  36. package/src/lib/signing/index.d.ts +1 -1
  37. package/src/lib/signing/types.d.ts +33 -4
  38. package/src/lib/version.d.ts +1 -1
  39. package/src/lib/version.js +1 -1
  40. package/src/signing.d.ts +2 -2
@@ -132,7 +132,7 @@ export class SfaClient {
132
132
  }
133
133
  const path = `/v1/objects/${enc(collection)}/records/query`;
134
134
  const raw = yield this.postJson(path, body);
135
- return normalizeKeystoneListResponse(raw, pageIndex, pageSize);
135
+ return normalizeKeystoneListResponse(raw, pageIndex);
136
136
  }
137
137
  const query = new URLSearchParams();
138
138
  if ((params === null || params === void 0 ? void 0 : params.limit) != null)
@@ -660,7 +660,7 @@ function inferScalarKind(value) {
660
660
  }
661
661
  return 'text';
662
662
  }
663
- function normalizeKeystoneListResponse(raw, pageIndex, pageSize) {
663
+ function normalizeKeystoneListResponse(raw, pageIndex) {
664
664
  var _a, _b, _c;
665
665
  const data = raw;
666
666
  const rawRecords = (_a = data['records']) !== null && _a !== void 0 ? _a : [];
@@ -668,12 +668,17 @@ function normalizeKeystoneListResponse(raw, pageIndex, pageSize) {
668
668
  const nextCursor = (_b = data['next_cursor']) !== null && _b !== void 0 ? _b : null;
669
669
  const prevCursor = (_c = data['prev_cursor']) !== null && _c !== void 0 ? _c : null;
670
670
  const hasMore = nextCursor != null;
671
- // Keystone uses cursor pagination without a total count.
672
- // Estimate a totalCount that keeps the hasMore logic correct.
673
- const totalCount = hasMore
674
- ? (pageIndex + 1) * pageSize + 1
675
- : pageIndex * pageSize + items.length;
676
- return { items, totalCount, hasMore, pageIndex, nextCursor, prevCursor };
671
+ // NOTE: Keystone pages with cursors and returns no total count. Report it as
672
+ // unknown rather than estimating one: an estimate reads as the real total
673
+ // ("21 records" for 500). Whether another page exists comes from hasMore
674
+ return {
675
+ items,
676
+ totalCount: null,
677
+ hasMore,
678
+ pageIndex,
679
+ nextCursor,
680
+ prevCursor,
681
+ };
677
682
  }
678
683
  // ── Legacy Chikyu normalization (proxy mode) ──
679
684
  const CHIKYU_KIND_MAP = {
@@ -53,7 +53,13 @@ export interface SfaRecord {
53
53
  }
54
54
  export interface SfaListResponse {
55
55
  readonly items: readonly SfaRecord[];
56
- readonly totalCount: number;
56
+ /**
57
+ * Records across all pages, or null when the backend does not report it.
58
+ *
59
+ * NOTE: Keystone pages with cursors and returns no total, so it is null in
60
+ * direct mode. Use `hasMore` to tell whether another page exists
61
+ */
62
+ readonly totalCount: number | null;
57
63
  readonly hasMore: boolean;
58
64
  readonly pageIndex: number;
59
65
  /** Cursor for fetching the next page (keystone cursor-based pagination). */
@@ -2,7 +2,9 @@
2
2
  * Computes the HMAC-SHA-256 bundle signature matching Keystone's
3
3
  * BundleSignatureVerifier.
4
4
  *
5
- * Signs the message `"{studioVersion}:{contentHash}"` with the given key.
5
+ * Signs the message `"{studioVersion}:{contentHash}"` with the given key. This
6
+ * is the legacy format; a manifest without `studio_version` is checked
7
+ * against `contentHash` alone (see `ContentHashManifest`).
6
8
  *
7
9
  * **The signing key lives only in Keystone (`KEYSTONE_STUDIO__SIGNING_KEY`),
8
10
  * so a page build cannot call this.** Deploying the key to Studio as well was
@@ -13,7 +15,7 @@
13
15
  * ```ts
14
16
  * const files = await readBundleFiles('dist');
15
17
  * const contentHash = computeContentHash(files);
16
- * // POST /v1/pages/sign { studio_version, content_hash } -> { signature }
18
+ * // POST /v1/pages/sign { content_hash } -> { signature }
17
19
  * ```
18
20
  *
19
21
  * Reach for this only from a service that legitimately holds the key. Signing
@@ -3,7 +3,9 @@ import { createHmac } from 'node:crypto';
3
3
  * Computes the HMAC-SHA-256 bundle signature matching Keystone's
4
4
  * BundleSignatureVerifier.
5
5
  *
6
- * Signs the message `"{studioVersion}:{contentHash}"` with the given key.
6
+ * Signs the message `"{studioVersion}:{contentHash}"` with the given key. This
7
+ * is the legacy format; a manifest without `studio_version` is checked
8
+ * against `contentHash` alone (see `ContentHashManifest`).
7
9
  *
8
10
  * **The signing key lives only in Keystone (`KEYSTONE_STUDIO__SIGNING_KEY`),
9
11
  * so a page build cannot call this.** Deploying the key to Studio as well was
@@ -14,7 +16,7 @@ import { createHmac } from 'node:crypto';
14
16
  * ```ts
15
17
  * const files = await readBundleFiles('dist');
16
18
  * const contentHash = computeContentHash(files);
17
- * // POST /v1/pages/sign { studio_version, content_hash } -> { signature }
19
+ * // POST /v1/pages/sign { content_hash } -> { signature }
18
20
  * ```
19
21
  *
20
22
  * Reach for this only from a service that legitimately holds the key. Signing
@@ -2,15 +2,17 @@ import type { BundleManifest, FileEntry } from './types.js';
2
2
  /**
3
3
  * Creates a signed {@link BundleManifest} from a list of bundle files.
4
4
  *
5
- * Returns the three fields Keystone's BundleSignatureVerifier requires.
6
- * Callers can spread decorative fields (e.g. `sfaKitVersion` for the npm
7
- * package version, `name`, `displayName`) on top before writing to disk.
5
+ * Returns the three fields of the legacy format, signed over
6
+ * `"{studio_version}:{content_hash}"`. Callers can spread decorative fields
7
+ * (e.g. `name`, `displayName`) on top before writing to disk.
8
8
  *
9
9
  * **Requires the shared signing key, which page builds do not have** — see
10
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.
11
+ * {@link computeContentHash}, posts it alone to Keystone's
12
+ * `POST /v1/pages/sign`, and writes the current format, a
13
+ * `ContentHashManifest` (see GUIDE.md). It does not write `studio_version`:
14
+ * Keystone checks a manifest carrying one in this legacy format, so a signature
15
+ * over `content_hash` alone would not verify.
14
16
  *
15
17
  * @param studioVersion - Studio version stored as page metadata.
16
18
  * @param files - All files in the bundle (manifest.json is automatically excluded).
@@ -3,15 +3,17 @@ import { computeSignature } from './compute-signature.js';
3
3
  /**
4
4
  * Creates a signed {@link BundleManifest} from a list of bundle files.
5
5
  *
6
- * Returns the three fields Keystone's BundleSignatureVerifier requires.
7
- * Callers can spread decorative fields (e.g. `sfaKitVersion` for the npm
8
- * package version, `name`, `displayName`) on top before writing to disk.
6
+ * Returns the three fields of the legacy format, signed over
7
+ * `"{studio_version}:{content_hash}"`. Callers can spread decorative fields
8
+ * (e.g. `name`, `displayName`) on top before writing to disk.
9
9
  *
10
10
  * **Requires the shared signing key, which page builds do not have** — see
11
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.
12
+ * {@link computeContentHash}, posts it alone to Keystone's
13
+ * `POST /v1/pages/sign`, and writes the current format, a
14
+ * `ContentHashManifest` (see GUIDE.md). It does not write `studio_version`:
15
+ * Keystone checks a manifest carrying one in this legacy format, so a signature
16
+ * over `content_hash` alone would not verify.
15
17
  *
16
18
  * @param studioVersion - Studio version stored as page metadata.
17
19
  * @param files - All files in the bundle (manifest.json is automatically excluded).
@@ -1,4 +1,4 @@
1
- export type { BundleManifest, FileEntry } from './types.js';
1
+ export type { BundleManifest, FileEntry, ContentHashManifest, } from './types.js';
2
2
  export { computeContentHash } from './compute-content-hash.js';
3
3
  export { readBundleFiles } from './read-bundle-files.js';
4
4
  export { computeSignature } from './compute-signature.js';
@@ -1,8 +1,9 @@
1
1
  /**
2
- * The three fields Keystone's BundleSignatureVerifier reads from
3
- * manifest.json. Callers can spread decorative fields on top before
4
- * writing to disk (e.g. `sfaKitVersion` for the npm package version,
5
- * `name`, `displayName`, `entry`).
2
+ * The legacy manifest format: the signature covers
3
+ * `"{studio_version}:{content_hash}"`. Keystone still accepts it, and
4
+ * {@link createManifest} and `buildStaticBundle` given a `studioVersion` still
5
+ * produce it. Callers can spread decorative fields on top before writing to
6
+ * disk (e.g. `name`, `displayName`, `entry`).
6
7
  */
7
8
  export interface BundleManifest {
8
9
  /** Studio version string (the build version, not the sfa-kit npm version). */
@@ -12,6 +13,34 @@ export interface BundleManifest {
12
13
  /** HMAC-SHA-256 hex of `"{studio_version}:{content_hash}"`. */
13
14
  signature: string;
14
15
  }
16
+ /**
17
+ * The manifest `buildStaticBundle` writes when no `studioVersion` is given.
18
+ *
19
+ * Keystone reads a manifest without `studio_version` as this format and checks
20
+ * the signature against `content_hash` alone. `content_hash` covers every
21
+ * other file in the bundle, so that is what makes an edited bundle fail.
22
+ */
23
+ export interface ContentHashManifest {
24
+ /**
25
+ * The sfa-kit version that ran the build. Not signed: Keystone stores it for
26
+ * troubleshooting only.
27
+ *
28
+ * NOTE: this is the copy of sfa-kit that ran the bundler. esbuild bundles
29
+ * whichever copy the entry module imports, which is normally the same one,
30
+ * but a project with two installed copies can bundle the other.
31
+ */
32
+ sfa_kit_version: string;
33
+ /** SHA-256 hex digest of all non-manifest file contents. */
34
+ content_hash: string;
35
+ /** HMAC-SHA-256 hex of `content_hash`. */
36
+ signature: string;
37
+ /**
38
+ * Never present in this format. Keystone picks the format by whether the
39
+ * manifest carries `studio_version`, so one that does is a legacy
40
+ * {@link BundleManifest}, not this.
41
+ */
42
+ studio_version?: never;
43
+ }
15
44
  /** A single file in the bundle, used for content hash computation. */
16
45
  export interface FileEntry {
17
46
  /** Relative path using forward slashes (e.g. "index.html", "assets/bundle.js"). */
@@ -1 +1 @@
1
- export declare const SFA_KIT_VERSION = "1.18.0";
1
+ export declare const SFA_KIT_VERSION = "1.19.2";
@@ -1,3 +1,3 @@
1
1
  // このファイルは libs/sfa-kit/scripts/sync-version.cjs が生成する。
2
2
  // 手で編集しないこと。バージョンを上げるときは libs/sfa-kit/package.json を変更する。
3
- export const SFA_KIT_VERSION = '1.18.0';
3
+ export const SFA_KIT_VERSION = '1.19.2';
package/src/signing.d.ts CHANGED
@@ -14,10 +14,10 @@
14
14
  * import { readBundleFiles, computeContentHash } from '@geniee-inc/sfa-kit/signing';
15
15
  *
16
16
  * const contentHash = computeContentHash(await readBundleFiles('./dist'));
17
- * // POST /v1/pages/sign { studio_version, content_hash } -> { signature }
17
+ * // POST /v1/pages/sign { content_hash } -> { signature }
18
18
  * ```
19
19
  *
20
20
  * @packageDocumentation
21
21
  */
22
- export type { BundleManifest, FileEntry } from './lib/signing/index.js';
22
+ export type { BundleManifest, FileEntry, ContentHashManifest, } from './lib/signing/index.js';
23
23
  export { computeContentHash, readBundleFiles, computeSignature, createManifest, createManifestFromDirectory, } from './lib/signing/index.js';