@sparkvault/sdk-mobile 6.0.2 → 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.
- package/README.md +5 -5
- package/dist/account.d.ts +4 -3
- package/dist/account.js +16 -11
- package/dist/account.js.map +1 -1
- package/dist/app-sdk/email-address.d.ts +37 -0
- package/dist/app-sdk/email-address.js +91 -0
- package/dist/app-sdk/email-address.js.map +1 -0
- package/dist/app-sdk/encoding.d.ts +64 -0
- package/dist/app-sdk/encoding.js +245 -0
- package/dist/app-sdk/encoding.js.map +1 -0
- package/dist/app-sdk/entropy-contract.d.ts +33 -0
- package/dist/app-sdk/entropy-contract.js +51 -0
- package/dist/app-sdk/entropy-contract.js.map +1 -0
- package/dist/app-sdk/filename.d.ts +93 -0
- package/dist/app-sdk/filename.js +161 -0
- package/dist/app-sdk/filename.js.map +1 -0
- package/dist/app-sdk/forge-url.d.ts +107 -0
- package/dist/app-sdk/forge-url.js +222 -0
- package/dist/app-sdk/forge-url.js.map +1 -0
- package/dist/app-sdk/ids.d.ts +48 -0
- package/dist/app-sdk/ids.js +65 -0
- package/dist/app-sdk/ids.js.map +1 -0
- package/dist/app-sdk/ingot-access-log.d.ts +29 -0
- package/dist/app-sdk/ingot-access-log.js +49 -0
- package/dist/app-sdk/ingot-access-log.js.map +1 -0
- package/dist/app-sdk/phone.d.ts +37 -0
- package/dist/app-sdk/phone.js +134 -0
- package/dist/app-sdk/phone.js.map +1 -0
- package/dist/app-sdk/platform-domains.d.ts +41 -0
- package/dist/app-sdk/platform-domains.js +82 -0
- package/dist/app-sdk/platform-domains.js.map +1 -0
- package/dist/app-sdk/request-path.d.ts +49 -0
- package/dist/app-sdk/request-path.js +81 -0
- package/dist/app-sdk/request-path.js.map +1 -0
- package/dist/app-sdk/transient.d.ts +23 -0
- package/dist/app-sdk/transient.js +29 -0
- package/dist/app-sdk/transient.js.map +1 -0
- package/dist/app-sdk/vat-refusal.d.ts +66 -0
- package/dist/app-sdk/vat-refusal.js +69 -0
- package/dist/app-sdk/vat-refusal.js.map +1 -0
- package/dist/billing.d.ts +9 -17
- package/dist/billing.js +14 -17
- package/dist/billing.js.map +1 -1
- package/dist/config.d.ts +7 -1
- package/dist/config.js +10 -17
- package/dist/config.js.map +1 -1
- package/dist/encoding.d.ts +30 -4
- package/dist/encoding.js +89 -83
- package/dist/encoding.js.map +1 -1
- package/dist/entropy.d.ts +25 -4
- package/dist/entropy.js +62 -15
- package/dist/entropy.js.map +1 -1
- package/dist/entropy.test-d.d.ts +40 -0
- package/dist/entropy.test-d.js +12 -0
- package/dist/entropy.test-d.js.map +1 -0
- package/dist/errors.d.ts +67 -17
- package/dist/errors.js +70 -27
- package/dist/errors.js.map +1 -1
- package/dist/folders.js +8 -7
- package/dist/folders.js.map +1 -1
- package/dist/http.d.ts +57 -15
- package/dist/http.js +125 -138
- package/dist/http.js.map +1 -1
- package/dist/identity-dialog.js +4 -30
- package/dist/identity-dialog.js.map +1 -1
- package/dist/identity-input.d.ts +39 -0
- package/dist/identity-input.js +59 -0
- package/dist/identity-input.js.map +1 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/ingots.d.ts +51 -18
- package/dist/ingots.js +132 -122
- package/dist/ingots.js.map +1 -1
- package/dist/mutex.d.ts +1 -2
- package/dist/mutex.js +0 -6
- package/dist/mutex.js.map +1 -1
- package/dist/notify.d.ts +7 -2
- package/dist/notify.js +12 -15
- package/dist/notify.js.map +1 -1
- package/dist/notify.test-d.d.ts +3 -2
- package/dist/notify.test-d.js +1 -1
- package/dist/products/identity.d.ts +5 -0
- package/dist/products/identity.js +40 -35
- package/dist/products/identity.js.map +1 -1
- package/dist/request-path.d.ts +32 -0
- package/dist/request-path.js +35 -0
- package/dist/request-path.js.map +1 -0
- package/dist/sparks.js +16 -15
- package/dist/sparks.js.map +1 -1
- package/dist/tus.d.ts +19 -2
- package/dist/tus.js +86 -35
- package/dist/tus.js.map +1 -1
- package/dist/types.d.ts +167 -15
- package/dist/users.d.ts +12 -5
- package/dist/users.js +27 -19
- package/dist/users.js.map +1 -1
- package/dist/validation.d.ts +20 -5
- package/dist/validation.js +29 -27
- package/dist/validation.js.map +1 -1
- package/dist/vaults.d.ts +34 -83
- package/dist/vaults.js +64 -44
- package/dist/vaults.js.map +1 -1
- package/dist/vaults.test-d.d.ts +22 -0
- package/dist/vaults.test-d.js +14 -0
- package/dist/vaults.test-d.js.map +1 -0
- package/package.json +4 -2
- package/src/account.ts +16 -11
- package/src/app-sdk/email-address.js +94 -0
- package/src/app-sdk/encoding.js +250 -0
- package/src/app-sdk/entropy-contract.js +56 -0
- package/src/app-sdk/filename.js +174 -0
- package/src/app-sdk/forge-url.js +224 -0
- package/src/app-sdk/ids.js +71 -0
- package/src/app-sdk/ingot-access-log.js +51 -0
- package/src/app-sdk/phone.js +139 -0
- package/src/app-sdk/platform-domains.js +99 -0
- package/src/app-sdk/request-path.js +81 -0
- package/src/app-sdk/transient.js +30 -0
- package/src/app-sdk/vat-refusal.js +74 -0
- package/src/billing.ts +16 -25
- package/src/config.ts +16 -23
- package/src/encoding.ts +91 -103
- package/src/entropy.test-d.ts +47 -0
- package/src/entropy.ts +86 -20
- package/src/errors.ts +93 -33
- package/src/folders.ts +8 -7
- package/src/http.ts +145 -150
- package/src/identity-dialog.tsx +4 -37
- package/src/identity-input.ts +70 -0
- package/src/index.ts +11 -3
- package/src/ingots.ts +173 -159
- package/src/mutex.ts +1 -8
- package/src/notify.test-d.ts +3 -1
- package/src/notify.ts +19 -17
- package/src/products/identity.ts +45 -39
- package/src/request-path.ts +45 -0
- package/src/sparks.ts +16 -13
- package/src/tus.ts +90 -37
- package/src/types.ts +165 -15
- package/src/users.ts +27 -17
- package/src/validation.ts +30 -24
- package/src/vaults.test-d.ts +29 -0
- package/src/vaults.ts +87 -153
- package/dist/platform-domains.generated.d.ts +0 -2
- package/dist/platform-domains.generated.js +0 -16
- package/dist/platform-domains.generated.js.map +0 -1
- package/src/platform-domains.generated.ts +0 -17
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a value is an id of the given kind.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} kind - A key of RESOURCE_ID_PREFIXES
|
|
5
|
+
* @param {unknown} value
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
* @throws {TypeError} for a kind the grammar does not name: a misspelled kind
|
|
8
|
+
* would otherwise refuse every id without saying why
|
|
9
|
+
*/
|
|
10
|
+
export function isResourceIdOf(kind: string, value: unknown): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Whether a value is an id of any kind.
|
|
13
|
+
*
|
|
14
|
+
* @param {unknown} value
|
|
15
|
+
* @returns {boolean}
|
|
16
|
+
*/
|
|
17
|
+
export function isResourceId(value: unknown): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* SparkVault resource ids: the one grammar every surface reads an id by before
|
|
20
|
+
* the id names a request path or a stored file.
|
|
21
|
+
*
|
|
22
|
+
* Core mints an id as its kind's prefix, an underscore and a body: the hex of a
|
|
23
|
+
* UUIDv7 (apps/api lib/utils.js buildPrefixedIdFromBytes), or a hex digest for
|
|
24
|
+
* an invitation and an inbox notification. The grammar admits the kind's
|
|
25
|
+
* prefix, '_' and a body of the path-safe alphabet [A-Za-z0-9_-], 128
|
|
26
|
+
* characters in all, so an id that passes is exactly one request-path segment
|
|
27
|
+
* and one file-name component: it can never name a parent path, carry a
|
|
28
|
+
* separator or a dot-segment, or read as an id of another kind.
|
|
29
|
+
*
|
|
30
|
+
* - `isResourceIdOf(kind, value)`: an id of that kind.
|
|
31
|
+
* - `isResourceId(value)`: an id of any kind, for a check that takes several.
|
|
32
|
+
*
|
|
33
|
+
* Browser-safe and import-free: sdk-js bundles it, sdk-mobile mirrors it, and
|
|
34
|
+
* the apps, the console and the mobile app import it.
|
|
35
|
+
*/
|
|
36
|
+
/** The prefix Core mints each resource kind's id with. */
|
|
37
|
+
export const RESOURCE_ID_PREFIXES: Readonly<{
|
|
38
|
+
account: "acc";
|
|
39
|
+
folder: "fld";
|
|
40
|
+
ingot: "ing";
|
|
41
|
+
invite: "inv";
|
|
42
|
+
notification: "ntf";
|
|
43
|
+
spark: "spk";
|
|
44
|
+
user: "usr";
|
|
45
|
+
vault: "vlt";
|
|
46
|
+
}>;
|
|
47
|
+
/** The longest id, prefix included. */
|
|
48
|
+
export const RESOURCE_ID_MAX_LENGTH: 128;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// GENERATED FILE — do not edit by hand.
|
|
2
|
+
// Source of truth: packages/app-sdk/src/ids.js
|
|
3
|
+
// Regenerate with: pnpm --filter @sparkvault/sdk-mobile build
|
|
4
|
+
/**
|
|
5
|
+
* SparkVault resource ids: the one grammar every surface reads an id by before
|
|
6
|
+
* the id names a request path or a stored file.
|
|
7
|
+
*
|
|
8
|
+
* Core mints an id as its kind's prefix, an underscore and a body: the hex of a
|
|
9
|
+
* UUIDv7 (apps/api lib/utils.js buildPrefixedIdFromBytes), or a hex digest for
|
|
10
|
+
* an invitation and an inbox notification. The grammar admits the kind's
|
|
11
|
+
* prefix, '_' and a body of the path-safe alphabet [A-Za-z0-9_-], 128
|
|
12
|
+
* characters in all, so an id that passes is exactly one request-path segment
|
|
13
|
+
* and one file-name component: it can never name a parent path, carry a
|
|
14
|
+
* separator or a dot-segment, or read as an id of another kind.
|
|
15
|
+
*
|
|
16
|
+
* - `isResourceIdOf(kind, value)`: an id of that kind.
|
|
17
|
+
* - `isResourceId(value)`: an id of any kind, for a check that takes several.
|
|
18
|
+
*
|
|
19
|
+
* Browser-safe and import-free: sdk-js bundles it, sdk-mobile mirrors it, and
|
|
20
|
+
* the apps, the console and the mobile app import it.
|
|
21
|
+
*/
|
|
22
|
+
/** The prefix Core mints each resource kind's id with. */
|
|
23
|
+
export const RESOURCE_ID_PREFIXES = Object.freeze({
|
|
24
|
+
account: 'acc',
|
|
25
|
+
folder: 'fld',
|
|
26
|
+
ingot: 'ing',
|
|
27
|
+
invite: 'inv',
|
|
28
|
+
notification: 'ntf',
|
|
29
|
+
spark: 'spk',
|
|
30
|
+
user: 'usr',
|
|
31
|
+
vault: 'vlt'
|
|
32
|
+
});
|
|
33
|
+
/** The longest id, prefix included. */
|
|
34
|
+
export const RESOURCE_ID_MAX_LENGTH = 128;
|
|
35
|
+
const ID_BODY = /^[A-Za-z0-9_-]+$/;
|
|
36
|
+
/**
|
|
37
|
+
* Whether a value is an id of the given kind.
|
|
38
|
+
*
|
|
39
|
+
* @param {string} kind - A key of RESOURCE_ID_PREFIXES
|
|
40
|
+
* @param {unknown} value
|
|
41
|
+
* @returns {boolean}
|
|
42
|
+
* @throws {TypeError} for a kind the grammar does not name: a misspelled kind
|
|
43
|
+
* would otherwise refuse every id without saying why
|
|
44
|
+
*/
|
|
45
|
+
export function isResourceIdOf(kind, value) {
|
|
46
|
+
if (!Object.hasOwn(RESOURCE_ID_PREFIXES, kind)) {
|
|
47
|
+
throw new TypeError(`No resource kind '${kind}'`);
|
|
48
|
+
}
|
|
49
|
+
const prefix = `${RESOURCE_ID_PREFIXES[kind]}_`;
|
|
50
|
+
return typeof value === 'string'
|
|
51
|
+
&& value.length <= RESOURCE_ID_MAX_LENGTH
|
|
52
|
+
&& value.startsWith(prefix)
|
|
53
|
+
&& ID_BODY.test(value.slice(prefix.length));
|
|
54
|
+
}
|
|
55
|
+
const KINDS = Object.freeze(Object.keys(RESOURCE_ID_PREFIXES));
|
|
56
|
+
/**
|
|
57
|
+
* Whether a value is an id of any kind.
|
|
58
|
+
*
|
|
59
|
+
* @param {unknown} value
|
|
60
|
+
* @returns {boolean}
|
|
61
|
+
*/
|
|
62
|
+
export function isResourceId(value) {
|
|
63
|
+
return KINDS.some((kind) => isResourceIdOf(kind, value));
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/app-sdk/ids.js"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,+CAA+C;AAC/C,8DAA8D;AAE9D;;;;;;;;;;;;;;;;;GAiBG;AAEH,0DAA0D;AAC1D,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;IAChD,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,KAAK;IACb,YAAY,EAAE,KAAK;IACnB,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,KAAK;IACX,KAAK,EAAE,KAAK;CACb,CAAC,CAAC;AAEH,uCAAuC;AACvC,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,MAAM,OAAO,GAAG,kBAAkB,CAAC;AAEnC;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,IAAI,EAAE,KAAK;IACxC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,SAAS,CAAC,qBAAqB,IAAI,GAAG,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC;IAChD,OAAO,OAAO,KAAK,KAAK,QAAQ;WAC3B,KAAK,CAAC,MAAM,IAAI,sBAAsB;WACtC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;WACxB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAK;IAChC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One audit entry as an access. The actor reads as the server resolved it (a
|
|
3
|
+
* member's email, an API key's name), else as the identity a SparkLink visitor
|
|
4
|
+
* gave (kept in the entry's metadata), else as the raw actor id.
|
|
5
|
+
*
|
|
6
|
+
* @param {{ timestamp: number, event_type: string, actor_id?: string | null, actor_display?: string,
|
|
7
|
+
* ip_address?: string | null, user_agent?: string | null, metadata?: { identity?: string | null } | null }} entry
|
|
8
|
+
* @returns {{ timestamp: number, action: 'download', identity: string, ip_address: string,
|
|
9
|
+
* user_agent: string } | null} null for an event that is not an access
|
|
10
|
+
*/
|
|
11
|
+
export function readIngotAccess(entry: {
|
|
12
|
+
timestamp: number;
|
|
13
|
+
event_type: string;
|
|
14
|
+
actor_id?: string | null;
|
|
15
|
+
actor_display?: string;
|
|
16
|
+
ip_address?: string | null;
|
|
17
|
+
user_agent?: string | null;
|
|
18
|
+
metadata?: {
|
|
19
|
+
identity?: string | null;
|
|
20
|
+
} | null;
|
|
21
|
+
}): {
|
|
22
|
+
timestamp: number;
|
|
23
|
+
action: "download";
|
|
24
|
+
identity: string;
|
|
25
|
+
ip_address: string;
|
|
26
|
+
user_agent: string;
|
|
27
|
+
} | null;
|
|
28
|
+
/** The event types an access-log request asks the server for. */
|
|
29
|
+
export const INGOT_ACCESS_EVENT_TYPES: readonly string[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// GENERATED FILE — do not edit by hand.
|
|
2
|
+
// Source of truth: packages/app-sdk/src/ingot-access-log.js
|
|
3
|
+
// Regenerate with: pnpm --filter @sparkvault/sdk-mobile build
|
|
4
|
+
/**
|
|
5
|
+
* Ingot access logs: which of an ingot's audit events are accesses, and how one
|
|
6
|
+
* audit entry reads as an access. Both SDKs read
|
|
7
|
+
* GET /v1/vaults/{vault_id}/ingots/{ingot_id}/audit-logs through it: sdk-js
|
|
8
|
+
* bundles this module, and sdk-mobile (which publishes standalone) carries a
|
|
9
|
+
* build-time copy pinned byte-for-byte by its drift test.
|
|
10
|
+
*
|
|
11
|
+
* An entry arrives in the server's public audit shape (AuditLogRepository
|
|
12
|
+
* toPublicFormat, annotated by the audit-log controller's actor resolution):
|
|
13
|
+
* `timestamp`, `event_type`, `actor_id`, `actor_type`, `actor_display`,
|
|
14
|
+
* `ip_address`, `user_agent`, `metadata` (null while encrypted), `encrypted`,
|
|
15
|
+
* `vault_id` and `ingot_id`.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* The ingot audit events that are accesses, and what each one is: Core records
|
|
19
|
+
* an access to a file as the download that delivered it, a SparkLink open of
|
|
20
|
+
* the file included.
|
|
21
|
+
*/
|
|
22
|
+
const ACCESS_ACTIONS = new Map([
|
|
23
|
+
['ingot_downloaded', 'download'],
|
|
24
|
+
]);
|
|
25
|
+
/** The event types an access-log request asks the server for. */
|
|
26
|
+
export const INGOT_ACCESS_EVENT_TYPES = Object.freeze([...ACCESS_ACTIONS.keys()]);
|
|
27
|
+
/**
|
|
28
|
+
* One audit entry as an access. The actor reads as the server resolved it (a
|
|
29
|
+
* member's email, an API key's name), else as the identity a SparkLink visitor
|
|
30
|
+
* gave (kept in the entry's metadata), else as the raw actor id.
|
|
31
|
+
*
|
|
32
|
+
* @param {{ timestamp: number, event_type: string, actor_id?: string | null, actor_display?: string,
|
|
33
|
+
* ip_address?: string | null, user_agent?: string | null, metadata?: { identity?: string | null } | null }} entry
|
|
34
|
+
* @returns {{ timestamp: number, action: 'download', identity: string, ip_address: string,
|
|
35
|
+
* user_agent: string } | null} null for an event that is not an access
|
|
36
|
+
*/
|
|
37
|
+
export function readIngotAccess(entry) {
|
|
38
|
+
const action = ACCESS_ACTIONS.get(entry.event_type);
|
|
39
|
+
if (action === undefined)
|
|
40
|
+
return null;
|
|
41
|
+
return {
|
|
42
|
+
timestamp: entry.timestamp,
|
|
43
|
+
action,
|
|
44
|
+
identity: entry.actor_display || entry.metadata?.identity || entry.actor_id || 'Unknown',
|
|
45
|
+
ip_address: entry.ip_address ?? '',
|
|
46
|
+
user_agent: entry.user_agent ?? '',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=ingot-access-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingot-access-log.js","sourceRoot":"","sources":["../../src/app-sdk/ingot-access-log.js"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,4DAA4D;AAC5D,8DAA8D;AAE9D;;;;;;;;;;;;GAYG;AAEH;;;;GAIG;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,CAAC,kBAAkB,EAAE,UAAU,CAAC;CACjC,CAAC,CAAC;AAEH,iEAAiE;AACjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AAElF;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,KAAK;IACnC,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACpD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACtC,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM;QACN,QAAQ,EAAE,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,QAAQ,EAAE,QAAQ,IAAI,KAAK,CAAC,QAAQ,IAAI,SAAS;QACxF,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,EAAE;QAClC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,EAAE;KACnC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a typed phone number as E.164.
|
|
3
|
+
*
|
|
4
|
+
* @param {unknown} raw
|
|
5
|
+
* @returns {string|null} E.164 with its leading '+', or null when the input
|
|
6
|
+
* names no dialable number
|
|
7
|
+
*/
|
|
8
|
+
export function parsePhone(raw: unknown): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Whether a value is already a canonical E.164 phone number — exactly the
|
|
11
|
+
* values parsePhone returns unchanged.
|
|
12
|
+
*
|
|
13
|
+
* @param {unknown} value
|
|
14
|
+
* @returns {boolean}
|
|
15
|
+
*/
|
|
16
|
+
export function isE164Phone(value: unknown): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whether an identifier typed where either is accepted is an email address or
|
|
19
|
+
* a phone number.
|
|
20
|
+
*
|
|
21
|
+
* @param {unknown} value
|
|
22
|
+
* @returns {'email' | 'phone'}
|
|
23
|
+
*/
|
|
24
|
+
export function inferIdentityType(value: unknown): "email" | "phone";
|
|
25
|
+
/**
|
|
26
|
+
* A phone number as a phone field shows it while it is typed: a NANP number as
|
|
27
|
+
* (XXX) XXX-XXXX; a declared country code, or a digit string that is not a NANP
|
|
28
|
+
* number, keeps every digit as given, so formatting never turns one destination
|
|
29
|
+
* into another. Text holding anything but phone characters (a letter, a
|
|
30
|
+
* dial-control character, a digit of another script) is left as typed, so it
|
|
31
|
+
* reaches parsePhone and is refused there instead of being dropped from the
|
|
32
|
+
* field.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} value
|
|
35
|
+
* @returns {string}
|
|
36
|
+
*/
|
|
37
|
+
export function formatPhoneDisplay(value: string): string;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// GENERATED FILE — do not edit by hand.
|
|
2
|
+
// Source of truth: packages/app-sdk/src/phone.js
|
|
3
|
+
// Regenerate with: pnpm --filter @sparkvault/sdk-mobile build
|
|
4
|
+
/**
|
|
5
|
+
* Phone numbers a person types: how one reads as E.164, and whether a typed
|
|
6
|
+
* identifier is a phone number at all. Pure, with no imports, so a browser or
|
|
7
|
+
* an SDK bundle can carry it: Core reads and checks every phone it is given
|
|
8
|
+
* with it, the console imports it, sdk-js bundles it, and sdk-mobile carries a
|
|
9
|
+
* build-time copy pinned byte-for-byte by its drift test.
|
|
10
|
+
*
|
|
11
|
+
* A '+' ahead of the digits DECLARES the country code, so every digit is kept
|
|
12
|
+
* exactly as given: ten digits after a '+' are a foreign number (+47 Norway,
|
|
13
|
+
* +45 Denmark, +65 Singapore, +354 Iceland …), and reading them as a NANP number
|
|
14
|
+
* would hand an OTP or a bearer link to whoever holds the matching North
|
|
15
|
+
* American line. Only input WITHOUT a '+' may take the NANP shorthand: exactly
|
|
16
|
+
* ten digits, or eleven starting with the '1'. Any other bare digit string
|
|
17
|
+
* declares no country and is refused rather than guessed.
|
|
18
|
+
*
|
|
19
|
+
* A typed number holds ASCII digits, at most one '+' ahead of all of them, and
|
|
20
|
+
* the separators people type: whitespace, parentheses, dots and dashes of any
|
|
21
|
+
* script, and the invisible formatting marks a contacts app wraps a number in.
|
|
22
|
+
* The separators and marks are dropped. Anything else is refused, never
|
|
23
|
+
* dropped: stripping it would fold part of the text into the number and deliver
|
|
24
|
+
* to someone else's line — a letter or a dial-control character (',' and ';'
|
|
25
|
+
* pause, '#' and '*' are keypad tones) carries an extension ("x2", ",89"), a
|
|
26
|
+
* digit of another script ('٧', '7') is a digit the ASCII read would silently
|
|
27
|
+
* lose, and a '+' after a digit declares nothing.
|
|
28
|
+
*
|
|
29
|
+
* An identifier typed where an email address or a phone number is accepted is
|
|
30
|
+
* a phone number only when it holds phone characters only, led by a digit, '+'
|
|
31
|
+
* or '(': an email whose local part starts with a digit ("2024user@gmail.com",
|
|
32
|
+
* "12345678@qq.com") stays an email.
|
|
33
|
+
*/
|
|
34
|
+
/** A '+' before any digit: the caller declared the country code. */
|
|
35
|
+
const DECLARED_COUNTRY_CODE = /^\D*\+/;
|
|
36
|
+
/** E.164 digits once a country code is declared: 8–15, never a leading 0. */
|
|
37
|
+
const E164_DIGITS = /^[1-9]\d{7,14}$/;
|
|
38
|
+
/** A canonical E.164 value. */
|
|
39
|
+
const E164 = /^\+[1-9]\d{7,14}$/;
|
|
40
|
+
/** Invisible formatting marks (bidi embeddings, zero-width characters), in any number. */
|
|
41
|
+
const FORMAT_MARKS = /\p{Cf}/gu;
|
|
42
|
+
/**
|
|
43
|
+
* Typed phone text once its formatting marks are dropped: ASCII digits and
|
|
44
|
+
* separators, with at most one '+', ahead of every digit.
|
|
45
|
+
*/
|
|
46
|
+
const PHONE_TEXT = /^[\s().\p{Pd}]*\+?[\d\s().\p{Pd}]*$/u;
|
|
47
|
+
/** How phone text starts where an identifier may be either: a digit, '+' or '('. */
|
|
48
|
+
const PHONE_LEAD = /^[+(\d]/;
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} value
|
|
51
|
+
* @returns {string} The value without its formatting marks
|
|
52
|
+
*/
|
|
53
|
+
function withoutFormatMarks(value) {
|
|
54
|
+
return value.replace(FORMAT_MARKS, '');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Read a typed phone number as E.164.
|
|
58
|
+
*
|
|
59
|
+
* @param {unknown} raw
|
|
60
|
+
* @returns {string|null} E.164 with its leading '+', or null when the input
|
|
61
|
+
* names no dialable number
|
|
62
|
+
*/
|
|
63
|
+
export function parsePhone(raw) {
|
|
64
|
+
if (typeof raw !== 'string')
|
|
65
|
+
return null;
|
|
66
|
+
const text = withoutFormatMarks(raw);
|
|
67
|
+
if (!PHONE_TEXT.test(text))
|
|
68
|
+
return null;
|
|
69
|
+
const digits = text.replace(/\D/g, '');
|
|
70
|
+
if (DECLARED_COUNTRY_CODE.test(text)) {
|
|
71
|
+
return E164_DIGITS.test(digits) ? `+${digits}` : null;
|
|
72
|
+
}
|
|
73
|
+
if (digits.length === 10)
|
|
74
|
+
return `+1${digits}`;
|
|
75
|
+
if (digits.length === 11 && digits.startsWith('1'))
|
|
76
|
+
return `+${digits}`;
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Whether a value is already a canonical E.164 phone number — exactly the
|
|
81
|
+
* values parsePhone returns unchanged.
|
|
82
|
+
*
|
|
83
|
+
* @param {unknown} value
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
export function isE164Phone(value) {
|
|
87
|
+
return typeof value === 'string' && E164.test(value);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Whether an identifier typed where either is accepted is an email address or
|
|
91
|
+
* a phone number.
|
|
92
|
+
*
|
|
93
|
+
* @param {unknown} value
|
|
94
|
+
* @returns {'email' | 'phone'}
|
|
95
|
+
*/
|
|
96
|
+
export function inferIdentityType(value) {
|
|
97
|
+
if (typeof value !== 'string')
|
|
98
|
+
return 'email';
|
|
99
|
+
const text = withoutFormatMarks(value).trim();
|
|
100
|
+
return PHONE_LEAD.test(text) && PHONE_TEXT.test(text) ? 'phone' : 'email';
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A phone number as a phone field shows it while it is typed: a NANP number as
|
|
104
|
+
* (XXX) XXX-XXXX; a declared country code, or a digit string that is not a NANP
|
|
105
|
+
* number, keeps every digit as given, so formatting never turns one destination
|
|
106
|
+
* into another. Text holding anything but phone characters (a letter, a
|
|
107
|
+
* dial-control character, a digit of another script) is left as typed, so it
|
|
108
|
+
* reaches parsePhone and is refused there instead of being dropped from the
|
|
109
|
+
* field.
|
|
110
|
+
*
|
|
111
|
+
* @param {string} value
|
|
112
|
+
* @returns {string}
|
|
113
|
+
*/
|
|
114
|
+
export function formatPhoneDisplay(value) {
|
|
115
|
+
const text = withoutFormatMarks(value);
|
|
116
|
+
if (!PHONE_TEXT.test(text))
|
|
117
|
+
return value;
|
|
118
|
+
const digits = text.replace(/\D/g, '');
|
|
119
|
+
if (DECLARED_COUNTRY_CODE.test(text) && !(digits.startsWith('1') && digits.length === 11)) {
|
|
120
|
+
return `+${digits}`;
|
|
121
|
+
}
|
|
122
|
+
if (digits.length > 11 || (digits.length === 11 && !digits.startsWith('1'))) {
|
|
123
|
+
return digits;
|
|
124
|
+
}
|
|
125
|
+
const national = digits.length === 11 ? digits.slice(1) : digits;
|
|
126
|
+
if (national.length === 0)
|
|
127
|
+
return '';
|
|
128
|
+
if (national.length <= 3)
|
|
129
|
+
return `(${national}`;
|
|
130
|
+
if (national.length <= 6)
|
|
131
|
+
return `(${national.slice(0, 3)}) ${national.slice(3)}`;
|
|
132
|
+
return `(${national.slice(0, 3)}) ${national.slice(3, 6)}-${national.slice(6, 10)}`;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=phone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phone.js","sourceRoot":"","sources":["../../src/app-sdk/phone.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export function isSparkVaultRootOrSubdomain(hostname: any): boolean;
|
|
2
|
+
export function isSparkVaultPlatformSvHost(hostname: any): boolean;
|
|
3
|
+
export function isSparkVaultOwnedHostname(hostname: any): boolean;
|
|
4
|
+
export function isSparkVaultReservedDomain(hostname: any): boolean;
|
|
5
|
+
export function sparkVaultPlatformSvOrigins(): string[];
|
|
6
|
+
export function sparkVaultWebSocketOrigins(): string[];
|
|
7
|
+
/**
|
|
8
|
+
* SparkVault-owned domain registry.
|
|
9
|
+
*
|
|
10
|
+
* Keep platform domain decisions centralized: CSP, redirect safety, custom
|
|
11
|
+
* domain reservation, and Identity postMessage trust all depend on the same
|
|
12
|
+
* ownership boundary.
|
|
13
|
+
*/
|
|
14
|
+
export const SPARKVAULT_ROOT_DOMAIN: "sparkvault.com";
|
|
15
|
+
/** The person-facing Identity portal host (auth.sv shell + hosted login). */
|
|
16
|
+
export const SPARKVAULT_AUTH_HOST: "auth.sv";
|
|
17
|
+
/**
|
|
18
|
+
* The Identity IdP origin's host: it serves the OIDC ceremonies (/authorize,
|
|
19
|
+
* /token), the SDK sign-in page and the Identity API, issues every Identity
|
|
20
|
+
* token (`iss` is https://{host}/{account_id}), and holds the hub session
|
|
21
|
+
* cookie. Core verifies the tokens it issues and the Identity product mints
|
|
22
|
+
* them, so both name it from here. Never the auth.sv portal host.
|
|
23
|
+
*/
|
|
24
|
+
export const SPARKVAULT_IDENTITY_HOST: "auth.sparkvault.com";
|
|
25
|
+
/** The SparkLinks host: shared Sparks, single-use links and the Messaging recipient pages. */
|
|
26
|
+
export const SPARKVAULT_LINKS_HOST: "x.sv";
|
|
27
|
+
/** The durable file-share and Secure Upload Portal host. */
|
|
28
|
+
export const SPARKVAULT_FILES_HOST: "files.sv";
|
|
29
|
+
export const SPARKVAULT_PLATFORM_SV_HOSTS: readonly string[];
|
|
30
|
+
/** The SparkVault console. */
|
|
31
|
+
export const SPARKVAULT_APP_HOST: "app.sparkvault.com";
|
|
32
|
+
/** Forge, the streaming encrypt/decrypt service every ingot transfer goes through. */
|
|
33
|
+
export const SPARKVAULT_FORGE_HOST: "forge.sparkvault.com";
|
|
34
|
+
/**
|
|
35
|
+
* The platform's own hosts as patterns over a URL's hostname: the root domain
|
|
36
|
+
* and its subdomains, and each .sv host exactly (isSparkVaultOwnedHostname).
|
|
37
|
+
* Both SDKs trust a backend-issued transfer URL on these hosts by default;
|
|
38
|
+
* their `allowedDownloadHostPatterns` option replaces the list for another
|
|
39
|
+
* deployment.
|
|
40
|
+
*/
|
|
41
|
+
export const SPARKVAULT_OWNED_HOST_PATTERNS: readonly RegExp[];
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// GENERATED FILE — do not edit by hand.
|
|
2
|
+
// Source of truth: packages/app-sdk/src/platform-domains.js
|
|
3
|
+
// Regenerate with: pnpm --filter @sparkvault/sdk-mobile build
|
|
4
|
+
/**
|
|
5
|
+
* SparkVault-owned domain registry.
|
|
6
|
+
*
|
|
7
|
+
* Keep platform domain decisions centralized: CSP, redirect safety, custom
|
|
8
|
+
* domain reservation, and Identity postMessage trust all depend on the same
|
|
9
|
+
* ownership boundary.
|
|
10
|
+
*/
|
|
11
|
+
export const SPARKVAULT_ROOT_DOMAIN = 'sparkvault.com';
|
|
12
|
+
/** The person-facing Identity portal host (auth.sv shell + hosted login). */
|
|
13
|
+
export const SPARKVAULT_AUTH_HOST = 'auth.sv';
|
|
14
|
+
/**
|
|
15
|
+
* The Identity IdP origin's host: it serves the OIDC ceremonies (/authorize,
|
|
16
|
+
* /token), the SDK sign-in page and the Identity API, issues every Identity
|
|
17
|
+
* token (`iss` is https://{host}/{account_id}), and holds the hub session
|
|
18
|
+
* cookie. Core verifies the tokens it issues and the Identity product mints
|
|
19
|
+
* them, so both name it from here. Never the auth.sv portal host.
|
|
20
|
+
*/
|
|
21
|
+
export const SPARKVAULT_IDENTITY_HOST = 'auth.sparkvault.com';
|
|
22
|
+
/** The SparkLinks host: shared Sparks, single-use links and the Messaging recipient pages. */
|
|
23
|
+
export const SPARKVAULT_LINKS_HOST = 'x.sv';
|
|
24
|
+
/** The durable file-share and Secure Upload Portal host. */
|
|
25
|
+
export const SPARKVAULT_FILES_HOST = 'files.sv';
|
|
26
|
+
export const SPARKVAULT_PLATFORM_SV_HOSTS = Object.freeze([
|
|
27
|
+
SPARKVAULT_AUTH_HOST,
|
|
28
|
+
SPARKVAULT_LINKS_HOST,
|
|
29
|
+
SPARKVAULT_FILES_HOST,
|
|
30
|
+
'file.sv',
|
|
31
|
+
'send.sv',
|
|
32
|
+
'spark.sv',
|
|
33
|
+
'by.sv',
|
|
34
|
+
'at.sv',
|
|
35
|
+
'db.sv'
|
|
36
|
+
]);
|
|
37
|
+
/** The SparkVault console. */
|
|
38
|
+
export const SPARKVAULT_APP_HOST = 'app.sparkvault.com';
|
|
39
|
+
/** Forge, the streaming encrypt/decrypt service every ingot transfer goes through. */
|
|
40
|
+
export const SPARKVAULT_FORGE_HOST = 'forge.sparkvault.com';
|
|
41
|
+
const SPARKVAULT_WEBSOCKET_HOSTS = Object.freeze([
|
|
42
|
+
'ws.sparkvault.com'
|
|
43
|
+
]);
|
|
44
|
+
function escapeRegExp(value) {
|
|
45
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The platform's own hosts as patterns over a URL's hostname: the root domain
|
|
49
|
+
* and its subdomains, and each .sv host exactly (isSparkVaultOwnedHostname).
|
|
50
|
+
* Both SDKs trust a backend-issued transfer URL on these hosts by default;
|
|
51
|
+
* their `allowedDownloadHostPatterns` option replaces the list for another
|
|
52
|
+
* deployment.
|
|
53
|
+
*/
|
|
54
|
+
export const SPARKVAULT_OWNED_HOST_PATTERNS = Object.freeze([
|
|
55
|
+
new RegExp(`(^|\\.)${escapeRegExp(SPARKVAULT_ROOT_DOMAIN)}$`, 'i'),
|
|
56
|
+
new RegExp(`^(${SPARKVAULT_PLATFORM_SV_HOSTS.map(escapeRegExp).join('|')})$`, 'i')
|
|
57
|
+
]);
|
|
58
|
+
function normalizeHostname(hostname) {
|
|
59
|
+
if (typeof hostname !== 'string')
|
|
60
|
+
return '';
|
|
61
|
+
return hostname.trim().toLowerCase().replace(/\.$/, '');
|
|
62
|
+
}
|
|
63
|
+
export function isSparkVaultRootOrSubdomain(hostname) {
|
|
64
|
+
const normalized = normalizeHostname(hostname);
|
|
65
|
+
return normalized === SPARKVAULT_ROOT_DOMAIN || normalized.endsWith(`.${SPARKVAULT_ROOT_DOMAIN}`);
|
|
66
|
+
}
|
|
67
|
+
export function isSparkVaultPlatformSvHost(hostname) {
|
|
68
|
+
return SPARKVAULT_PLATFORM_SV_HOSTS.includes(normalizeHostname(hostname));
|
|
69
|
+
}
|
|
70
|
+
export function isSparkVaultOwnedHostname(hostname) {
|
|
71
|
+
return isSparkVaultRootOrSubdomain(hostname) || isSparkVaultPlatformSvHost(hostname);
|
|
72
|
+
}
|
|
73
|
+
export function isSparkVaultReservedDomain(hostname) {
|
|
74
|
+
return isSparkVaultOwnedHostname(hostname);
|
|
75
|
+
}
|
|
76
|
+
export function sparkVaultPlatformSvOrigins() {
|
|
77
|
+
return SPARKVAULT_PLATFORM_SV_HOSTS.map((host) => `https://${host}`);
|
|
78
|
+
}
|
|
79
|
+
export function sparkVaultWebSocketOrigins() {
|
|
80
|
+
return SPARKVAULT_WEBSOCKET_HOSTS.map((host) => `wss://${host}`);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=platform-domains.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-domains.js","sourceRoot":"","sources":["../../src/app-sdk/platform-domains.js"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,4DAA4D;AAC5D,8DAA8D;AAE9D;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,gBAAgB,CAAC;AAEvD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AAE9D,8FAA8F;AAC9F,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE5C,4DAA4D;AAC5D,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC;AAEhD,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC,MAAM,CAAC;IACxD,oBAAoB;IACpB,qBAAqB;IACrB,qBAAqB;IACrB,SAAS;IACT,SAAS;IACT,UAAU;IACV,OAAO;IACP,OAAO;IACP,OAAO;CACR,CAAC,CAAC;AAEH,8BAA8B;AAC9B,MAAM,CAAC,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AAExD,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAE5D,MAAM,0BAA0B,GAAG,MAAM,CAAC,MAAM,CAAC;IAC/C,mBAAmB;CACpB,CAAC,CAAC;AAEH,SAAS,YAAY,CAAC,KAAK;IACzB,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,MAAM,CAAC,MAAM,CAAC;IAC1D,IAAI,MAAM,CAAC,UAAU,YAAY,CAAC,sBAAsB,CAAC,GAAG,EAAE,GAAG,CAAC;IAClE,IAAI,MAAM,CAAC,KAAK,4BAA4B,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC;CACnF,CAAC,CAAC;AAEH,SAAS,iBAAiB,CAAC,QAAQ;IACjC,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAC5C,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,QAAQ;IAClD,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC/C,OAAO,UAAU,KAAK,sBAAsB,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,4BAA4B,CAAC,QAAQ,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAQ;IAChD,OAAO,2BAA2B,CAAC,QAAQ,CAAC,IAAI,0BAA0B,CAAC,QAAQ,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAQ;IACjD,OAAO,yBAAyB,CAAC,QAAQ,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,OAAO,4BAA4B,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO,0BAA0B,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request paths: the one rule every SDK applies before a caller-supplied value
|
|
3
|
+
* becomes part of a SparkVault request URL.
|
|
4
|
+
*
|
|
5
|
+
* A request carries the caller's credentials (a Bearer token, an API key, a
|
|
6
|
+
* Vault Access Token), so a value that smuggles '/' or a dot-segment into the
|
|
7
|
+
* path would re-target that credentialed request at another route. The rules:
|
|
8
|
+
*
|
|
9
|
+
* - `encodePathSegment`: every value interpolated into a path is encoded as
|
|
10
|
+
* exactly one segment. Percent-encoding keeps '/', '?' and '#' inside the
|
|
11
|
+
* segment, and the three values no encoding can keep one segment ('', '.'
|
|
12
|
+
* and '..', which URL resolution drops or collapses) are refused.
|
|
13
|
+
* - `buildRequestPath`: the template loop an SDK's tagged path builder runs,
|
|
14
|
+
* so every interpolated value passes `encodePathSegment` by construction.
|
|
15
|
+
* - `queryString`: the one query encoding, which leaves unset values out.
|
|
16
|
+
*
|
|
17
|
+
* A server-issued id is checked for its shape first, by the one resource-id
|
|
18
|
+
* grammar (ids.js).
|
|
19
|
+
*
|
|
20
|
+
* Browser-safe and dependency-free: sdk-js bundles it, and sdk-mobile (which
|
|
21
|
+
* publishes standalone) carries a build-time copy pinned byte-for-byte by its
|
|
22
|
+
* drift test. Each SDK wraps it in a typed front door that throws its own
|
|
23
|
+
* validation error.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Encode a value as exactly one request-path segment.
|
|
27
|
+
* @param {unknown} value
|
|
28
|
+
* @returns {string | null} the encoded segment, or null when the value cannot
|
|
29
|
+
* be one segment: not a string, empty, '.', '..', or not well-formed UTF-16
|
|
30
|
+
* (a lone surrogate has no percent-encoding).
|
|
31
|
+
*/
|
|
32
|
+
export function encodePathSegment(value: unknown): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Join a tagged template's literals with its values, each value encoded as
|
|
35
|
+
* exactly one path segment.
|
|
36
|
+
* @param {readonly string[]} literals
|
|
37
|
+
* @param {readonly unknown[]} values
|
|
38
|
+
* @returns {string | null} the path, or null when any value cannot be one
|
|
39
|
+
* segment (see `encodePathSegment`).
|
|
40
|
+
*/
|
|
41
|
+
export function buildRequestPath(literals: readonly string[], values: readonly unknown[]): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* Encode query parameters, leaving out every unset value (`undefined`, `null`
|
|
44
|
+
* or `''`). Other values are sent as their string form, so `0` and `false`
|
|
45
|
+
* are sent.
|
|
46
|
+
* @param {Readonly<Record<string, string | number | boolean | null | undefined>> | undefined} params
|
|
47
|
+
* @returns {string} `?a=1&b=2`, or '' when no value is set.
|
|
48
|
+
*/
|
|
49
|
+
export function queryString(params: Readonly<Record<string, string | number | boolean | null | undefined>> | undefined): string;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// GENERATED FILE — do not edit by hand.
|
|
2
|
+
// Source of truth: packages/app-sdk/src/request-path.js
|
|
3
|
+
// Regenerate with: pnpm --filter @sparkvault/sdk-mobile build
|
|
4
|
+
/**
|
|
5
|
+
* Request paths: the one rule every SDK applies before a caller-supplied value
|
|
6
|
+
* becomes part of a SparkVault request URL.
|
|
7
|
+
*
|
|
8
|
+
* A request carries the caller's credentials (a Bearer token, an API key, a
|
|
9
|
+
* Vault Access Token), so a value that smuggles '/' or a dot-segment into the
|
|
10
|
+
* path would re-target that credentialed request at another route. The rules:
|
|
11
|
+
*
|
|
12
|
+
* - `encodePathSegment`: every value interpolated into a path is encoded as
|
|
13
|
+
* exactly one segment. Percent-encoding keeps '/', '?' and '#' inside the
|
|
14
|
+
* segment, and the three values no encoding can keep one segment ('', '.'
|
|
15
|
+
* and '..', which URL resolution drops or collapses) are refused.
|
|
16
|
+
* - `buildRequestPath`: the template loop an SDK's tagged path builder runs,
|
|
17
|
+
* so every interpolated value passes `encodePathSegment` by construction.
|
|
18
|
+
* - `queryString`: the one query encoding, which leaves unset values out.
|
|
19
|
+
*
|
|
20
|
+
* A server-issued id is checked for its shape first, by the one resource-id
|
|
21
|
+
* grammar (ids.js).
|
|
22
|
+
*
|
|
23
|
+
* Browser-safe and dependency-free: sdk-js bundles it, and sdk-mobile (which
|
|
24
|
+
* publishes standalone) carries a build-time copy pinned byte-for-byte by its
|
|
25
|
+
* drift test. Each SDK wraps it in a typed front door that throws its own
|
|
26
|
+
* validation error.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Encode a value as exactly one request-path segment.
|
|
30
|
+
* @param {unknown} value
|
|
31
|
+
* @returns {string | null} the encoded segment, or null when the value cannot
|
|
32
|
+
* be one segment: not a string, empty, '.', '..', or not well-formed UTF-16
|
|
33
|
+
* (a lone surrogate has no percent-encoding).
|
|
34
|
+
*/
|
|
35
|
+
export function encodePathSegment(value) {
|
|
36
|
+
if (typeof value !== 'string' || value === '' || value === '.' || value === '..') {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
return encodeURIComponent(value);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Join a tagged template's literals with its values, each value encoded as
|
|
48
|
+
* exactly one path segment.
|
|
49
|
+
* @param {readonly string[]} literals
|
|
50
|
+
* @param {readonly unknown[]} values
|
|
51
|
+
* @returns {string | null} the path, or null when any value cannot be one
|
|
52
|
+
* segment (see `encodePathSegment`).
|
|
53
|
+
*/
|
|
54
|
+
export function buildRequestPath(literals, values) {
|
|
55
|
+
let path = literals[0];
|
|
56
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
57
|
+
const segment = encodePathSegment(values[index]);
|
|
58
|
+
if (segment === null)
|
|
59
|
+
return null;
|
|
60
|
+
path += segment + literals[index + 1];
|
|
61
|
+
}
|
|
62
|
+
return path;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Encode query parameters, leaving out every unset value (`undefined`, `null`
|
|
66
|
+
* or `''`). Other values are sent as their string form, so `0` and `false`
|
|
67
|
+
* are sent.
|
|
68
|
+
* @param {Readonly<Record<string, string | number | boolean | null | undefined>> | undefined} params
|
|
69
|
+
* @returns {string} `?a=1&b=2`, or '' when no value is set.
|
|
70
|
+
*/
|
|
71
|
+
export function queryString(params) {
|
|
72
|
+
const search = new URLSearchParams();
|
|
73
|
+
for (const [key, value] of Object.entries(params ?? {})) {
|
|
74
|
+
if (value === undefined || value === null || value === '')
|
|
75
|
+
continue;
|
|
76
|
+
search.append(key, String(value));
|
|
77
|
+
}
|
|
78
|
+
const query = search.toString();
|
|
79
|
+
return query ? `?${query}` : '';
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=request-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-path.js","sourceRoot":"","sources":["../../src/app-sdk/request-path.js"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,wDAAwD;AACxD,8DAA8D;AAE9D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAK;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACjF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAQ,EAAE,MAAM;IAC/C,IAAI,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACvB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACjD,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAClC,IAAI,IAAI,OAAO,GAAG,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAAM;IAChC,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;YAAE,SAAS;QACpE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAChC,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAClC,CAAC"}
|