@colixsystems/widget-sdk 0.241.0 → 0.243.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 CHANGED
@@ -84,7 +84,28 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
84
84
 
85
85
  ## Status
86
86
 
87
- `v0.241.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
87
+ `v0.243.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
88
+
89
+ ### What's new in 0.243.0 (contract 1.197.0)
90
+
91
+ **`bankIdAppUrl(autoStartToken)` opens BankID on this device** (from 0.243.0). The link a signing or identification widget opens from its "Open BankID on this device" button: `Linking.openURL(bankIdAppUrl(autoStartToken))`. It is the same link the built-in Files and Identification widgets and the signing page use. For BankID on another device, show the order's `qr` with `<Image>`.
92
+
93
+ `useFileSignature` does not poll by itself: while `status` is `"pending"`, call `refresh()` every 2 seconds, and render each answer's `qr`. It signs a file of any type in a shared space; outside a signing round the signature is kept beside the file, and in a round the signature is added to the PDF, which is then sealed. A `verify()` verdict reads as: `valid` (the BankID signature), `content_status` (`unchanged`, `changed` or `unavailable`), `signed_by_others_since` (later signatures in a round) and `seal.status` (`valid`, `invalid`, `certificate_revoked`, `unavailable`, or `not_applicable` for a signature kept beside the file). `useFileSignatures` is described as what it is: the signed-in user's own signatures.
94
+
95
+ ```jsx
96
+ import { Button, Image, Linking, bankIdAppUrl, useFileSignature } from "@colixsystems/widget-sdk";
97
+
98
+ const { status, qr, autoStartToken, initiate, refresh } = useFileSignature(fileId);
99
+ useEffect(() => {
100
+ if (status !== "pending") return undefined;
101
+ const timer = setInterval(refresh, 2000);
102
+ return () => clearInterval(timer);
103
+ }, [status, refresh]);
104
+ // bankIdAppUrl exists from 0.243.0; a widget that must load on an older SDK
105
+ // reads it as sdk.bankIdAppUrl from `import * as sdk` and builds the same link itself.
106
+ // autoStartToken && <Button title="Open BankID on this device" onPress={() => Linking.openURL(bankIdAppUrl(autoStartToken))} />
107
+ // qr && <Image source={{ uri: qr }} style={{ width: 200, height: 200 }} />
108
+ ```
88
109
 
89
110
  ### What's new in 0.241.0 (contract 1.195.0)
90
111
 
@@ -0,0 +1,6 @@
1
+ // The one BankID app launch link: widgets, the Player's login and the signing
2
+ // page. Imports nothing, so every host and the exported app share it as it is.
3
+
4
+ /** The URL that opens the BankID app on this device for the order of `autoStartToken`. */
5
+ export const bankIdAppUrl = (autoStartToken) =>
6
+ `bankid:///?autostarttoken=${encodeURIComponent(autoStartToken)}&redirect=null`;
package/dist/contract.cjs CHANGED
@@ -1624,10 +1624,30 @@ const HOOKS = [
1624
1624
  signature: "useFileSignature(fileId, existingSignatureId)",
1625
1625
  optionalArgs: ["existingSignatureId"],
1626
1626
  description:
1627
- "Drive a BankID signing flow for one Filestore file. initiate() opens a " +
1628
- "sign order (the backend hashes the bytes + binds the digest), refresh() " +
1629
- "polls (fresh QR while pending — render with the Image primitive), " +
1630
- "cancel() aborts, verify() returns the offline verdict. Pass " +
1627
+ "Drive a BankID signing flow for one Filestore file of ANY type in a " +
1628
+ "shared (project or public) space; a personal file is refused with " +
1629
+ "NOT_SIGNABLE. Outside a signing round the signature is kept beside " +
1630
+ "the file and the file is not changed; a PDF in an open signing round " +
1631
+ "gets the signature added to the document itself, which is then " +
1632
+ "sealed against changes (see useSigningRounds). initiate() opens a " +
1633
+ "sign order (the backend hashes the bytes + binds the digest). The " +
1634
+ "hook does NOT poll by itself: while status is 'pending' call " +
1635
+ "refresh() every 2 seconds (a setInterval in an effect, cleared when " +
1636
+ "status leaves 'pending' or the widget unmounts); each answer carries " +
1637
+ "a fresh qr frame. Offer both ways to sign: BankID on THIS device is a " +
1638
+ "button whose onPress calls Linking.openURL(bankIdAppUrl(autoStartToken)), " +
1639
+ "shown only while autoStartToken is set; BankID on ANOTHER device is " +
1640
+ "the qr rendered with the Image primitive, replaced by each poll's " +
1641
+ "frame. cancel() aborts, verify() returns the offline verdict: valid " +
1642
+ "is the BankID signature itself; content_status 'unchanged' means the " +
1643
+ "file still holds what was signed, 'changed' that it was altered " +
1644
+ "since, 'unavailable' that it could not be checked now; " +
1645
+ "signed_by_others_since counts later signatures in a round's PDF; " +
1646
+ "seal.status is 'valid' (protected against changes), 'invalid' or " +
1647
+ "'certificate_revoked' (do not rely on the copy), 'unavailable' (try " +
1648
+ "later) or 'not_applicable' (a signature kept beside the file). Say " +
1649
+ "each in plain words and never show a green mark when any of them " +
1650
+ "failed. Pass " +
1631
1651
  "existingSignatureId for an already-signed file to seed the complete " +
1632
1652
  "state + verify() without re-signing. autoStartToken is set only while " +
1633
1653
  "opening BankID can still help (null once the user has signed or the " +
@@ -1644,19 +1664,21 @@ const HOOKS = [
1644
1664
  "ctx.filestore.signatures.{initiate,status,cancel,verify}.",
1645
1665
  returnShape: {
1646
1666
  status: "'pending' | 'complete' | 'failed' | 'cancelled' | null",
1647
- qr: "string | null // PNG data-URL of the animated BankID QR",
1648
- autoStartToken: "string | null",
1667
+ qr: "string | null // PNG data-URL of the animated BankID QR; render with <Image>, refresh() every 2 s while pending for the next frame",
1668
+ autoStartToken: "string | null // BankID on this device: a button calling Linking.openURL(bankIdAppUrl(autoStartToken))",
1649
1669
  message: "string | null",
1650
1670
  signerName: "string | null",
1651
1671
  signedAt: "string | null",
1652
1672
  hintCode: "string | null // where the order stands, e.g. 'sealing'",
1653
1673
  nameRefusal:
1654
1674
  "{ reason: 'empty' | 'too_long' | 'unsupported_characters' | 'mixed_scripts', characters: string[] } | null",
1655
- verdict: "{ valid, checks, content_status, signed_by_others_since, seal, ... } | null",
1675
+ verdict:
1676
+ "{ valid, checks, content_status: 'unchanged' | 'changed' | 'unavailable', signed_by_others_since: number | null, " +
1677
+ "seal: { status: 'valid' | 'invalid' | 'certificate_revoked' | 'unavailable' | 'not_applicable', sealed_at, certificate_revoked_at, ... }, ... } | null",
1656
1678
  loading: "boolean",
1657
1679
  error: "PermissionError | null // { code, message, retryable }",
1658
1680
  initiate: "() => Promise<{ signature_id, qr, auto_start_token, status, hint_code?, message? }>",
1659
- refresh: "() => Promise<void>",
1681
+ refresh: "() => Promise<void> // the hook never polls by itself",
1660
1682
  cancel: "() => Promise<{ status, hint_code?, message?, signer_name?, signed_at? } | undefined>",
1661
1683
  verify: "() => Promise<verdict>",
1662
1684
  },
@@ -1667,10 +1689,14 @@ const HOOKS = [
1667
1689
  name: "useFileSignatures",
1668
1690
  signature: "useFileSignatures(fileIds)",
1669
1691
  description:
1670
- "Batch 'is this file signed?' lookup for a set of file ids. Returns a map " +
1671
- "of each signed, accessible file id to its latest signature; unsigned " +
1672
- "files are absent. Lets a file browser mark already-signed files in one " +
1673
- "request. Reads ctx.filestore.signatures.list and unwraps { data, meta }.",
1692
+ "Batch 'have I signed this file?' lookup for a set of file ids. Returns " +
1693
+ "a map of each file the SIGNED-IN USER has signed (and can still see) " +
1694
+ "to their own latest signature; a file only others have signed, or " +
1695
+ "nobody has, is absent, so it never tells who else signed. Pass a " +
1696
+ "file's signature_id to useFileSignature(fileId, signatureId) to show " +
1697
+ "and verify it. Who has signed is useFileRoster(), for someone who " +
1698
+ "manages the folder. Reads ctx.filestore.signatures.list and unwraps " +
1699
+ "{ data, meta }.",
1674
1700
  returnShape: {
1675
1701
  signaturesByFileId:
1676
1702
  "{ [fileId]: { signature_id, signer_name, signed_at } }",
@@ -1709,8 +1735,10 @@ const HOOKS = [
1709
1735
  signature: "useSigningRounds(fileIds)",
1710
1736
  description:
1711
1737
  "What the signed-in user may know about the signing round of each file " +
1712
- "in a list, in one batched request. A signing round fixes a PDF and a " +
1713
- "list of signers: it is prepared and confirmed by someone who manages " +
1738
+ "in a list, in one batched request. A signing round fixes a PDF in the " +
1739
+ "project space and a list of signers (other file types are signed one " +
1740
+ "person at a time with useFileSignature() and no round): it is " +
1741
+ "prepared and confirmed by someone who manages " +
1714
1742
  "the file's folder, then each signer signs once with useFileSignature(), " +
1715
1743
  "in any order (there are no turns; the list only orders the places on " +
1716
1744
  "the signature page). byFileId maps a file id to { file_id, can_manage, " +
@@ -1719,7 +1747,8 @@ const HOOKS = [
1719
1747
  "manager nor one of its signers; a signer sees it once it is confirmed, " +
1720
1748
  "with their own place (my_place) and can_sign (the round is open and " +
1721
1749
  "their place is unsigned), and signed_count is null " +
1722
- "for them. locked is 'signing_round' while the file cannot be changed, " +
1750
+ "for them. Each signature is added to the PDF itself and the document " +
1751
+ "is sealed against changes. locked is 'signing_round' while the file cannot be changed, " +
1723
1752
  "'signed' once its content cannot be replaced. roundsEnabled is false " +
1724
1753
  "when the workspace cannot start signing rounds (offer no way to start " +
1725
1754
  "one), and null until the first answer. can_prepare is about the file " +
@@ -1790,7 +1819,11 @@ const HOOKS = [
1790
1819
  "document changed) the hook reads the round again by itself. Code " +
1791
1820
  "SIGNING_ROUNDS_NOT_ENABLED means the workspace cannot start signing " +
1792
1821
  "rounds; check roundsEnabled from useSigningRounds() before offering to " +
1793
- "start one. When fileId or the signed-in user changes, round is null " +
1822
+ "start one, and when it is false say that document signing is not " +
1823
+ "turned on for this workspace and that the platform turns it on. " +
1824
+ "Rounds take PDFs in the project space only (NOT_A_PDF otherwise). A " +
1825
+ "signer signs their place with useFileSignature(fileId), the same " +
1826
+ "BankID flow as any file. When fileId or the signed-in user changes, round is null " +
1794
1827
  "and loading true until the new answer. Reads ctx.filestore.signingRounds.",
1795
1828
  returnShape: {
1796
1829
  round:
@@ -2619,8 +2652,9 @@ const HOOKS = [
2619
2652
  "with the Image primitive) and the hook then POLLS to completion itself " +
2620
2653
  "(pollIntervalMs, default 1000; pass 0 to drive refresh() yourself); " +
2621
2654
  "cancel() aborts; reset() clears the flow. autoStartToken opens the " +
2622
- "provider app on the SAME device (bankid:///?autostarttoken=<token>" +
2623
- "&redirect=null). On complete, `identity` is { provider, name, given_name, " +
2655
+ "provider app on the SAME device: Linking.openURL(bankIdAppUrl(" +
2656
+ "autoStartToken)) opens bankid:///?autostarttoken=<token>&redirect=null. " +
2657
+ "On complete, `identity` is { provider, name, given_name, " +
2624
2658
  "surname, personal_number_masked, subject_hash, identified_at } — there is " +
2625
2659
  "NO raw personal number by design: write personal_number_masked " +
2626
2660
  "(\"19900101-****\") and, if you need to trace the proof, identificationId. " +
@@ -6117,7 +6151,11 @@ const CONTRACT = deepFreeze({
6117
6151
  // `{ name, email }` entries for signers without an account, and
6118
6152
  // `resendLink(signerId, { email })` sends such a signer a new link.
6119
6153
  // The manager's places carry id, kind, email and link.
6120
- version: "1.195.0",
6154
+ // 1.197.0: additive (sc-12063) — new export `bankIdAppUrl(autoStartToken)`,
6155
+ // the link that opens BankID on this device. Signing hooks document
6156
+ // polling, the two ways to start BankID and how to read a verdict;
6157
+ // useFileSignatures is described as the caller's own signatures.
6158
+ version: "1.197.0",
6121
6159
  sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
6122
6160
  hooks: HOOKS,
6123
6161
  primitives: PRIMITIVES,
package/dist/contract.js CHANGED
@@ -1624,10 +1624,30 @@ const HOOKS = [
1624
1624
  signature: "useFileSignature(fileId, existingSignatureId)",
1625
1625
  optionalArgs: ["existingSignatureId"],
1626
1626
  description:
1627
- "Drive a BankID signing flow for one Filestore file. initiate() opens a " +
1628
- "sign order (the backend hashes the bytes + binds the digest), refresh() " +
1629
- "polls (fresh QR while pending — render with the Image primitive), " +
1630
- "cancel() aborts, verify() returns the offline verdict. Pass " +
1627
+ "Drive a BankID signing flow for one Filestore file of ANY type in a " +
1628
+ "shared (project or public) space; a personal file is refused with " +
1629
+ "NOT_SIGNABLE. Outside a signing round the signature is kept beside " +
1630
+ "the file and the file is not changed; a PDF in an open signing round " +
1631
+ "gets the signature added to the document itself, which is then " +
1632
+ "sealed against changes (see useSigningRounds). initiate() opens a " +
1633
+ "sign order (the backend hashes the bytes + binds the digest). The " +
1634
+ "hook does NOT poll by itself: while status is 'pending' call " +
1635
+ "refresh() every 2 seconds (a setInterval in an effect, cleared when " +
1636
+ "status leaves 'pending' or the widget unmounts); each answer carries " +
1637
+ "a fresh qr frame. Offer both ways to sign: BankID on THIS device is a " +
1638
+ "button whose onPress calls Linking.openURL(bankIdAppUrl(autoStartToken)), " +
1639
+ "shown only while autoStartToken is set; BankID on ANOTHER device is " +
1640
+ "the qr rendered with the Image primitive, replaced by each poll's " +
1641
+ "frame. cancel() aborts, verify() returns the offline verdict: valid " +
1642
+ "is the BankID signature itself; content_status 'unchanged' means the " +
1643
+ "file still holds what was signed, 'changed' that it was altered " +
1644
+ "since, 'unavailable' that it could not be checked now; " +
1645
+ "signed_by_others_since counts later signatures in a round's PDF; " +
1646
+ "seal.status is 'valid' (protected against changes), 'invalid' or " +
1647
+ "'certificate_revoked' (do not rely on the copy), 'unavailable' (try " +
1648
+ "later) or 'not_applicable' (a signature kept beside the file). Say " +
1649
+ "each in plain words and never show a green mark when any of them " +
1650
+ "failed. Pass " +
1631
1651
  "existingSignatureId for an already-signed file to seed the complete " +
1632
1652
  "state + verify() without re-signing. autoStartToken is set only while " +
1633
1653
  "opening BankID can still help (null once the user has signed or the " +
@@ -1644,19 +1664,21 @@ const HOOKS = [
1644
1664
  "ctx.filestore.signatures.{initiate,status,cancel,verify}.",
1645
1665
  returnShape: {
1646
1666
  status: "'pending' | 'complete' | 'failed' | 'cancelled' | null",
1647
- qr: "string | null // PNG data-URL of the animated BankID QR",
1648
- autoStartToken: "string | null",
1667
+ qr: "string | null // PNG data-URL of the animated BankID QR; render with <Image>, refresh() every 2 s while pending for the next frame",
1668
+ autoStartToken: "string | null // BankID on this device: a button calling Linking.openURL(bankIdAppUrl(autoStartToken))",
1649
1669
  message: "string | null",
1650
1670
  signerName: "string | null",
1651
1671
  signedAt: "string | null",
1652
1672
  hintCode: "string | null // where the order stands, e.g. 'sealing'",
1653
1673
  nameRefusal:
1654
1674
  "{ reason: 'empty' | 'too_long' | 'unsupported_characters' | 'mixed_scripts', characters: string[] } | null",
1655
- verdict: "{ valid, checks, content_status, signed_by_others_since, seal, ... } | null",
1675
+ verdict:
1676
+ "{ valid, checks, content_status: 'unchanged' | 'changed' | 'unavailable', signed_by_others_since: number | null, " +
1677
+ "seal: { status: 'valid' | 'invalid' | 'certificate_revoked' | 'unavailable' | 'not_applicable', sealed_at, certificate_revoked_at, ... }, ... } | null",
1656
1678
  loading: "boolean",
1657
1679
  error: "PermissionError | null // { code, message, retryable }",
1658
1680
  initiate: "() => Promise<{ signature_id, qr, auto_start_token, status, hint_code?, message? }>",
1659
- refresh: "() => Promise<void>",
1681
+ refresh: "() => Promise<void> // the hook never polls by itself",
1660
1682
  cancel: "() => Promise<{ status, hint_code?, message?, signer_name?, signed_at? } | undefined>",
1661
1683
  verify: "() => Promise<verdict>",
1662
1684
  },
@@ -1667,10 +1689,14 @@ const HOOKS = [
1667
1689
  name: "useFileSignatures",
1668
1690
  signature: "useFileSignatures(fileIds)",
1669
1691
  description:
1670
- "Batch 'is this file signed?' lookup for a set of file ids. Returns a map " +
1671
- "of each signed, accessible file id to its latest signature; unsigned " +
1672
- "files are absent. Lets a file browser mark already-signed files in one " +
1673
- "request. Reads ctx.filestore.signatures.list and unwraps { data, meta }.",
1692
+ "Batch 'have I signed this file?' lookup for a set of file ids. Returns " +
1693
+ "a map of each file the SIGNED-IN USER has signed (and can still see) " +
1694
+ "to their own latest signature; a file only others have signed, or " +
1695
+ "nobody has, is absent, so it never tells who else signed. Pass a " +
1696
+ "file's signature_id to useFileSignature(fileId, signatureId) to show " +
1697
+ "and verify it. Who has signed is useFileRoster(), for someone who " +
1698
+ "manages the folder. Reads ctx.filestore.signatures.list and unwraps " +
1699
+ "{ data, meta }.",
1674
1700
  returnShape: {
1675
1701
  signaturesByFileId:
1676
1702
  "{ [fileId]: { signature_id, signer_name, signed_at } }",
@@ -1709,8 +1735,10 @@ const HOOKS = [
1709
1735
  signature: "useSigningRounds(fileIds)",
1710
1736
  description:
1711
1737
  "What the signed-in user may know about the signing round of each file " +
1712
- "in a list, in one batched request. A signing round fixes a PDF and a " +
1713
- "list of signers: it is prepared and confirmed by someone who manages " +
1738
+ "in a list, in one batched request. A signing round fixes a PDF in the " +
1739
+ "project space and a list of signers (other file types are signed one " +
1740
+ "person at a time with useFileSignature() and no round): it is " +
1741
+ "prepared and confirmed by someone who manages " +
1714
1742
  "the file's folder, then each signer signs once with useFileSignature(), " +
1715
1743
  "in any order (there are no turns; the list only orders the places on " +
1716
1744
  "the signature page). byFileId maps a file id to { file_id, can_manage, " +
@@ -1719,7 +1747,8 @@ const HOOKS = [
1719
1747
  "manager nor one of its signers; a signer sees it once it is confirmed, " +
1720
1748
  "with their own place (my_place) and can_sign (the round is open and " +
1721
1749
  "their place is unsigned), and signed_count is null " +
1722
- "for them. locked is 'signing_round' while the file cannot be changed, " +
1750
+ "for them. Each signature is added to the PDF itself and the document " +
1751
+ "is sealed against changes. locked is 'signing_round' while the file cannot be changed, " +
1723
1752
  "'signed' once its content cannot be replaced. roundsEnabled is false " +
1724
1753
  "when the workspace cannot start signing rounds (offer no way to start " +
1725
1754
  "one), and null until the first answer. can_prepare is about the file " +
@@ -1790,7 +1819,11 @@ const HOOKS = [
1790
1819
  "document changed) the hook reads the round again by itself. Code " +
1791
1820
  "SIGNING_ROUNDS_NOT_ENABLED means the workspace cannot start signing " +
1792
1821
  "rounds; check roundsEnabled from useSigningRounds() before offering to " +
1793
- "start one. When fileId or the signed-in user changes, round is null " +
1822
+ "start one, and when it is false say that document signing is not " +
1823
+ "turned on for this workspace and that the platform turns it on. " +
1824
+ "Rounds take PDFs in the project space only (NOT_A_PDF otherwise). A " +
1825
+ "signer signs their place with useFileSignature(fileId), the same " +
1826
+ "BankID flow as any file. When fileId or the signed-in user changes, round is null " +
1794
1827
  "and loading true until the new answer. Reads ctx.filestore.signingRounds.",
1795
1828
  returnShape: {
1796
1829
  round:
@@ -2619,8 +2652,9 @@ const HOOKS = [
2619
2652
  "with the Image primitive) and the hook then POLLS to completion itself " +
2620
2653
  "(pollIntervalMs, default 1000; pass 0 to drive refresh() yourself); " +
2621
2654
  "cancel() aborts; reset() clears the flow. autoStartToken opens the " +
2622
- "provider app on the SAME device (bankid:///?autostarttoken=<token>" +
2623
- "&redirect=null). On complete, `identity` is { provider, name, given_name, " +
2655
+ "provider app on the SAME device: Linking.openURL(bankIdAppUrl(" +
2656
+ "autoStartToken)) opens bankid:///?autostarttoken=<token>&redirect=null. " +
2657
+ "On complete, `identity` is { provider, name, given_name, " +
2624
2658
  "surname, personal_number_masked, subject_hash, identified_at } — there is " +
2625
2659
  "NO raw personal number by design: write personal_number_masked " +
2626
2660
  "(\"19900101-****\") and, if you need to trace the proof, identificationId. " +
@@ -6113,7 +6147,11 @@ const CONTRACT = deepFreeze({
6113
6147
  // `{ name, email }` entries for signers without an account, and
6114
6148
  // `resendLink(signerId, { email })` sends such a signer a new link.
6115
6149
  // The manager's places carry id, kind, email and link.
6116
- version: "1.195.0",
6150
+ // 1.197.0: additive (sc-12063) — new export `bankIdAppUrl(autoStartToken)`,
6151
+ // the link that opens BankID on this device. Signing hooks document
6152
+ // polling, the two ways to start BankID and how to read a verdict;
6153
+ // useFileSignatures is described as the caller's own signatures.
6154
+ version: "1.197.0",
6117
6155
  sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
6118
6156
  hooks: HOOKS,
6119
6157
  primitives: PRIMITIVES,
package/dist/index.d.ts CHANGED
@@ -5065,6 +5065,13 @@ export function useFileSignature(
5065
5065
  verify(): Promise<FileSignatureVerdict | null>;
5066
5066
  };
5067
5067
 
5068
+ /**
5069
+ * The link that opens the BankID app on this device for a pending order:
5070
+ * `Linking.openURL(bankIdAppUrl(autoStartToken))` from a button. For BankID
5071
+ * on another device, show the order's `qr` instead.
5072
+ */
5073
+ export function bankIdAppUrl(autoStartToken: string): string;
5074
+
5068
5075
  export interface FileSignatureSummary {
5069
5076
  signature_id: string;
5070
5077
  subject_file_id: string;
package/dist/index.js CHANGED
@@ -135,6 +135,7 @@ export {
135
135
  } from "./stats-hooks.js";
136
136
  // sc-11025 — one source, bound to how each platform says the app is in front.
137
137
  export { useFileSignature, useSigningRounds, useSigningRound } from "./signing-hooks.js";
138
+ export { bankIdAppUrl } from "./bankid-app.js";
138
139
  export { useOnlineMembers, useOnlineVisibility } from "./presence.js";
139
140
  // sc-6607 — `<Overlay>` is one shared component (./overlay-view.js) bound to
140
141
  // each platform's primitives, so a widget's modal escapes its container box
@@ -133,6 +133,7 @@ export {
133
133
  } from "./stats-hooks.js";
134
134
  // sc-11025 — see the note on the web mirror in ./index.js.
135
135
  export { useFileSignature, useSigningRounds, useSigningRound } from "./signing-hooks.js";
136
+ export { bankIdAppUrl } from "./bankid-app.js";
136
137
  export { useOnlineMembers, useOnlineVisibility } from "./presence.native.js";
137
138
  // sc-6607 — see the note on the web mirror in ./index.js.
138
139
  export { Overlay } from "./overlay.native.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colixsystems/widget-sdk",
3
- "version": "0.241.0",
3
+ "version": "0.243.0",
4
4
  "description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
5
5
  "homepage": "https://github.com/Colix-AB/AppStudio",
6
6
  "type": "module",
package/src/contract.js CHANGED
@@ -1624,10 +1624,30 @@ const HOOKS = [
1624
1624
  signature: "useFileSignature(fileId, existingSignatureId)",
1625
1625
  optionalArgs: ["existingSignatureId"],
1626
1626
  description:
1627
- "Drive a BankID signing flow for one Filestore file. initiate() opens a " +
1628
- "sign order (the backend hashes the bytes + binds the digest), refresh() " +
1629
- "polls (fresh QR while pending — render with the Image primitive), " +
1630
- "cancel() aborts, verify() returns the offline verdict. Pass " +
1627
+ "Drive a BankID signing flow for one Filestore file of ANY type in a " +
1628
+ "shared (project or public) space; a personal file is refused with " +
1629
+ "NOT_SIGNABLE. Outside a signing round the signature is kept beside " +
1630
+ "the file and the file is not changed; a PDF in an open signing round " +
1631
+ "gets the signature added to the document itself, which is then " +
1632
+ "sealed against changes (see useSigningRounds). initiate() opens a " +
1633
+ "sign order (the backend hashes the bytes + binds the digest). The " +
1634
+ "hook does NOT poll by itself: while status is 'pending' call " +
1635
+ "refresh() every 2 seconds (a setInterval in an effect, cleared when " +
1636
+ "status leaves 'pending' or the widget unmounts); each answer carries " +
1637
+ "a fresh qr frame. Offer both ways to sign: BankID on THIS device is a " +
1638
+ "button whose onPress calls Linking.openURL(bankIdAppUrl(autoStartToken)), " +
1639
+ "shown only while autoStartToken is set; BankID on ANOTHER device is " +
1640
+ "the qr rendered with the Image primitive, replaced by each poll's " +
1641
+ "frame. cancel() aborts, verify() returns the offline verdict: valid " +
1642
+ "is the BankID signature itself; content_status 'unchanged' means the " +
1643
+ "file still holds what was signed, 'changed' that it was altered " +
1644
+ "since, 'unavailable' that it could not be checked now; " +
1645
+ "signed_by_others_since counts later signatures in a round's PDF; " +
1646
+ "seal.status is 'valid' (protected against changes), 'invalid' or " +
1647
+ "'certificate_revoked' (do not rely on the copy), 'unavailable' (try " +
1648
+ "later) or 'not_applicable' (a signature kept beside the file). Say " +
1649
+ "each in plain words and never show a green mark when any of them " +
1650
+ "failed. Pass " +
1631
1651
  "existingSignatureId for an already-signed file to seed the complete " +
1632
1652
  "state + verify() without re-signing. autoStartToken is set only while " +
1633
1653
  "opening BankID can still help (null once the user has signed or the " +
@@ -1644,19 +1664,21 @@ const HOOKS = [
1644
1664
  "ctx.filestore.signatures.{initiate,status,cancel,verify}.",
1645
1665
  returnShape: {
1646
1666
  status: "'pending' | 'complete' | 'failed' | 'cancelled' | null",
1647
- qr: "string | null // PNG data-URL of the animated BankID QR",
1648
- autoStartToken: "string | null",
1667
+ qr: "string | null // PNG data-URL of the animated BankID QR; render with <Image>, refresh() every 2 s while pending for the next frame",
1668
+ autoStartToken: "string | null // BankID on this device: a button calling Linking.openURL(bankIdAppUrl(autoStartToken))",
1649
1669
  message: "string | null",
1650
1670
  signerName: "string | null",
1651
1671
  signedAt: "string | null",
1652
1672
  hintCode: "string | null // where the order stands, e.g. 'sealing'",
1653
1673
  nameRefusal:
1654
1674
  "{ reason: 'empty' | 'too_long' | 'unsupported_characters' | 'mixed_scripts', characters: string[] } | null",
1655
- verdict: "{ valid, checks, content_status, signed_by_others_since, seal, ... } | null",
1675
+ verdict:
1676
+ "{ valid, checks, content_status: 'unchanged' | 'changed' | 'unavailable', signed_by_others_since: number | null, " +
1677
+ "seal: { status: 'valid' | 'invalid' | 'certificate_revoked' | 'unavailable' | 'not_applicable', sealed_at, certificate_revoked_at, ... }, ... } | null",
1656
1678
  loading: "boolean",
1657
1679
  error: "PermissionError | null // { code, message, retryable }",
1658
1680
  initiate: "() => Promise<{ signature_id, qr, auto_start_token, status, hint_code?, message? }>",
1659
- refresh: "() => Promise<void>",
1681
+ refresh: "() => Promise<void> // the hook never polls by itself",
1660
1682
  cancel: "() => Promise<{ status, hint_code?, message?, signer_name?, signed_at? } | undefined>",
1661
1683
  verify: "() => Promise<verdict>",
1662
1684
  },
@@ -1667,10 +1689,14 @@ const HOOKS = [
1667
1689
  name: "useFileSignatures",
1668
1690
  signature: "useFileSignatures(fileIds)",
1669
1691
  description:
1670
- "Batch 'is this file signed?' lookup for a set of file ids. Returns a map " +
1671
- "of each signed, accessible file id to its latest signature; unsigned " +
1672
- "files are absent. Lets a file browser mark already-signed files in one " +
1673
- "request. Reads ctx.filestore.signatures.list and unwraps { data, meta }.",
1692
+ "Batch 'have I signed this file?' lookup for a set of file ids. Returns " +
1693
+ "a map of each file the SIGNED-IN USER has signed (and can still see) " +
1694
+ "to their own latest signature; a file only others have signed, or " +
1695
+ "nobody has, is absent, so it never tells who else signed. Pass a " +
1696
+ "file's signature_id to useFileSignature(fileId, signatureId) to show " +
1697
+ "and verify it. Who has signed is useFileRoster(), for someone who " +
1698
+ "manages the folder. Reads ctx.filestore.signatures.list and unwraps " +
1699
+ "{ data, meta }.",
1674
1700
  returnShape: {
1675
1701
  signaturesByFileId:
1676
1702
  "{ [fileId]: { signature_id, signer_name, signed_at } }",
@@ -1709,8 +1735,10 @@ const HOOKS = [
1709
1735
  signature: "useSigningRounds(fileIds)",
1710
1736
  description:
1711
1737
  "What the signed-in user may know about the signing round of each file " +
1712
- "in a list, in one batched request. A signing round fixes a PDF and a " +
1713
- "list of signers: it is prepared and confirmed by someone who manages " +
1738
+ "in a list, in one batched request. A signing round fixes a PDF in the " +
1739
+ "project space and a list of signers (other file types are signed one " +
1740
+ "person at a time with useFileSignature() and no round): it is " +
1741
+ "prepared and confirmed by someone who manages " +
1714
1742
  "the file's folder, then each signer signs once with useFileSignature(), " +
1715
1743
  "in any order (there are no turns; the list only orders the places on " +
1716
1744
  "the signature page). byFileId maps a file id to { file_id, can_manage, " +
@@ -1719,7 +1747,8 @@ const HOOKS = [
1719
1747
  "manager nor one of its signers; a signer sees it once it is confirmed, " +
1720
1748
  "with their own place (my_place) and can_sign (the round is open and " +
1721
1749
  "their place is unsigned), and signed_count is null " +
1722
- "for them. locked is 'signing_round' while the file cannot be changed, " +
1750
+ "for them. Each signature is added to the PDF itself and the document " +
1751
+ "is sealed against changes. locked is 'signing_round' while the file cannot be changed, " +
1723
1752
  "'signed' once its content cannot be replaced. roundsEnabled is false " +
1724
1753
  "when the workspace cannot start signing rounds (offer no way to start " +
1725
1754
  "one), and null until the first answer. can_prepare is about the file " +
@@ -1790,7 +1819,11 @@ const HOOKS = [
1790
1819
  "document changed) the hook reads the round again by itself. Code " +
1791
1820
  "SIGNING_ROUNDS_NOT_ENABLED means the workspace cannot start signing " +
1792
1821
  "rounds; check roundsEnabled from useSigningRounds() before offering to " +
1793
- "start one. When fileId or the signed-in user changes, round is null " +
1822
+ "start one, and when it is false say that document signing is not " +
1823
+ "turned on for this workspace and that the platform turns it on. " +
1824
+ "Rounds take PDFs in the project space only (NOT_A_PDF otherwise). A " +
1825
+ "signer signs their place with useFileSignature(fileId), the same " +
1826
+ "BankID flow as any file. When fileId or the signed-in user changes, round is null " +
1794
1827
  "and loading true until the new answer. Reads ctx.filestore.signingRounds.",
1795
1828
  returnShape: {
1796
1829
  round:
@@ -2619,8 +2652,9 @@ const HOOKS = [
2619
2652
  "with the Image primitive) and the hook then POLLS to completion itself " +
2620
2653
  "(pollIntervalMs, default 1000; pass 0 to drive refresh() yourself); " +
2621
2654
  "cancel() aborts; reset() clears the flow. autoStartToken opens the " +
2622
- "provider app on the SAME device (bankid:///?autostarttoken=<token>" +
2623
- "&redirect=null). On complete, `identity` is { provider, name, given_name, " +
2655
+ "provider app on the SAME device: Linking.openURL(bankIdAppUrl(" +
2656
+ "autoStartToken)) opens bankid:///?autostarttoken=<token>&redirect=null. " +
2657
+ "On complete, `identity` is { provider, name, given_name, " +
2624
2658
  "surname, personal_number_masked, subject_hash, identified_at } — there is " +
2625
2659
  "NO raw personal number by design: write personal_number_masked " +
2626
2660
  "(\"19900101-****\") and, if you need to trace the proof, identificationId. " +
@@ -6113,7 +6147,11 @@ const CONTRACT = deepFreeze({
6113
6147
  // `{ name, email }` entries for signers without an account, and
6114
6148
  // `resendLink(signerId, { email })` sends such a signer a new link.
6115
6149
  // The manager's places carry id, kind, email and link.
6116
- version: "1.195.0",
6150
+ // 1.197.0: additive (sc-12063) — new export `bankIdAppUrl(autoStartToken)`,
6151
+ // the link that opens BankID on this device. Signing hooks document
6152
+ // polling, the two ways to start BankID and how to read a verdict;
6153
+ // useFileSignatures is described as the caller's own signatures.
6154
+ version: "1.197.0",
6117
6155
  sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
6118
6156
  hooks: HOOKS,
6119
6157
  primitives: PRIMITIVES,