@q9labsai/chalk-client 4.1.5 → 4.1.7
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/dist/access/grant.d.ts +8 -0
- package/dist/access/grant.d.ts.map +1 -1
- package/dist/{chunk-PBCGWE2V.js → chunk-C4BIONCP.js} +442 -7
- package/dist/chunk-DFLTEYWX.js +144 -0
- package/dist/chunk-JPNE4K2L.js +8911 -0
- package/dist/{chunk-DI7C5UEM.js → chunk-MMK2K3LO.js} +63 -174
- package/dist/client.d.ts +951 -59
- package/dist/client.d.ts.map +1 -1
- package/dist/connection/dependencies.d.ts +4 -4
- package/dist/connection/dependencies.d.ts.map +1 -1
- package/dist/connection/lifecycle.d.ts.map +1 -1
- package/dist/connection/production.d.ts.map +1 -1
- package/dist/connection/snapshot.d.ts +2 -2
- package/dist/connection/snapshot.d.ts.map +1 -1
- package/dist/effect.js +1012 -7052
- package/dist/generated/http-api.d.ts +941 -62
- package/dist/generated/http-api.d.ts.map +1 -1
- package/dist/generated/schemas.d.ts +1353 -31
- package/dist/generated/schemas.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -2
- package/dist/media/client.d.ts.map +1 -1
- package/dist/media/index.d.ts +2 -1
- package/dist/media/index.d.ts.map +1 -1
- package/dist/media/index.js +5 -1
- package/dist/media/observers.d.ts +3 -0
- package/dist/media/observers.d.ts.map +1 -0
- package/dist/media/plane.d.ts +25 -0
- package/dist/media/plane.d.ts.map +1 -1
- package/dist/media/rtk.d.ts +101 -0
- package/dist/media/rtk.d.ts.map +1 -0
- package/dist/media/target.d.ts +10 -0
- package/dist/media/target.d.ts.map +1 -0
- package/dist/public-invites/client.d.ts +4 -0
- package/dist/public-invites/client.d.ts.map +1 -0
- package/dist/public-invites/index.d.ts +5 -0
- package/dist/public-invites/index.d.ts.map +1 -0
- package/dist/public-invites/index.js +18 -0
- package/dist/public-invites/types.d.ts +67 -0
- package/dist/public-invites/types.d.ts.map +1 -0
- package/dist/server/{chunk-A6YMG5FM.js → chunk-C4XITY5U.js} +1 -1
- package/dist/server/client.d.ts.map +1 -1
- package/dist/server/index.cjs +72 -19
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +72 -19
- package/dist/server/server-only.js +1 -1
- package/dist/server/transport.d.cts +1 -1
- package/dist/server/transport.d.ts +1 -1
- package/dist/server/transport.d.ts.map +1 -1
- package/dist/server/types.d.cts +40 -0
- package/dist/server/types.d.ts +40 -0
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +20 -2
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
CloudflareRTKClient,
|
|
2
3
|
CloudflareSFUClient,
|
|
3
4
|
createCloudflareSFUHTTPTransport
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-C4BIONCP.js";
|
|
6
|
+
import {
|
|
7
|
+
AccessGrantError,
|
|
8
|
+
requireParsedAccessGrant,
|
|
9
|
+
validEpisodeDiagnosticCredential
|
|
10
|
+
} from "./chunk-JPNE4K2L.js";
|
|
5
11
|
import {
|
|
6
12
|
createBrowserSyncLifecycle,
|
|
7
13
|
createBrowserWebSocketFactory,
|
|
@@ -81,7 +87,15 @@ function validateRefresh(previous, next, replaceMediaConnection) {
|
|
|
81
87
|
if (left.tenantId !== right.tenantId || left.spaceId !== right.spaceId || left.episodeId !== right.episodeId || left.participantId !== right.participantId || left.participantGeneration !== right.participantGeneration) {
|
|
82
88
|
throw new TypeError("Access grant refresh changed its subject");
|
|
83
89
|
}
|
|
84
|
-
if (!replaceMediaConnection && previous.media.
|
|
90
|
+
if (!replaceMediaConnection && (previous.media.provider !== next.media.provider || mediaBinding(previous) !== mediaBinding(next))) throw new TypeError("Access grant refresh unexpectedly replaced its media connection");
|
|
91
|
+
}
|
|
92
|
+
function mediaBinding(access) {
|
|
93
|
+
switch (access.media.provider) {
|
|
94
|
+
case "cloudflare_sfu":
|
|
95
|
+
return access.media.clientPayload.connectionId;
|
|
96
|
+
case "cloudflare_rtk":
|
|
97
|
+
return access.media.clientPayload.providerSubject;
|
|
98
|
+
}
|
|
85
99
|
}
|
|
86
100
|
function expiresAt(value) {
|
|
87
101
|
const timestamp = Date.parse(value);
|
|
@@ -1669,8 +1683,18 @@ function createChatFileTransport(apiBaseURL, input) {
|
|
|
1669
1683
|
});
|
|
1670
1684
|
}
|
|
1671
1685
|
function createMediaClient(apiBaseURL, input) {
|
|
1686
|
+
if (input.access.media.provider === "cloudflare_rtk") {
|
|
1687
|
+
return createRTKConnectionMediaClient(
|
|
1688
|
+
new CloudflareRTKClient({
|
|
1689
|
+
authToken: input.access.media.clientPayload.token,
|
|
1690
|
+
participantId: input.access.subject.participantId,
|
|
1691
|
+
onError: input.onFailure,
|
|
1692
|
+
onScreenEnded: input.onScreenEnded
|
|
1693
|
+
})
|
|
1694
|
+
);
|
|
1695
|
+
}
|
|
1672
1696
|
const { subject } = input.access;
|
|
1673
|
-
|
|
1697
|
+
const client = new CloudflareSFUClient({
|
|
1674
1698
|
bootstrap: input.access.media.clientPayload,
|
|
1675
1699
|
participantId: subject.participantId,
|
|
1676
1700
|
transport: createCloudflareSFUHTTPTransport({
|
|
@@ -1684,6 +1708,36 @@ function createMediaClient(apiBaseURL, input) {
|
|
|
1684
1708
|
onError: input.onFailure,
|
|
1685
1709
|
onScreenEnded: input.onScreenEnded
|
|
1686
1710
|
});
|
|
1711
|
+
return createSFUConnectionMediaClient(client);
|
|
1712
|
+
}
|
|
1713
|
+
function createRTKConnectionMediaClient(client) {
|
|
1714
|
+
return bindConnectionMediaClient(client, (input) => {
|
|
1715
|
+
if (!("provider" in input) || input.provider !== "cloudflare_rtk") throw new TypeError("The RealtimeKit adapter requires a Cloudflare RealtimeKit access grant");
|
|
1716
|
+
return client.restart(input);
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
function createSFUConnectionMediaClient(client) {
|
|
1720
|
+
return bindConnectionMediaClient(client, (input) => {
|
|
1721
|
+
if ("provider" in input) {
|
|
1722
|
+
if (input.provider !== "cloudflare_sfu") throw new TypeError("The Cloudflare SFU adapter requires a Cloudflare SFU access grant");
|
|
1723
|
+
return client.restart(input.clientPayload);
|
|
1724
|
+
}
|
|
1725
|
+
return client.restart(input);
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
function bindConnectionMediaClient(client, restart) {
|
|
1729
|
+
return {
|
|
1730
|
+
setLocalPublicationTarget: client.setLocalPublicationTarget.bind(client),
|
|
1731
|
+
observeLocalPublications: client.observeLocalPublications.bind(client),
|
|
1732
|
+
observeRemotePublications: client.observeRemotePublications.bind(client),
|
|
1733
|
+
start: client.start.bind(client),
|
|
1734
|
+
stop: client.stop.bind(client),
|
|
1735
|
+
restart,
|
|
1736
|
+
prepareLocalTrack: client.prepareLocalTrack.bind(client),
|
|
1737
|
+
clearPreparedLocalTrack: client.clearPreparedLocalTrack.bind(client),
|
|
1738
|
+
getSnapshot: client.getSnapshot.bind(client),
|
|
1739
|
+
subscribe: client.subscribe.bind(client)
|
|
1740
|
+
};
|
|
1687
1741
|
}
|
|
1688
1742
|
function createSyncClient(syncURL, input) {
|
|
1689
1743
|
return createV1SyncClient({
|
|
@@ -1725,172 +1779,6 @@ function whiteboardURL(syncURL) {
|
|
|
1725
1779
|
// src/connection/lifecycle.ts
|
|
1726
1780
|
import { Clock as Clock2, Context as Context3, Data as Data2, Deferred, Duration, Effect as Effect2, Exit, Fiber, Layer as Layer3, Queue, Scope, SubscriptionRef } from "effect";
|
|
1727
1781
|
|
|
1728
|
-
// src/access/base64-url.ts
|
|
1729
|
-
function decodeBase64Url(value) {
|
|
1730
|
-
const base64 = value.replaceAll("-", "+").replaceAll("_", "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
|
|
1731
|
-
const bytes = Uint8Array.from(globalThis.atob(base64), (character) => character.charCodeAt(0));
|
|
1732
|
-
return new TextDecoder().decode(bytes);
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
|
-
// src/access/episode-diagnostic-credential.ts
|
|
1736
|
-
var INTAKE_PATH = "/_internal/episode-diagnostic-events";
|
|
1737
|
-
var RFC3339_ZONED = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
|
|
1738
|
-
function parseEpisodeDiagnosticCredential(value) {
|
|
1739
|
-
if (!isRecord3(value)) return null;
|
|
1740
|
-
const token = value.token;
|
|
1741
|
-
const expiresAt2 = value.expires_at;
|
|
1742
|
-
const generation = value.generation;
|
|
1743
|
-
const intakePath = value.intake_path;
|
|
1744
|
-
if (typeof token !== "string" || !validDiagnosticCredential(token)) return null;
|
|
1745
|
-
if (!isRFC3339Zoned(expiresAt2)) return null;
|
|
1746
|
-
if (!Number.isSafeInteger(generation) || generation < 1) return null;
|
|
1747
|
-
if (intakePath !== INTAKE_PATH) return null;
|
|
1748
|
-
return Object.freeze({ token, expiresAt: expiresAt2, generation, intakePath });
|
|
1749
|
-
}
|
|
1750
|
-
function validEpisodeDiagnosticCredential(credential, now) {
|
|
1751
|
-
return credential.intakePath === INTAKE_PATH && Number.isSafeInteger(credential.generation) && credential.generation > 0 && isRFC3339Zoned(credential.expiresAt) && Date.parse(credential.expiresAt) > now && validDiagnosticCredential(credential.token);
|
|
1752
|
-
}
|
|
1753
|
-
function validDiagnosticCredential(token) {
|
|
1754
|
-
const segments = token.split(".");
|
|
1755
|
-
if (segments.length !== 3) return false;
|
|
1756
|
-
try {
|
|
1757
|
-
const payload = JSON.parse(decodeBase64Url(segments[1] ?? ""));
|
|
1758
|
-
return isRecord3(payload) && payload.aud === "chalk-diagnostics";
|
|
1759
|
-
} catch {
|
|
1760
|
-
return false;
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
|
-
function isRFC3339Zoned(value) {
|
|
1764
|
-
if (typeof value !== "string") return false;
|
|
1765
|
-
const match = RFC3339_ZONED.exec(value);
|
|
1766
|
-
if (!match) return false;
|
|
1767
|
-
return validTimestampFields(match) && Number.isFinite(Date.parse(value));
|
|
1768
|
-
}
|
|
1769
|
-
function validTimestampFields(match) {
|
|
1770
|
-
const year = Number(match[1]);
|
|
1771
|
-
const month = Number(match[2]);
|
|
1772
|
-
const day = Number(match[3]);
|
|
1773
|
-
const hour = Number(match[4]);
|
|
1774
|
-
const minute = Number(match[5]);
|
|
1775
|
-
const second = Number(match[6]);
|
|
1776
|
-
const zone = match[7] ?? "";
|
|
1777
|
-
return validCalendarDate(year, month, day) && validClockTime(hour, minute, second) && validZoneOffset(zone);
|
|
1778
|
-
}
|
|
1779
|
-
function inRange(value, min, max) {
|
|
1780
|
-
return value >= min && value <= max;
|
|
1781
|
-
}
|
|
1782
|
-
function validCalendarDate(year, month, day) {
|
|
1783
|
-
return inRange(month, 1, 12) && inRange(day, 1, daysInMonth(year, month));
|
|
1784
|
-
}
|
|
1785
|
-
function validClockTime(hour, minute, second) {
|
|
1786
|
-
return inRange(hour, 0, 23) && inRange(minute, 0, 59) && inRange(second, 0, 59);
|
|
1787
|
-
}
|
|
1788
|
-
function validZoneOffset(zone) {
|
|
1789
|
-
if (zone === "Z") return true;
|
|
1790
|
-
return inRange(Number(zone.slice(1, 3)), 0, 23) && inRange(Number(zone.slice(4, 6)), 0, 59);
|
|
1791
|
-
}
|
|
1792
|
-
function daysInMonth(year, month) {
|
|
1793
|
-
if (month === 2) return isLeapYear(year) ? 29 : 28;
|
|
1794
|
-
return [4, 6, 9, 11].includes(month) ? 30 : 31;
|
|
1795
|
-
}
|
|
1796
|
-
function isLeapYear(year) {
|
|
1797
|
-
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
1798
|
-
}
|
|
1799
|
-
function isRecord3(value) {
|
|
1800
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
// src/access/grant.ts
|
|
1804
|
-
var AccessGrantError = class extends TypeError {
|
|
1805
|
-
code = "access.invalid";
|
|
1806
|
-
constructor(message = "Access grant is invalid") {
|
|
1807
|
-
super(message);
|
|
1808
|
-
this.name = "AccessGrantError";
|
|
1809
|
-
}
|
|
1810
|
-
};
|
|
1811
|
-
function parseParsedAccessGrant(value) {
|
|
1812
|
-
if (!isRecord4(value)) throw new AccessGrantError();
|
|
1813
|
-
const subject = parseSubject(value.subject);
|
|
1814
|
-
const diagnostics = parseEpisodeDiagnosticCredential(value.diagnostics);
|
|
1815
|
-
return {
|
|
1816
|
-
subject,
|
|
1817
|
-
sync: parseSyncAccess(value.sync),
|
|
1818
|
-
media: parseMediaAccess(value.media),
|
|
1819
|
-
diagnostics: diagnostics?.generation === subject.participantGeneration ? diagnostics : null
|
|
1820
|
-
};
|
|
1821
|
-
}
|
|
1822
|
-
async function requireParsedAccessGrant(value) {
|
|
1823
|
-
if (typeof Response !== "undefined" && value instanceof Response) {
|
|
1824
|
-
if (!value.ok) throw new AccessGrantError(`Access grant request failed with HTTP ${value.status}`);
|
|
1825
|
-
try {
|
|
1826
|
-
return parseParsedAccessGrant(await value.json());
|
|
1827
|
-
} catch (error2) {
|
|
1828
|
-
if (error2 instanceof AccessGrantError) throw error2;
|
|
1829
|
-
throw new AccessGrantError();
|
|
1830
|
-
}
|
|
1831
|
-
}
|
|
1832
|
-
return parseParsedAccessGrant(value);
|
|
1833
|
-
}
|
|
1834
|
-
function parseSubject(value) {
|
|
1835
|
-
if (!isRecord4(value)) throw new AccessGrantError();
|
|
1836
|
-
return {
|
|
1837
|
-
tenantId: requireNonEmptyString(value.tenant_id),
|
|
1838
|
-
spaceId: requireNonEmptyString(value.space_id),
|
|
1839
|
-
episodeId: requireNonEmptyString(value.episode_id),
|
|
1840
|
-
participantId: requireNonEmptyString(value.participant_id),
|
|
1841
|
-
participantGeneration: requirePositiveInteger(value.participant_generation)
|
|
1842
|
-
};
|
|
1843
|
-
}
|
|
1844
|
-
function requirePositiveInteger(value) {
|
|
1845
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) throw new AccessGrantError();
|
|
1846
|
-
return value;
|
|
1847
|
-
}
|
|
1848
|
-
function parseSyncAccess(value) {
|
|
1849
|
-
if (!isRecord4(value)) throw new AccessGrantError();
|
|
1850
|
-
return {
|
|
1851
|
-
token: requireCredential(value.token, "chalk-sync"),
|
|
1852
|
-
expiresAt: requireDateTime(value.expires_at ?? value.expiresAt)
|
|
1853
|
-
};
|
|
1854
|
-
}
|
|
1855
|
-
function parseMediaAccess(value) {
|
|
1856
|
-
if (!isRecord4(value) || value.provider !== "cloudflare_sfu" || !isRecord4(value.client_payload ?? value.clientPayload)) throw new AccessGrantError();
|
|
1857
|
-
const payload = value.client_payload ?? value.clientPayload;
|
|
1858
|
-
return {
|
|
1859
|
-
token: requireCredential(value.token, "chalk-media"),
|
|
1860
|
-
expiresAt: requireDateTime(value.expires_at ?? value.expiresAt),
|
|
1861
|
-
provider: value.provider,
|
|
1862
|
-
clientPayload: {
|
|
1863
|
-
connectionId: requireNonEmptyString(payload.connectionId),
|
|
1864
|
-
stunServer: requireNonEmptyString(payload.stunServer)
|
|
1865
|
-
}
|
|
1866
|
-
};
|
|
1867
|
-
}
|
|
1868
|
-
function requireCredential(value, audience) {
|
|
1869
|
-
const token = requireNonEmptyString(value);
|
|
1870
|
-
const segments = token.split(".");
|
|
1871
|
-
if (segments.length !== 3) throw new AccessGrantError();
|
|
1872
|
-
let payload;
|
|
1873
|
-
try {
|
|
1874
|
-
payload = JSON.parse(decodeBase64Url(segments[1] ?? ""));
|
|
1875
|
-
} catch {
|
|
1876
|
-
throw new AccessGrantError();
|
|
1877
|
-
}
|
|
1878
|
-
if (!isRecord4(payload) || payload.aud !== audience) throw new AccessGrantError();
|
|
1879
|
-
return token;
|
|
1880
|
-
}
|
|
1881
|
-
function requireDateTime(value) {
|
|
1882
|
-
const dateTime = requireNonEmptyString(value);
|
|
1883
|
-
if (!Number.isFinite(Date.parse(dateTime))) throw new AccessGrantError();
|
|
1884
|
-
return dateTime;
|
|
1885
|
-
}
|
|
1886
|
-
function requireNonEmptyString(value) {
|
|
1887
|
-
if (typeof value !== "string" || value.trim().length === 0) throw new AccessGrantError();
|
|
1888
|
-
return value;
|
|
1889
|
-
}
|
|
1890
|
-
function isRecord4(value) {
|
|
1891
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1892
|
-
}
|
|
1893
|
-
|
|
1894
1782
|
// src/connection/diagnostics.ts
|
|
1895
1783
|
var ConnectionDiagnostics = class {
|
|
1896
1784
|
#limit;
|
|
@@ -2346,7 +2234,8 @@ var makeConnectionLifecycleLayerFromServices = (options) => Layer3.effect(
|
|
|
2346
2234
|
const sync = model.sync;
|
|
2347
2235
|
if (!media || !sync) return yield* Effect2.fail(lifecycleFailure("invalid_state", false, "Media recovery requires active ports"));
|
|
2348
2236
|
const grant = yield* access.refresh("media_recovery", true).pipe(Effect2.mapError(accessFailure));
|
|
2349
|
-
|
|
2237
|
+
const restartInput = grant.media.provider === "cloudflare_sfu" ? grant.media.clientPayload : grant.media;
|
|
2238
|
+
yield* foreign6(() => media.restart(restartInput));
|
|
2350
2239
|
model.mediaSnapshot = media.getSnapshot();
|
|
2351
2240
|
yield* waitForSyncLive(sync, boundedInteger(options.recovery?.budgetMs, RECOVERY_BUDGET_MS, 1, 6e4));
|
|
2352
2241
|
});
|
|
@@ -4757,7 +4646,7 @@ function stripTrailingUrlSlash(value) {
|
|
|
4757
4646
|
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
4758
4647
|
}
|
|
4759
4648
|
function intakeResponse(value) {
|
|
4760
|
-
if (!
|
|
4649
|
+
if (!isRecord3(value) || typeof value.diagnosticReference !== "string" || !Number.isSafeInteger(value.committedCursor)) return null;
|
|
4761
4650
|
if (!Array.isArray(value.accepted) || !Array.isArray(value.duplicates) || !Array.isArray(value.conflicts)) return null;
|
|
4762
4651
|
return { accepted: value.accepted, duplicates: value.duplicates, conflicts: value.conflicts };
|
|
4763
4652
|
}
|
|
@@ -4768,14 +4657,14 @@ function completeDelivery(delivery, expected) {
|
|
|
4768
4657
|
function intakeIds(items, expected, cursorRequired) {
|
|
4769
4658
|
const ids = [];
|
|
4770
4659
|
for (const item of items) {
|
|
4771
|
-
if (!
|
|
4660
|
+
if (!isRecord3(item) || typeof item.eventId !== "string" || !expected.has(item.eventId)) return null;
|
|
4772
4661
|
if (cursorRequired && !Number.isSafeInteger(item.cursor)) return null;
|
|
4773
4662
|
if (!cursorRequired && item.code !== "fingerprint_mismatch") return null;
|
|
4774
4663
|
ids.push(item.eventId);
|
|
4775
4664
|
}
|
|
4776
4665
|
return ids;
|
|
4777
4666
|
}
|
|
4778
|
-
function
|
|
4667
|
+
function isRecord3(value) {
|
|
4779
4668
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4780
4669
|
}
|
|
4781
4670
|
|
|
@@ -4863,7 +4752,7 @@ var makeSpaceClientCoreLayer = (options, platform = {}) => {
|
|
|
4863
4752
|
now: baseDependencies.clock.now,
|
|
4864
4753
|
setTimeout: baseDependencies.clock.setTimeout,
|
|
4865
4754
|
clearTimeout: baseDependencies.clock.clearTimeout,
|
|
4866
|
-
release: { id: "chalk-client@4.1.
|
|
4755
|
+
release: { id: "chalk-client@4.1.7" }
|
|
4867
4756
|
});
|
|
4868
4757
|
const diagnosticSyncClients = /* @__PURE__ */ new Set();
|
|
4869
4758
|
const dependencies = {
|