Skip to content

Commit c510bd8

Browse files
chore: couple new methods
1 parent 5bb0b53 commit c510bd8

8 files changed

Lines changed: 316 additions & 21 deletions

File tree

README.md

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Shared TypeScript utilities for removing repeated code across Sovereignbase code
1212
- Runtimes: modern JavaScript runtimes; the repository includes runtime compatibility tests for Node, Bun, Deno, Cloudflare Workers, Edge Runtime, and browsers.
1313
- Module format: ESM and CommonJS.
1414
- Required globals / APIs: `structuredClone` is required for successful `safeStructuredClone()` results.
15+
- Browser capability checks: `browserHasSovereignbaseDependencies()` resolves to `false` outside secure browser contexts and when required browser APIs are missing.
1516
- TypeScript: bundled types.
1617

1718
## Goals
@@ -77,6 +78,8 @@ if (result[0]) {
7778
}
7879
```
7980

81+
Attempts a structured clone and returns a tuple instead of throwing on unsupported values.
82+
8083
### `getISO31661Alpha2CountryCodeSet()`
8184

8285
```ts
@@ -93,32 +96,45 @@ function epicFunction1(countryCode: ISO31661Alpha2) {
9396
}
9497
```
9598

96-
Attempts a structured clone and returns a tuple instead of throwing on unsupported values.
99+
Returns a fresh `Set` containing all supported ISO 3166-1 alpha-2 country codes.
100+
101+
### `browserHasSovereignbaseDependencies()`
102+
103+
```ts
104+
import { browserHasSovereignbaseDependencies } from '@sovereignbase/utils'
105+
106+
if (await browserHasSovereignbaseDependencies()) {
107+
console.log('browser runtime supports Sovereignbase dependencies')
108+
}
109+
```
110+
111+
Checks whether the current browser environment exposes the secure-context, storage, worker, notification, Web Crypto, and WebAuthn APIs required by Sovereignbase browser features.
97112

98113
## Tests
99114

100115
- Latest local `npm run test` run passed on Node `v22.14.0`.
101-
- Node unit suite: `5/5` passed.
116+
- Node unit suite: `9/9` passed.
102117
- Node integration suite: `2/2` passed.
103118
- Coverage: `100%` statements, branches, functions, and lines.
104-
- Runtime E2E: Node ESM `9/9` passed.
105-
- Runtime E2E: Node CJS `9/9` passed.
106-
- Runtime E2E: Bun ESM `9/9` passed.
107-
- Runtime E2E: Bun CJS `9/9` passed.
108-
- Runtime E2E: Deno ESM `9/9` passed.
109-
- Runtime E2E: Cloudflare Workers ESM `9/9` passed.
110-
- Runtime E2E: Edge Runtime ESM `9/9` passed.
119+
- Runtime E2E: Node ESM `11/11` passed.
120+
- Runtime E2E: Node CJS `11/11` passed.
121+
- Runtime E2E: Bun ESM `11/11` passed.
122+
- Runtime E2E: Bun CJS `11/11` passed.
123+
- Runtime E2E: Deno ESM `11/11` passed.
124+
- Runtime E2E: Cloudflare Workers ESM `11/11` passed.
125+
- Runtime E2E: Edge Runtime ESM `11/11` passed.
111126
- Browser E2E: `5/5` Playwright projects passed (`chromium`, `firefox`, `webkit`, `mobile-chrome`, `mobile-safari`).
112127

113128
## Benchmarks
114129

115130
- Latest local `npm run bench` run: Node `v22.14.0` on `win32 x64`.
116-
- `prototype(record)`: `8,060,210 ops/sec` (`248.1 ms`).
117-
- `prototype(url)`: `3,624,304 ops/sec` (`551.8 ms`).
118-
- `isUuidV7(valid)`: `3,575,658 ops/sec` (`279.7 ms`).
119-
- `isUuidV7(invalid)`: `4,184,715 ops/sec` (`239.0 ms`).
120-
- `safeStructuredClone(record)`: `110,503 ops/sec` (`2262.4 ms`).
121-
- `safeStructuredClone(function)`: `28,112 ops/sec` (`8893.1 ms`).
131+
- `prototype(record)`: `4,882,423 ops/sec` (`409.6 ms`).
132+
- `prototype(url)`: `2,626,656 ops/sec` (`761.4 ms`).
133+
- `isUuidV7(valid)`: `2,366,821 ops/sec` (`422.5 ms`).
134+
- `isUuidV7(invalid)`: `2,970,958 ops/sec` (`336.6 ms`).
135+
- `getISO31661Alpha2CountryCodeSet()`: `35,059 ops/sec` (`1426.2 ms`).
136+
- `safeStructuredClone(record)`: `57,335 ops/sec` (`4360.4 ms`).
137+
- `safeStructuredClone(function)`: `12,678 ops/sec` (`19718.8 ms`).
122138
- Results vary by machine.
123139

124140
## License

benchmark/bench.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { performance } from 'node:perf_hooks'
22

3-
import { isUuidV7, prototype, safeStructuredClone } from '../dist/index.js'
3+
import {
4+
getISO31661Alpha2CountryCodeSet,
5+
isUuidV7,
6+
prototype,
7+
safeStructuredClone,
8+
} from '../dist/index.js'
49

510
const validUuidV7 = '018f0d1e-6c82-7d4b-91c1-8a7b5e2f4a10'
611
const invalidUuid = '550e8400-e29b-41d4-a716-446655440000'
@@ -33,6 +38,9 @@ const results = [
3338
benchmark('prototype(url)', 2_000_000, () => prototype(urlValue)),
3439
benchmark('isUuidV7(valid)', 1_000_000, () => isUuidV7(validUuidV7)),
3540
benchmark('isUuidV7(invalid)', 1_000_000, () => isUuidV7(invalidUuid)),
41+
benchmark('getISO31661Alpha2CountryCodeSet()', 50_000, () =>
42+
getISO31661Alpha2CountryCodeSet()
43+
),
3644
benchmark('safeStructuredClone(record)', 250_000, () =>
3745
safeStructuredClone(cloneValue)
3846
),

src/ISO31661Alpha2/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/**
2+
* Represents an ISO 3166-1 alpha-2 country code.
3+
*/
14
export type ISO31661Alpha2 =
25
| "AF"
36
| "AX"
@@ -249,6 +252,11 @@ export type ISO31661Alpha2 =
249252
| "ZM"
250253
| "ZW";
251254

255+
/**
256+
* Returns a new set containing every supported ISO 3166-1 alpha-2 country code.
257+
*
258+
* @returns A fresh `Set` of uppercase two-character country codes.
259+
*/
252260
export function getISO31661Alpha2CountryCodeSet(): Set<ISO31661Alpha2> {
253261
return new Set([
254262
"AF",

src/browserHasSovereignbaseDepencies/index.ts renamed to src/browserHasSovereignbaseDependencies/index.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
export async function browserHasSovereignbaseDepencies(): Promise<boolean> {
1+
/**
2+
* Checks whether the current browser environment exposes the APIs required by
3+
* Sovereignbase browser features.
4+
*
5+
* The check requires a secure browser context plus storage, worker,
6+
* notifications, Web Crypto, and WebAuthn platform authenticator support. It
7+
* resolves to `false` in non-browser runtimes and unsupported browsers.
8+
*
9+
* @returns A promise that resolves to `true` when the required browser
10+
* dependencies are available; otherwise, `false`.
11+
*/
12+
export async function browserHasSovereignbaseDependencies(): Promise<boolean> {
213
return (
314
typeof window !== 'undefined' &&
415
window.isSecureContext &&

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ export {
55
type ISO31661Alpha2,
66
getISO31661Alpha2CountryCodeSet,
77
} from './ISO31661Alpha2/index.js'
8-
export { browserHasSovereignbaseDepencies } from './browserHasSovereignbaseDepencies/index.js'
8+
export { browserHasSovereignbaseDependencies } from './browserHasSovereignbaseDependencies/index.js'

test/e2e/shared/suite.mjs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@ export async function runUtilsSuite(api, options = {}) {
4242
const runtimeGlobals = options.runtimeGlobals ?? globalThis
4343
const results = { label, ok: true, errors: [], tests: [] }
4444

45-
const { prototype, isUuidV7, safeStructuredClone } = api
45+
const {
46+
browserHasSovereignbaseDependencies,
47+
getISO31661Alpha2CountryCodeSet,
48+
prototype,
49+
isUuidV7,
50+
safeStructuredClone,
51+
} = api
4652

4753
function assert(condition, message) {
4854
if (!condition) throw new Error(message || 'assertion failed')
@@ -90,6 +96,14 @@ export async function runUtilsSuite(api, options = {}) {
9096
}
9197

9298
await runTest('exports shape', () => {
99+
assert(
100+
typeof browserHasSovereignbaseDependencies === 'function',
101+
'browserHasSovereignbaseDependencies export missing'
102+
)
103+
assert(
104+
typeof getISO31661Alpha2CountryCodeSet === 'function',
105+
'getISO31661Alpha2CountryCodeSet export missing'
106+
)
93107
assert(typeof prototype === 'function', 'prototype export missing')
94108
assert(typeof isUuidV7 === 'function', 'isUuidV7 export missing')
95109
assert(
@@ -257,6 +271,35 @@ export async function runUtilsSuite(api, options = {}) {
257271
}
258272
)
259273

274+
await runTest(
275+
'getISO31661Alpha2CountryCodeSet returns a fresh set of country codes',
276+
() => {
277+
const first = getISO31661Alpha2CountryCodeSet()
278+
const second = getISO31661Alpha2CountryCodeSet()
279+
280+
assertEqual(Object.prototype.toString.call(first), '[object Set]')
281+
assertEqual(first.size, 249)
282+
assertEqual(first.has('FI'), true)
283+
assertEqual(first.has('US'), true)
284+
assertEqual(first.has('XX'), false)
285+
assert(first !== second, 'expected a fresh Set per call')
286+
assertEqual([...first].join(','), [...second].join(','))
287+
}
288+
)
289+
290+
await runTest(
291+
'browserHasSovereignbaseDependencies reports runtime support',
292+
async () => {
293+
const supported = await browserHasSovereignbaseDependencies()
294+
295+
assertEqual(typeof supported, 'boolean')
296+
297+
if (typeof runtimeGlobals.window === 'undefined') {
298+
assertEqual(supported, false)
299+
}
300+
}
301+
)
302+
260303
return results
261304
}
262305

test/integration/integration.test.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,22 @@ const cjsApi = require('../../dist/index.cjs')
99

1010
test('esm and cjs entrypoints expose the same runtime API', () => {
1111
assert.deepEqual(Object.keys(esmApi).sort(), [
12+
'browserHasSovereignbaseDependencies',
13+
'getISO31661Alpha2CountryCodeSet',
1214
'isUuidV7',
1315
'prototype',
1416
'safeStructuredClone',
1517
])
1618
assert.deepEqual(Object.keys(cjsApi).sort(), [
19+
'browserHasSovereignbaseDependencies',
20+
'getISO31661Alpha2CountryCodeSet',
1721
'isUuidV7',
1822
'prototype',
1923
'safeStructuredClone',
2024
])
2125
})
2226

23-
test('esm and cjs entrypoints behave the same', () => {
27+
test('esm and cjs entrypoints behave the same', async () => {
2428
const values = [
2529
null,
2630
{ ok: true },
@@ -60,4 +64,17 @@ test('esm and cjs entrypoints behave the same', () => {
6064
cjsApi.safeStructuredClone(() => {}),
6165
[false]
6266
)
67+
68+
const esmCountryCodes = esmApi.getISO31661Alpha2CountryCodeSet()
69+
const cjsCountryCodes = cjsApi.getISO31661Alpha2CountryCodeSet()
70+
71+
assert.equal(esmCountryCodes.size, cjsCountryCodes.size)
72+
assert.equal(esmCountryCodes.has('FI'), cjsCountryCodes.has('FI'))
73+
assert.equal(esmCountryCodes.has('US'), cjsCountryCodes.has('US'))
74+
assert.equal(esmCountryCodes.has('XX'), cjsCountryCodes.has('XX'))
75+
76+
assert.equal(
77+
await esmApi.browserHasSovereignbaseDependencies(),
78+
await cjsApi.browserHasSovereignbaseDependencies()
79+
)
6380
})

0 commit comments

Comments
 (0)