@sparkvault/sdk-mobile 6.0.1 → 7.0.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.
Files changed (148) hide show
  1. package/README.md +5 -5
  2. package/dist/account.d.ts +4 -3
  3. package/dist/account.js +16 -11
  4. package/dist/account.js.map +1 -1
  5. package/dist/app-sdk/email-address.d.ts +37 -0
  6. package/dist/app-sdk/email-address.js +91 -0
  7. package/dist/app-sdk/email-address.js.map +1 -0
  8. package/dist/app-sdk/encoding.d.ts +64 -0
  9. package/dist/app-sdk/encoding.js +245 -0
  10. package/dist/app-sdk/encoding.js.map +1 -0
  11. package/dist/app-sdk/entropy-contract.d.ts +33 -0
  12. package/dist/app-sdk/entropy-contract.js +51 -0
  13. package/dist/app-sdk/entropy-contract.js.map +1 -0
  14. package/dist/app-sdk/filename.d.ts +93 -0
  15. package/dist/app-sdk/filename.js +161 -0
  16. package/dist/app-sdk/filename.js.map +1 -0
  17. package/dist/app-sdk/forge-url.d.ts +107 -0
  18. package/dist/app-sdk/forge-url.js +222 -0
  19. package/dist/app-sdk/forge-url.js.map +1 -0
  20. package/dist/app-sdk/ids.d.ts +48 -0
  21. package/dist/app-sdk/ids.js +65 -0
  22. package/dist/app-sdk/ids.js.map +1 -0
  23. package/dist/app-sdk/ingot-access-log.d.ts +29 -0
  24. package/dist/app-sdk/ingot-access-log.js +49 -0
  25. package/dist/app-sdk/ingot-access-log.js.map +1 -0
  26. package/dist/app-sdk/phone.d.ts +37 -0
  27. package/dist/app-sdk/phone.js +134 -0
  28. package/dist/app-sdk/phone.js.map +1 -0
  29. package/dist/app-sdk/platform-domains.d.ts +41 -0
  30. package/dist/app-sdk/platform-domains.js +82 -0
  31. package/dist/app-sdk/platform-domains.js.map +1 -0
  32. package/dist/app-sdk/request-path.d.ts +49 -0
  33. package/dist/app-sdk/request-path.js +81 -0
  34. package/dist/app-sdk/request-path.js.map +1 -0
  35. package/dist/app-sdk/transient.d.ts +23 -0
  36. package/dist/app-sdk/transient.js +29 -0
  37. package/dist/app-sdk/transient.js.map +1 -0
  38. package/dist/app-sdk/vat-refusal.d.ts +66 -0
  39. package/dist/app-sdk/vat-refusal.js +69 -0
  40. package/dist/app-sdk/vat-refusal.js.map +1 -0
  41. package/dist/billing.d.ts +9 -17
  42. package/dist/billing.js +14 -17
  43. package/dist/billing.js.map +1 -1
  44. package/dist/config.d.ts +7 -1
  45. package/dist/config.js +10 -17
  46. package/dist/config.js.map +1 -1
  47. package/dist/encoding.d.ts +30 -4
  48. package/dist/encoding.js +89 -83
  49. package/dist/encoding.js.map +1 -1
  50. package/dist/entropy.d.ts +25 -4
  51. package/dist/entropy.js +62 -15
  52. package/dist/entropy.js.map +1 -1
  53. package/dist/entropy.test-d.d.ts +40 -0
  54. package/dist/entropy.test-d.js +12 -0
  55. package/dist/entropy.test-d.js.map +1 -0
  56. package/dist/errors.d.ts +67 -17
  57. package/dist/errors.js +70 -27
  58. package/dist/errors.js.map +1 -1
  59. package/dist/folders.js +8 -7
  60. package/dist/folders.js.map +1 -1
  61. package/dist/http.d.ts +57 -15
  62. package/dist/http.js +125 -138
  63. package/dist/http.js.map +1 -1
  64. package/dist/identity-dialog.js +4 -30
  65. package/dist/identity-dialog.js.map +1 -1
  66. package/dist/identity-input.d.ts +39 -0
  67. package/dist/identity-input.js +59 -0
  68. package/dist/identity-input.js.map +1 -0
  69. package/dist/index.d.ts +6 -5
  70. package/dist/index.js +4 -3
  71. package/dist/index.js.map +1 -1
  72. package/dist/ingots.d.ts +58 -19
  73. package/dist/ingots.js +145 -125
  74. package/dist/ingots.js.map +1 -1
  75. package/dist/mutex.d.ts +1 -2
  76. package/dist/mutex.js +0 -6
  77. package/dist/mutex.js.map +1 -1
  78. package/dist/notify.d.ts +7 -2
  79. package/dist/notify.js +12 -15
  80. package/dist/notify.js.map +1 -1
  81. package/dist/notify.test-d.d.ts +3 -2
  82. package/dist/notify.test-d.js +1 -1
  83. package/dist/products/identity.d.ts +5 -0
  84. package/dist/products/identity.js +40 -35
  85. package/dist/products/identity.js.map +1 -1
  86. package/dist/request-path.d.ts +32 -0
  87. package/dist/request-path.js +35 -0
  88. package/dist/request-path.js.map +1 -0
  89. package/dist/sparks.js +16 -15
  90. package/dist/sparks.js.map +1 -1
  91. package/dist/tus.d.ts +19 -2
  92. package/dist/tus.js +86 -35
  93. package/dist/tus.js.map +1 -1
  94. package/dist/types.d.ts +169 -15
  95. package/dist/users.d.ts +12 -5
  96. package/dist/users.js +27 -19
  97. package/dist/users.js.map +1 -1
  98. package/dist/validation.d.ts +20 -5
  99. package/dist/validation.js +29 -27
  100. package/dist/validation.js.map +1 -1
  101. package/dist/vaults.d.ts +34 -83
  102. package/dist/vaults.js +64 -44
  103. package/dist/vaults.js.map +1 -1
  104. package/dist/vaults.test-d.d.ts +22 -0
  105. package/dist/vaults.test-d.js +14 -0
  106. package/dist/vaults.test-d.js.map +1 -0
  107. package/package.json +4 -2
  108. package/src/account.ts +16 -11
  109. package/src/app-sdk/email-address.js +94 -0
  110. package/src/app-sdk/encoding.js +250 -0
  111. package/src/app-sdk/entropy-contract.js +56 -0
  112. package/src/app-sdk/filename.js +174 -0
  113. package/src/app-sdk/forge-url.js +224 -0
  114. package/src/app-sdk/ids.js +71 -0
  115. package/src/app-sdk/ingot-access-log.js +51 -0
  116. package/src/app-sdk/phone.js +139 -0
  117. package/src/app-sdk/platform-domains.js +99 -0
  118. package/src/app-sdk/request-path.js +81 -0
  119. package/src/app-sdk/transient.js +30 -0
  120. package/src/app-sdk/vat-refusal.js +74 -0
  121. package/src/billing.ts +16 -25
  122. package/src/config.ts +16 -23
  123. package/src/encoding.ts +91 -103
  124. package/src/entropy.test-d.ts +47 -0
  125. package/src/entropy.ts +86 -20
  126. package/src/errors.ts +93 -33
  127. package/src/folders.ts +8 -7
  128. package/src/http.ts +145 -150
  129. package/src/identity-dialog.tsx +4 -37
  130. package/src/identity-input.ts +70 -0
  131. package/src/index.ts +11 -3
  132. package/src/ingots.ts +191 -163
  133. package/src/mutex.ts +1 -8
  134. package/src/notify.test-d.ts +3 -1
  135. package/src/notify.ts +19 -17
  136. package/src/products/identity.ts +45 -39
  137. package/src/request-path.ts +45 -0
  138. package/src/sparks.ts +16 -13
  139. package/src/tus.ts +90 -37
  140. package/src/types.ts +167 -15
  141. package/src/users.ts +27 -17
  142. package/src/validation.ts +30 -24
  143. package/src/vaults.test-d.ts +29 -0
  144. package/src/vaults.ts +87 -153
  145. package/dist/platform-domains.generated.d.ts +0 -2
  146. package/dist/platform-domains.generated.js +0 -16
  147. package/dist/platform-domains.generated.js.map +0 -1
  148. package/src/platform-domains.generated.ts +0 -17
@@ -0,0 +1,51 @@
1
+ // GENERATED FILE — do not edit by hand.
2
+ // Source of truth: packages/app-sdk/src/entropy-contract.js
3
+ // Regenerate with: pnpm --filter @sparkvault/sdk-mobile build
4
+ /**
5
+ * The request contract of the entropy endpoint (POST /v1/entropy/generate):
6
+ * the output formats it serves and how many bytes one request may ask for.
7
+ *
8
+ * Core's route enforces it; the console and both SDKs hold a request to it
9
+ * before sending, so a request the server would refuse is refused where it is
10
+ * made. Dependency-free: sdk-js bundles it and sdk-mobile carries a generated
11
+ * copy.
12
+ */
13
+ /** Output formats the endpoint serves. `bytes` returns a number array; every other format a string. */
14
+ export const ENTROPY_FORMATS = Object.freeze([
15
+ 'hex',
16
+ 'base64',
17
+ 'base64url',
18
+ 'alphanumeric',
19
+ 'alphanumeric-mixed',
20
+ 'password',
21
+ 'numeric',
22
+ 'uuid',
23
+ 'bytes',
24
+ ]);
25
+ /** The hardware ceiling on one entropy draw, in bytes. */
26
+ export const MAX_DRAW_BYTES = 1024;
27
+ /**
28
+ * Formats whose characters are drawn from an alphabet by rejection sampling.
29
+ * They open with two raw bytes per output character, so one request's output
30
+ * caps at half a draw. `numeric` rejects so few bytes that it opens with one
31
+ * byte per digit and keeps the full ceiling.
32
+ */
33
+ export const CHARSET_FORMATS = Object.freeze(['alphanumeric', 'alphanumeric-mixed', 'password']);
34
+ /**
35
+ * @param {unknown} format
36
+ * @returns {boolean} Whether the endpoint serves this output format
37
+ */
38
+ export function isEntropyFormat(format) {
39
+ return ENTROPY_FORMATS.includes(format);
40
+ }
41
+ /**
42
+ * The most bytes one request may ask for in a format (`num_bytes` runs from 1
43
+ * to this). A `uuid` always draws 16 bytes, whatever the request names.
44
+ *
45
+ * @param {string} format - One of ENTROPY_FORMATS
46
+ * @returns {number}
47
+ */
48
+ export function maxBytesFor(format) {
49
+ return CHARSET_FORMATS.includes(format) ? MAX_DRAW_BYTES / 2 : MAX_DRAW_BYTES;
50
+ }
51
+ //# sourceMappingURL=entropy-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy-contract.js","sourceRoot":"","sources":["../../src/app-sdk/entropy-contract.js"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,4DAA4D;AAC5D,8DAA8D;AAE9D;;;;;;;;GAQG;AAEH,uGAAuG;AACvG,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,KAAK;IACL,QAAQ;IACR,WAAW;IACX,cAAc;IACd,oBAAoB;IACpB,UAAU;IACV,SAAS;IACT,MAAM;IACN,OAAO;CACR,CAAC,CAAC;AAEH,0DAA0D;AAC1D,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AAEnC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,oBAAoB,EAAE,UAAU,CAAC,CAAC,CAAC;AAEjG;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAM;IACpC,OAAO,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAAM;IAChC,OAAO,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;AAChF,CAAC"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * What stops `name` from being stored as a file name, or null when nothing
3
+ * does. Length and emptiness are the storing runtime's own limits.
4
+ *
5
+ * @param {string} name
6
+ * @returns {string|null} One of FILENAME_PROBLEMS, or null
7
+ */
8
+ export function storableFilenameProblem(name: string): string | null;
9
+ /**
10
+ * A name as it is saved to a device: every unsafe character replaced by `_`.
11
+ *
12
+ * @param {string} name
13
+ * @returns {string}
14
+ */
15
+ export function toSavedFilename(name: string): string;
16
+ /**
17
+ * The name a download is saved under: the file's own name by the saved-name
18
+ * rule (toSavedFilename), or SAVED_FILENAME_FALLBACK when it has none.
19
+ *
20
+ * @param {string|null|undefined} name
21
+ * @returns {string}
22
+ */
23
+ export function savedFilename(name: string | null | undefined): string;
24
+ /**
25
+ * A storable name derived from text nobody chose as a file name (a note's
26
+ * title, a device's file name): every unsafe or non-portable character
27
+ * replaced by `_`. It can still be only dots or spaces, which a caller that
28
+ * derives a name must refuse or replace itself.
29
+ *
30
+ * @param {string} text
31
+ * @returns {string}
32
+ */
33
+ export function toStorableFilename(text: string): string;
34
+ /**
35
+ * A name's stem and extension: "report.pdf" is { stem: "report", extension:
36
+ * ".pdf" }, "Plan.note.html" is { stem: "Plan", extension: ".note.html" }, and
37
+ * a leading dot is part of the stem.
38
+ *
39
+ * @param {string} name
40
+ * @returns {{ stem: string, extension: string }}
41
+ */
42
+ export function splitExtension(name: string): {
43
+ stem: string;
44
+ extension: string;
45
+ };
46
+ /**
47
+ * The longest prefix of `text` within `maxLength` UTF-16 units that splits no
48
+ * character.
49
+ *
50
+ * @param {string} text
51
+ * @param {number} maxLength
52
+ * @returns {string}
53
+ */
54
+ export function truncateToLength(text: string, maxLength: number): string;
55
+ /**
56
+ * `name` shortened to at most `maxLength` UTF-16 units, keeping its extension:
57
+ * the stem gives way, and a name whose extension leaves no room for a stem is
58
+ * shortened as a whole.
59
+ *
60
+ * @param {string} name
61
+ * @param {number} [maxLength=INGOT_NAME_MAX]
62
+ * @returns {string}
63
+ */
64
+ export function fitName(name: string, maxLength?: number): string;
65
+ /** Why a name cannot be stored, as storableFilenameProblem reports it. */
66
+ export const FILENAME_PROBLEMS: Readonly<{
67
+ UNSAFE_CHARACTER: "unsafe_character";
68
+ NON_PORTABLE_CHARACTER: "non_portable_character";
69
+ ONLY_DOTS_OR_SPACES: "only_dots_or_spaces";
70
+ }>;
71
+ /** The one name a download is saved under when its file has no name. */
72
+ export const SAVED_FILENAME_FALLBACK: "download";
73
+ /**
74
+ * The saved-name rule as the source of a classic browser script, for a page
75
+ * that cannot import an ES module (the x.sv reveal page): it declares
76
+ * `savedFilename` and everything it reads at the script's top level, built
77
+ * from the functions and constants above, so the page runs this rule, not a
78
+ * copy. A new module-scope binding the rule reads must be added here.
79
+ */
80
+ export const SAVED_FILENAME_SCRIPT: string;
81
+ /** The longest name an ingot stores, in UTF-16 code units. */
82
+ export const INGOT_NAME_MAX: 255;
83
+ /**
84
+ * Two-part extensions that mark a SparkVault document, by the editor that
85
+ * opens it. A name's extension is the whole marker, so a numbered or
86
+ * shortened copy still opens in its editor ("Plan (2).note.html", never
87
+ * "Plan.note (2).html"); the console and the mobile app classify a document by
88
+ * these lists (./ingot-kind.js).
89
+ */
90
+ export const WHITEBOARD_MARKER_EXTENSIONS: readonly string[];
91
+ export const NOTE_MARKER_EXTENSIONS: readonly string[];
92
+ /** Every SparkVault document marker. */
93
+ export const DOCUMENT_MARKER_EXTENSIONS: readonly string[];
@@ -0,0 +1,161 @@
1
+ // GENERATED FILE — do not edit by hand.
2
+ // Source of truth: packages/app-sdk/src/filename.js
3
+ // Regenerate with: pnpm --filter @sparkvault/sdk-mobile build
4
+ /**
5
+ * The one rule for which characters a file name may hold, shared by every
6
+ * runtime that stores a name (Core refuses them at ingest, and clients check
7
+ * before they send) and every runtime that saves a stored name to a device
8
+ * (Forge's Content-Disposition, the web console's download, the x.sv reveal
9
+ * page, the mobile share sheet). A download saves under the file's current
10
+ * name by this rule, or under SAVED_FILENAME_FALLBACK when it has none.
11
+ *
12
+ * UNSAFE characters are never stored, and are replaced in any name saved to a
13
+ * device: path separators, control characters (C0, DEL and C1), and the
14
+ * invisible bidirectional controls that make a name display a different
15
+ * extension than it has (`invoice<U+202E>fdp.exe` shows as `invoiceexe.pdf`).
16
+ *
17
+ * NON-PORTABLE characters (`: * ? " < > |`) are refused by the file systems a
18
+ * name is saved to, so they are never stored either. A saved name keeps them:
19
+ * a stored name cannot hold one, and Forge carries a name's exact text in the
20
+ * RFC 5987 `filename*` parameter.
21
+ *
22
+ * Pure and import-free, so a browser, a container and a Lambda load it alike;
23
+ * sdk-mobile mirrors it at build time (scripts/generate-app-sdk-mirrors.mjs).
24
+ */
25
+ /** Path separators, control characters and bidirectional text controls. */
26
+ const UNSAFE_FILENAME_CHARACTERS = /[\\/\p{Cc}\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/u;
27
+ /** Characters the file systems a name is saved to refuse. */
28
+ const NON_PORTABLE_FILENAME_CHARACTERS = /[:*?"<>|]/;
29
+ /** Why a name cannot be stored, as storableFilenameProblem reports it. */
30
+ export const FILENAME_PROBLEMS = Object.freeze({
31
+ UNSAFE_CHARACTER: 'unsafe_character',
32
+ NON_PORTABLE_CHARACTER: 'non_portable_character',
33
+ ONLY_DOTS_OR_SPACES: 'only_dots_or_spaces'
34
+ });
35
+ const ONLY_DOTS_OR_SPACES = /^[\s.]+$/;
36
+ /**
37
+ * What stops `name` from being stored as a file name, or null when nothing
38
+ * does. Length and emptiness are the storing runtime's own limits.
39
+ *
40
+ * @param {string} name
41
+ * @returns {string|null} One of FILENAME_PROBLEMS, or null
42
+ */
43
+ export function storableFilenameProblem(name) {
44
+ if (UNSAFE_FILENAME_CHARACTERS.test(name))
45
+ return FILENAME_PROBLEMS.UNSAFE_CHARACTER;
46
+ if (NON_PORTABLE_FILENAME_CHARACTERS.test(name))
47
+ return FILENAME_PROBLEMS.NON_PORTABLE_CHARACTER;
48
+ if (ONLY_DOTS_OR_SPACES.test(name))
49
+ return FILENAME_PROBLEMS.ONLY_DOTS_OR_SPACES;
50
+ return null;
51
+ }
52
+ /**
53
+ * A name as it is saved to a device: every unsafe character replaced by `_`.
54
+ *
55
+ * @param {string} name
56
+ * @returns {string}
57
+ */
58
+ export function toSavedFilename(name) {
59
+ return name.replace(new RegExp(UNSAFE_FILENAME_CHARACTERS.source, 'gu'), '_');
60
+ }
61
+ /** The one name a download is saved under when its file has no name. */
62
+ export const SAVED_FILENAME_FALLBACK = 'download';
63
+ /**
64
+ * The name a download is saved under: the file's own name by the saved-name
65
+ * rule (toSavedFilename), or SAVED_FILENAME_FALLBACK when it has none.
66
+ *
67
+ * @param {string|null|undefined} name
68
+ * @returns {string}
69
+ */
70
+ export function savedFilename(name) {
71
+ return typeof name === 'string' && name !== '' ? toSavedFilename(name) : SAVED_FILENAME_FALLBACK;
72
+ }
73
+ /**
74
+ * The saved-name rule as the source of a classic browser script, for a page
75
+ * that cannot import an ES module (the x.sv reveal page): it declares
76
+ * `savedFilename` and everything it reads at the script's top level, built
77
+ * from the functions and constants above, so the page runs this rule, not a
78
+ * copy. A new module-scope binding the rule reads must be added here.
79
+ */
80
+ export const SAVED_FILENAME_SCRIPT = [
81
+ `var UNSAFE_FILENAME_CHARACTERS = ${UNSAFE_FILENAME_CHARACTERS};`,
82
+ `var SAVED_FILENAME_FALLBACK = ${JSON.stringify(SAVED_FILENAME_FALLBACK)};`,
83
+ toSavedFilename,
84
+ savedFilename
85
+ ].join('\n');
86
+ /**
87
+ * A storable name derived from text nobody chose as a file name (a note's
88
+ * title, a device's file name): every unsafe or non-portable character
89
+ * replaced by `_`. It can still be only dots or spaces, which a caller that
90
+ * derives a name must refuse or replace itself.
91
+ *
92
+ * @param {string} text
93
+ * @returns {string}
94
+ */
95
+ export function toStorableFilename(text) {
96
+ return toSavedFilename(text).replace(new RegExp(NON_PORTABLE_FILENAME_CHARACTERS.source, 'g'), '_');
97
+ }
98
+ /** The longest name an ingot stores, in UTF-16 code units. */
99
+ export const INGOT_NAME_MAX = 255;
100
+ /**
101
+ * Two-part extensions that mark a SparkVault document, by the editor that
102
+ * opens it. A name's extension is the whole marker, so a numbered or
103
+ * shortened copy still opens in its editor ("Plan (2).note.html", never
104
+ * "Plan.note (2).html"); the console and the mobile app classify a document by
105
+ * these lists (./ingot-kind.js).
106
+ */
107
+ export const WHITEBOARD_MARKER_EXTENSIONS = Object.freeze(['.whiteboard.svg', '.whiteboard.png']);
108
+ export const NOTE_MARKER_EXTENSIONS = Object.freeze(['.note.html', '.note.htm']);
109
+ /** Every SparkVault document marker. */
110
+ export const DOCUMENT_MARKER_EXTENSIONS = Object.freeze([...WHITEBOARD_MARKER_EXTENSIONS, ...NOTE_MARKER_EXTENSIONS]);
111
+ /**
112
+ * A name's stem and extension: "report.pdf" is { stem: "report", extension:
113
+ * ".pdf" }, "Plan.note.html" is { stem: "Plan", extension: ".note.html" }, and
114
+ * a leading dot is part of the stem.
115
+ *
116
+ * @param {string} name
117
+ * @returns {{ stem: string, extension: string }}
118
+ */
119
+ export function splitExtension(name) {
120
+ const lowerName = name.toLowerCase();
121
+ const marker = DOCUMENT_MARKER_EXTENSIONS.find((candidate) => lowerName.endsWith(candidate) && lowerName.length > candidate.length);
122
+ const dot = marker ? name.length - marker.length : name.lastIndexOf('.');
123
+ return dot > 0
124
+ ? { stem: name.slice(0, dot), extension: name.slice(dot) }
125
+ : { stem: name, extension: '' };
126
+ }
127
+ /**
128
+ * The longest prefix of `text` within `maxLength` UTF-16 units that splits no
129
+ * character.
130
+ *
131
+ * @param {string} text
132
+ * @param {number} maxLength
133
+ * @returns {string}
134
+ */
135
+ export function truncateToLength(text, maxLength) {
136
+ let truncated = '';
137
+ for (const character of text) {
138
+ if (truncated.length + character.length > maxLength)
139
+ break;
140
+ truncated += character;
141
+ }
142
+ return truncated;
143
+ }
144
+ /**
145
+ * `name` shortened to at most `maxLength` UTF-16 units, keeping its extension:
146
+ * the stem gives way, and a name whose extension leaves no room for a stem is
147
+ * shortened as a whole.
148
+ *
149
+ * @param {string} name
150
+ * @param {number} [maxLength=INGOT_NAME_MAX]
151
+ * @returns {string}
152
+ */
153
+ export function fitName(name, maxLength = INGOT_NAME_MAX) {
154
+ if (name.length <= maxLength)
155
+ return name;
156
+ const { stem, extension } = splitExtension(name);
157
+ return extension.length < maxLength
158
+ ? `${truncateToLength(stem, maxLength - extension.length)}${extension}`
159
+ : truncateToLength(name, maxLength);
160
+ }
161
+ //# sourceMappingURL=filename.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filename.js","sourceRoot":"","sources":["../../src/app-sdk/filename.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Forge's own host, the one a platform-issued transfer URL names.
3
+ * @param {string} hostname
4
+ * @returns {boolean}
5
+ */
6
+ export function isForgeHost(hostname: string): boolean;
7
+ /**
8
+ * The URL Core issues for a transfer: Forge's operation endpoint carrying the
9
+ * ISTK.
10
+ *
11
+ * @param {'encrypt'|'decrypt'} operation
12
+ * @param {string} istk
13
+ * @returns {string}
14
+ */
15
+ export function forgeTransferUrl(operation: "encrypt" | "decrypt", istk: string): string;
16
+ /**
17
+ * Read a Core-issued transfer URL. It must be written in printable ASCII, be
18
+ * https, carry no userinfo, port or fragment, name an allowed host, have the
19
+ * operation as its whole path, and carry exactly one base64url `istk`. Other
20
+ * query parameters (a preview URL's `disposition=inline`) ride along; the query
21
+ * is read the way a form encodes one (`+` is a space, escapes are decoded).
22
+ *
23
+ * A download fetches the URL it read as it was written; an upload is created
24
+ * at `endpoint` with the ISTK in a header.
25
+ *
26
+ * @param {unknown} value
27
+ * @param {Object} options
28
+ * @param {'encrypt'|'decrypt'} options.operation - The transfer the URL must name
29
+ * @param {(hostname: string) => boolean} [options.isAllowedHost] - Forge's own
30
+ * host by default; a published SDK passes its configured allowlist. It is
31
+ * handed the lowercased host name.
32
+ * @returns {{ ok: true, origin: string, endpoint: string, istk: string } | { ok: false, reason: string }}
33
+ * `origin` is the scheme and host; `endpoint` is where a tus upload is created.
34
+ */
35
+ export function readForgeTransferUrl(value: unknown, { operation, isAllowedHost }: {
36
+ operation: "encrypt" | "decrypt";
37
+ isAllowedHost?: ((hostname: string) => boolean) | undefined;
38
+ }): {
39
+ ok: true;
40
+ origin: string;
41
+ endpoint: string;
42
+ istk: string;
43
+ } | {
44
+ ok: false;
45
+ reason: string;
46
+ };
47
+ /**
48
+ * Whether a value is exactly the URL Core issues for a transfer
49
+ * (`forgeTransferUrl`), with nothing added or re-spelled. A client deployed
50
+ * with Core may demand this; a published SDK, which must accept what a newer
51
+ * Core adds, reads with readForgeTransferUrl.
52
+ *
53
+ * @param {unknown} value
54
+ * @param {'encrypt'|'decrypt'} operation
55
+ * @returns {boolean}
56
+ */
57
+ export function isIssuedForgeTransferUrl(value: unknown, operation: "encrypt" | "decrypt"): boolean;
58
+ /**
59
+ * Place the session a tus create answered with (its `Location`) under the
60
+ * endpoint the session was created at. Every later request carries the ISTK
61
+ * and the file's bytes, so the session must be one segment directly under the
62
+ * endpoint's path on the endpoint's own origin: `<endpoint path>/<session>` as
63
+ * Forge sends it, or the same with the endpoint's origin written in front.
64
+ *
65
+ * @param {unknown} location
66
+ * @param {string} endpoint - An `endpoint` readForgeTransferUrl returned
67
+ * @returns {string|null} The session URL, or null when the answer points anywhere else
68
+ */
69
+ export function resolveForgeSessionUrl(location: unknown, endpoint: string): string | null;
70
+ /**
71
+ * Read a tus session URL a client kept to resume an upload: a session Forge
72
+ * opened directly under the operation's endpoint on an allowed host, exactly
73
+ * as resolveForgeSessionUrl placed it when the session was created. A resumed
74
+ * session receives the ISTK and the file's bytes, so it is held to the rule a
75
+ * created one was.
76
+ *
77
+ * @param {unknown} value
78
+ * @param {Object} options
79
+ * @param {'encrypt'|'decrypt'} options.operation - The transfer the session belongs to
80
+ * @param {(hostname: string) => boolean} [options.isAllowedHost] - As for readForgeTransferUrl
81
+ * @returns {{ ok: true, url: string } | { ok: false, reason: string }}
82
+ */
83
+ export function readForgeSessionUrl(value: unknown, { operation, isAllowedHost }: {
84
+ operation: "encrypt" | "decrypt";
85
+ isAllowedHost?: ((hostname: string) => boolean) | undefined;
86
+ }): {
87
+ ok: true;
88
+ url: string;
89
+ } | {
90
+ ok: false;
91
+ reason: string;
92
+ };
93
+ /** Why a transfer URL was refused; each caller raises its own error for the reason. */
94
+ export const FORGE_URL_REFUSAL: Readonly<{
95
+ /** Not a string, or not an absolute URL written in printable ASCII. */
96
+ INVALID: "invalid_url";
97
+ /** Not https: the credential and the bytes would cross the network in the clear. */
98
+ NOT_HTTPS: "not_https";
99
+ /** Userinfo, a port or a fragment, none of which Core ever issues. */
100
+ UNSAFE_PARTS: "unsafe_parts";
101
+ /** A host the caller does not send transfers to, or one that is not a DNS name. */
102
+ HOST: "host_not_allowed";
103
+ /** A path other than the transfer operation's own. */
104
+ OPERATION: "wrong_operation";
105
+ /** No ISTK, more than one, or one that is not base64url. */
106
+ ISTK: "bad_istk";
107
+ }>;
@@ -0,0 +1,222 @@
1
+ // GENERATED FILE — do not edit by hand.
2
+ // Source of truth: packages/app-sdk/src/forge-url.js
3
+ // Regenerate with: pnpm --filter @sparkvault/sdk-mobile build
4
+ /**
5
+ * Forge transfer URLs: the one reading of the URL Core issues for an ingot
6
+ * transfer, `https://forge.sparkvault.com/{encrypt|decrypt}?istk=…`, and of the
7
+ * session URL a tus upload continues at, whether just created or kept (resumed,
8
+ * probed or terminated).
9
+ *
10
+ * The URL carries the ISTK, a bearer credential for one transfer, and an upload
11
+ * sends the plaintext after it, so every client reads the URL here before a
12
+ * byte or the credential leaves: the Node tus client (forge-tus), both SDKs
13
+ * (sdk-js bundles this module; sdk-mobile carries a generated copy), the
14
+ * console, the Slack app, the HubSpot record tab and the Salesforce record
15
+ * panel (each a generated copy). Core builds the URL with `forgeTransferUrl`.
16
+ *
17
+ * Both readings are string rules over the one shape Core and Forge write, not
18
+ * a URL parser: a React Native host need not provide a WHATWG `URL` (React
19
+ * Native's own resolves relative references and serializes query strings
20
+ * differently), and a shape this strict leaves nothing for a parser to
21
+ * normalize, so a transfer goes to exactly the host and path that was checked.
22
+ *
23
+ * Dependency-free and free of runtime globals.
24
+ */
25
+ import { SPARKVAULT_FORGE_HOST } from './platform-domains.js';
26
+ /** Why a transfer URL was refused; each caller raises its own error for the reason. */
27
+ export const FORGE_URL_REFUSAL = Object.freeze({
28
+ /** Not a string, or not an absolute URL written in printable ASCII. */
29
+ INVALID: 'invalid_url',
30
+ /** Not https: the credential and the bytes would cross the network in the clear. */
31
+ NOT_HTTPS: 'not_https',
32
+ /** Userinfo, a port or a fragment, none of which Core ever issues. */
33
+ UNSAFE_PARTS: 'unsafe_parts',
34
+ /** A host the caller does not send transfers to, or one that is not a DNS name. */
35
+ HOST: 'host_not_allowed',
36
+ /** A path other than the transfer operation's own. */
37
+ OPERATION: 'wrong_operation',
38
+ /** No ISTK, more than one, or one that is not base64url. */
39
+ ISTK: 'bad_istk',
40
+ });
41
+ /** An ISTK is base64url; its length is Core's to choose, so it is not pinned. */
42
+ const ISTK_PATTERN = /^[A-Za-z0-9_-]+$/;
43
+ /** A tus session Forge opens under its endpoint (`tus_<hex>`): one segment, no dot segment or escape. */
44
+ const SESSION_ID_PATTERN = /^[A-Za-z0-9_-]+$/;
45
+ /** Printable ASCII with no space: every character a transfer URL is written in. */
46
+ const URL_TEXT = /^[\x21-\x7e]+$/;
47
+ /** An absolute URL cut at its delimiters: scheme, authority, path, query, fragment. */
48
+ const ABSOLUTE_URL = /^([A-Za-z][A-Za-z0-9+.-]*):\/\/([^/?#]*)([^?#]*)(?:\?([^#]*))?(#.*)?$/;
49
+ /** A DNS name: letter-digit-hyphen labels joined by dots (compared lowercased). */
50
+ const HOSTNAME = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*$/;
51
+ /**
52
+ * Forge's own host, the one a platform-issued transfer URL names.
53
+ * @param {string} hostname
54
+ * @returns {boolean}
55
+ */
56
+ export function isForgeHost(hostname) {
57
+ return hostname === SPARKVAULT_FORGE_HOST;
58
+ }
59
+ /**
60
+ * The URL Core issues for a transfer: Forge's operation endpoint carrying the
61
+ * ISTK.
62
+ *
63
+ * @param {'encrypt'|'decrypt'} operation
64
+ * @param {string} istk
65
+ * @returns {string}
66
+ */
67
+ export function forgeTransferUrl(operation, istk) {
68
+ return `https://${SPARKVAULT_FORGE_HOST}/${operation}?istk=${encodeURIComponent(istk)}`;
69
+ }
70
+ /**
71
+ * Read a Core-issued transfer URL. It must be written in printable ASCII, be
72
+ * https, carry no userinfo, port or fragment, name an allowed host, have the
73
+ * operation as its whole path, and carry exactly one base64url `istk`. Other
74
+ * query parameters (a preview URL's `disposition=inline`) ride along; the query
75
+ * is read the way a form encodes one (`+` is a space, escapes are decoded).
76
+ *
77
+ * A download fetches the URL it read as it was written; an upload is created
78
+ * at `endpoint` with the ISTK in a header.
79
+ *
80
+ * @param {unknown} value
81
+ * @param {Object} options
82
+ * @param {'encrypt'|'decrypt'} options.operation - The transfer the URL must name
83
+ * @param {(hostname: string) => boolean} [options.isAllowedHost] - Forge's own
84
+ * host by default; a published SDK passes its configured allowlist. It is
85
+ * handed the lowercased host name.
86
+ * @returns {{ ok: true, origin: string, endpoint: string, istk: string } | { ok: false, reason: string }}
87
+ * `origin` is the scheme and host; `endpoint` is where a tus upload is created.
88
+ */
89
+ export function readForgeTransferUrl(value, { operation, isAllowedHost = isForgeHost }) {
90
+ const url = readHttpsUrl(value);
91
+ if (!url.ok)
92
+ return url;
93
+ if (!isAllowedHost(url.hostname))
94
+ return refused(FORGE_URL_REFUSAL.HOST);
95
+ if (url.path !== `/${operation}`)
96
+ return refused(FORGE_URL_REFUSAL.OPERATION);
97
+ const istks = queryValues(url.query, 'istk');
98
+ if (istks.length !== 1 || !ISTK_PATTERN.test(istks[0]))
99
+ return refused(FORGE_URL_REFUSAL.ISTK);
100
+ const origin = `https://${url.hostname}`;
101
+ return { ok: true, origin, endpoint: `${origin}/${operation}`, istk: istks[0] };
102
+ }
103
+ /**
104
+ * Whether a value is exactly the URL Core issues for a transfer
105
+ * (`forgeTransferUrl`), with nothing added or re-spelled. A client deployed
106
+ * with Core may demand this; a published SDK, which must accept what a newer
107
+ * Core adds, reads with readForgeTransferUrl.
108
+ *
109
+ * @param {unknown} value
110
+ * @param {'encrypt'|'decrypt'} operation
111
+ * @returns {boolean}
112
+ */
113
+ export function isIssuedForgeTransferUrl(value, operation) {
114
+ const read = readForgeTransferUrl(value, { operation });
115
+ return read.ok && value === forgeTransferUrl(operation, read.istk);
116
+ }
117
+ /**
118
+ * Place the session a tus create answered with (its `Location`) under the
119
+ * endpoint the session was created at. Every later request carries the ISTK
120
+ * and the file's bytes, so the session must be one segment directly under the
121
+ * endpoint's path on the endpoint's own origin: `<endpoint path>/<session>` as
122
+ * Forge sends it, or the same with the endpoint's origin written in front.
123
+ *
124
+ * @param {unknown} location
125
+ * @param {string} endpoint - An `endpoint` readForgeTransferUrl returned
126
+ * @returns {string|null} The session URL, or null when the answer points anywhere else
127
+ */
128
+ export function resolveForgeSessionUrl(location, endpoint) {
129
+ const base = readHttpsUrl(endpoint);
130
+ if (!base.ok || base.query !== undefined || typeof location !== 'string' || !URL_TEXT.test(location)) {
131
+ return null;
132
+ }
133
+ const origin = `https://${base.hostname}`;
134
+ let path = null;
135
+ if (location.startsWith(`${origin}/`)) {
136
+ path = location.slice(origin.length);
137
+ }
138
+ else if (location.startsWith('/') && !location.startsWith('//')) {
139
+ path = location;
140
+ }
141
+ if (path === null || !path.startsWith(`${base.path}/`))
142
+ return null;
143
+ const session = path.slice(base.path.length + 1);
144
+ return SESSION_ID_PATTERN.test(session) ? `${origin}${base.path}/${session}` : null;
145
+ }
146
+ /**
147
+ * Read a tus session URL a client kept to resume an upload: a session Forge
148
+ * opened directly under the operation's endpoint on an allowed host, exactly
149
+ * as resolveForgeSessionUrl placed it when the session was created. A resumed
150
+ * session receives the ISTK and the file's bytes, so it is held to the rule a
151
+ * created one was.
152
+ *
153
+ * @param {unknown} value
154
+ * @param {Object} options
155
+ * @param {'encrypt'|'decrypt'} options.operation - The transfer the session belongs to
156
+ * @param {(hostname: string) => boolean} [options.isAllowedHost] - As for readForgeTransferUrl
157
+ * @returns {{ ok: true, url: string } | { ok: false, reason: string }}
158
+ */
159
+ export function readForgeSessionUrl(value, { operation, isAllowedHost = isForgeHost }) {
160
+ const url = readHttpsUrl(value);
161
+ if (!url.ok)
162
+ return url;
163
+ if (!isAllowedHost(url.hostname))
164
+ return refused(FORGE_URL_REFUSAL.HOST);
165
+ const session = resolveForgeSessionUrl(value, `https://${url.hostname}/${operation}`);
166
+ return session === null ? refused(FORGE_URL_REFUSAL.OPERATION) : { ok: true, url: session };
167
+ }
168
+ /**
169
+ * Cut an https URL into its host name, path and query by string rules alone.
170
+ * @param {unknown} value
171
+ * @returns {{ ok: true, hostname: string, path: string, query: string|undefined } | { ok: false, reason: string }}
172
+ */
173
+ function readHttpsUrl(value) {
174
+ if (typeof value !== 'string' || !URL_TEXT.test(value))
175
+ return refused(FORGE_URL_REFUSAL.INVALID);
176
+ const parts = ABSOLUTE_URL.exec(value);
177
+ if (!parts)
178
+ return refused(FORGE_URL_REFUSAL.INVALID);
179
+ const [, scheme, authority, path, query, fragment] = parts;
180
+ if (scheme.toLowerCase() !== 'https')
181
+ return refused(FORGE_URL_REFUSAL.NOT_HTTPS);
182
+ if (authority.includes('@') || /:[0-9]*$/.test(authority) || fragment !== undefined) {
183
+ return refused(FORGE_URL_REFUSAL.UNSAFE_PARTS);
184
+ }
185
+ const hostname = authority.toLowerCase();
186
+ if (!HOSTNAME.test(hostname))
187
+ return refused(FORGE_URL_REFUSAL.HOST);
188
+ return { ok: true, hostname, path, query };
189
+ }
190
+ /**
191
+ * Every value of one query parameter, names and values read as a form encodes
192
+ * them: `+` is a space and escapes are decoded (text that is not a valid
193
+ * escape sequence stays as written).
194
+ * @param {string|undefined} query
195
+ * @param {string} name
196
+ * @returns {string[]}
197
+ */
198
+ function queryValues(query, name) {
199
+ const values = [];
200
+ for (const pair of (query ?? '').split('&')) {
201
+ if (!pair)
202
+ continue;
203
+ const equals = pair.indexOf('=');
204
+ const key = formDecode(equals === -1 ? pair : pair.slice(0, equals));
205
+ if (key === name)
206
+ values.push(equals === -1 ? '' : formDecode(pair.slice(equals + 1)));
207
+ }
208
+ return values;
209
+ }
210
+ function formDecode(text) {
211
+ const spaced = text.replace(/\+/g, ' ');
212
+ try {
213
+ return decodeURIComponent(spaced);
214
+ }
215
+ catch {
216
+ return spaced;
217
+ }
218
+ }
219
+ function refused(reason) {
220
+ return { ok: false, reason };
221
+ }
222
+ //# sourceMappingURL=forge-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forge-url.js","sourceRoot":"","sources":["../../src/app-sdk/forge-url.js"],"names":[],"mappings":"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"}