@planningcenter/chat-react-native 3.34.0 → 3.35.0-rc.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.
@@ -11,7 +11,7 @@ declare class ErrorBoundary extends React.Component<PropsWithChildren<{
11
11
  componentDidCatch(error: any): void;
12
12
  handleError(error: any): void;
13
13
  handleReset: () => void;
14
- render(): string | number | bigint | boolean | React.JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined;
14
+ render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
15
15
  }
16
16
  export default ErrorBoundary;
17
17
  //# sourceMappingURL=error_boundary.d.ts.map
package/build/index.d.ts CHANGED
@@ -5,13 +5,14 @@ export * from './contexts/chat_context';
5
5
  export * from './contexts/session_context';
6
6
  export * from './navigation';
7
7
  export { ScreenLayout } from './navigation/screenLayout';
8
+ export { CustomEvent } from './polyfills/events/CustomEvent';
9
+ export { default as Event } from './polyfills/events/Event';
8
10
  export * from './screens';
9
11
  export { AgeCheckUnderageScreen } from './screens/age_check/age_check_underage_screen';
10
12
  export * from './types';
11
13
  export { platformFontWeightBold, Session, TemporaryDefaultColorsType, Uri } from './utils';
12
14
  export * from './utils/client';
15
+ export * from './utils/host_bridge';
13
16
  export * from './utils/native_adapters';
14
17
  export { ResponseError } from './utils/response_error';
15
- export { default as Event } from './polyfills/events/Event';
16
- export { CustomEvent } from './polyfills/events/CustomEvent';
17
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAA;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACvF,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,cAAc,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAA;AACtF,cAAc,SAAS,CAAA;AACvB,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,0BAA0B,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAC1F,cAAc,gBAAgB,CAAA;AAC9B,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAA;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACvF,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,cAAc,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAC5D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAC3D,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAA;AACtF,cAAc,SAAS,CAAA;AACvB,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,0BAA0B,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAC1F,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA"}
package/build/index.js CHANGED
@@ -5,13 +5,14 @@ export * from './contexts/chat_context';
5
5
  export * from './contexts/session_context';
6
6
  export * from './navigation';
7
7
  export { ScreenLayout } from './navigation/screenLayout';
8
+ export { CustomEvent } from './polyfills/events/CustomEvent';
9
+ export { default as Event } from './polyfills/events/Event';
8
10
  export * from './screens';
9
11
  export { AgeCheckUnderageScreen } from './screens/age_check/age_check_underage_screen'; // TODO: add to barrel
10
12
  export * from './types';
11
13
  export { platformFontWeightBold, Session, Uri } from './utils';
12
14
  export * from './utils/client';
15
+ export * from './utils/host_bridge';
13
16
  export * from './utils/native_adapters';
14
17
  export { ResponseError } from './utils/response_error';
15
- export { default as Event } from './polyfills/events/Event';
16
- export { CustomEvent } from './polyfills/events/CustomEvent';
17
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAA;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACvF,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,cAAc,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAA,CAAC,sBAAsB;AAC7G,cAAc,SAAS,CAAA;AACvB,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAA8B,GAAG,EAAE,MAAM,SAAS,CAAA;AAC1F,cAAc,gBAAgB,CAAA;AAC9B,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA","sourcesContent":["import './icons/font_awesome'\n\nexport { GroupConversations } from './components'\nexport { ApiProvider, chatQueryClient, useFocusManager } from './contexts/api_provider'\nexport * from './contexts/chat_context'\nexport * from './contexts/session_context'\nexport * from './navigation'\nexport { ScreenLayout } from './navigation/screenLayout'\nexport * from './screens'\nexport { AgeCheckUnderageScreen } from './screens/age_check/age_check_underage_screen' // TODO: add to barrel\nexport * from './types'\nexport { platformFontWeightBold, Session, TemporaryDefaultColorsType, Uri } from './utils'\nexport * from './utils/client'\nexport * from './utils/native_adapters'\nexport { ResponseError } from './utils/response_error'\nexport { default as Event } from './polyfills/events/Event'\nexport { CustomEvent } from './polyfills/events/CustomEvent'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAA;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACvF,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,cAAc,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAC5D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAC3D,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAA,CAAC,sBAAsB;AAC7G,cAAc,SAAS,CAAA;AACvB,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAA8B,GAAG,EAAE,MAAM,SAAS,CAAA;AAC1F,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA","sourcesContent":["import './icons/font_awesome'\n\nexport { GroupConversations } from './components'\nexport { ApiProvider, chatQueryClient, useFocusManager } from './contexts/api_provider'\nexport * from './contexts/chat_context'\nexport * from './contexts/session_context'\nexport * from './navigation'\nexport { ScreenLayout } from './navigation/screenLayout'\nexport { CustomEvent } from './polyfills/events/CustomEvent'\nexport { default as Event } from './polyfills/events/Event'\nexport * from './screens'\nexport { AgeCheckUnderageScreen } from './screens/age_check/age_check_underage_screen' // TODO: add to barrel\nexport * from './types'\nexport { platformFontWeightBold, Session, TemporaryDefaultColorsType, Uri } from './utils'\nexport * from './utils/client'\nexport * from './utils/host_bridge'\nexport * from './utils/native_adapters'\nexport { ResponseError } from './utils/response_error'\n"]}
@@ -0,0 +1,20 @@
1
+ export type HostBridgeMessage = Record<string, unknown> & {
2
+ type?: unknown;
3
+ };
4
+ export type HostBridgeSubscription = {
5
+ remove: () => void;
6
+ };
7
+ export type HostBridgeMessaging = {
8
+ addMessageListener: (handler: (event: HostBridgeMessage) => void) => HostBridgeSubscription;
9
+ sendMessage: (message: HostBridgeMessage) => void;
10
+ };
11
+ export declare const createHostBridge: <TRequest extends string = string, TEvent extends {
12
+ type: string;
13
+ } = {
14
+ type: string;
15
+ }>(messaging: HostBridgeMessaging) => {
16
+ request: <T extends Record<string, unknown>>(type: TRequest, payload?: Record<string, unknown>) => Promise<T>;
17
+ send: (type: TRequest, payload?: Record<string, unknown>) => void;
18
+ subscribe: <E extends TEvent>(eventType: E["type"], handler: (event: E) => void) => (() => void);
19
+ };
20
+ //# sourceMappingURL=host_bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host_bridge.d.ts","sourceRoot":"","sources":["../../src/utils/host_bridge.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAE5E,MAAM,MAAM,sBAAsB,GAAG;IAAE,MAAM,EAAE,MAAM,IAAI,CAAA;CAAE,CAAA;AAE3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,kBAAkB,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,KAAK,sBAAsB,CAAA;IAC3F,WAAW,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAA;CAClD,CAAA;AAOD,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,SAAS,MAAM,GAAG,MAAM,EAChC,MAAM,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAElD,WAAW,mBAAmB;cAsBlB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,QACnC,QAAQ,YACL,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC/B,OAAO,CAAC,CAAC,CAAC;iBAaA,QAAQ,YAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAQ,IAAI;gBAKvD,CAAC,SAAS,MAAM,aACf,CAAC,CAAC,MAAM,CAAC,WACX,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KAC1B,CAAC,MAAM,IAAI,CAAC;CAOlB,CAAA"}
@@ -0,0 +1,46 @@
1
+ const createIdGenerator = () => {
2
+ let counter = 0;
3
+ return () => `req_${Date.now()}_${++counter}`;
4
+ };
5
+ export const createHostBridge = (messaging) => {
6
+ const pending = new Map();
7
+ const nextRequestId = createIdGenerator();
8
+ messaging.addMessageListener(event => {
9
+ const id = typeof event?.requestId === 'string' ? event.requestId : undefined;
10
+ if (!id)
11
+ return;
12
+ const entry = pending.get(id);
13
+ if (!entry)
14
+ return;
15
+ pending.delete(id);
16
+ if (event.error)
17
+ entry.reject(new Error(String(event.error)));
18
+ else
19
+ entry.resolve(event);
20
+ });
21
+ return {
22
+ request: (type, payload = {}) => {
23
+ const requestId = nextRequestId();
24
+ return new Promise((resolve, reject) => {
25
+ pending.set(requestId, {
26
+ resolve: value => resolve(value),
27
+ reject,
28
+ });
29
+ // Spread payload first so it can't override the routing keys.
30
+ messaging.sendMessage({ ...payload, type, requestId });
31
+ });
32
+ },
33
+ send: (type, payload = {}) => {
34
+ // Spread payload first so it can't override the type.
35
+ messaging.sendMessage({ ...payload, type });
36
+ },
37
+ subscribe: (eventType, handler) => {
38
+ const sub = messaging.addMessageListener(event => {
39
+ if (event?.type === eventType)
40
+ handler(event);
41
+ });
42
+ return () => sub.remove();
43
+ },
44
+ };
45
+ };
46
+ //# sourceMappingURL=host_bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host_bridge.js","sourceRoot":"","sources":["../../src/utils/host_bridge.ts"],"names":[],"mappings":"AASA,MAAM,iBAAiB,GAAG,GAAG,EAAE;IAC7B,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,OAAO,GAAG,EAAE,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AAC/C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAI9B,SAA8B,EAC9B,EAAE;IAKF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAA;IAC3C,MAAM,aAAa,GAAG,iBAAiB,EAAE,CAAA;IAEzC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;QACnC,MAAM,EAAE,GAAG,OAAO,KAAK,EAAE,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;QAC7E,IAAI,CAAC,EAAE;YAAE,OAAM;QAEf,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC7B,IAAI,CAAC,KAAK;YAAE,OAAM;QAElB,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QAClB,IAAI,KAAK,CAAC,KAAK;YAAE,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;;YACxD,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC,CAAC,CAAA;IAEF,OAAO;QACL,OAAO,EAAE,CACP,IAAc,EACd,UAAmC,EAAE,EACzB,EAAE;YACd,MAAM,SAAS,GAAG,aAAa,EAAE,CAAA;YAEjC,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACxC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE;oBACrB,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,KAAU,CAAC;oBACrC,MAAM;iBACP,CAAC,CAAA;gBACF,8DAA8D;gBAC9D,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;YACxD,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,EAAE,CAAC,IAAc,EAAE,UAAmC,EAAE,EAAQ,EAAE;YACpE,sDAAsD;YACtD,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7C,CAAC;QAED,SAAS,EAAE,CACT,SAAoB,EACpB,OAA2B,EACb,EAAE;YAChB,MAAM,GAAG,GAAG,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;gBAC/C,IAAI,KAAK,EAAE,IAAI,KAAK,SAAS;oBAAE,OAAO,CAAC,KAAqB,CAAC,CAAA;YAC/D,CAAC,CAAC,CAAA;YACF,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAA;QAC3B,CAAC;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["export type HostBridgeMessage = Record<string, unknown> & { type?: unknown }\n\nexport type HostBridgeSubscription = { remove: () => void }\n\nexport type HostBridgeMessaging = {\n addMessageListener: (handler: (event: HostBridgeMessage) => void) => HostBridgeSubscription\n sendMessage: (message: HostBridgeMessage) => void\n}\n\nconst createIdGenerator = () => {\n let counter = 0\n return () => `req_${Date.now()}_${++counter}`\n}\n\nexport const createHostBridge = <\n TRequest extends string = string,\n TEvent extends { type: string } = { type: string },\n>(\n messaging: HostBridgeMessaging\n) => {\n type Resolver = {\n resolve: (value: Record<string, unknown>) => void\n reject: (error: Error) => void\n }\n const pending = new Map<string, Resolver>()\n const nextRequestId = createIdGenerator()\n\n messaging.addMessageListener(event => {\n const id = typeof event?.requestId === 'string' ? event.requestId : undefined\n if (!id) return\n\n const entry = pending.get(id)\n if (!entry) return\n\n pending.delete(id)\n if (event.error) entry.reject(new Error(String(event.error)))\n else entry.resolve(event)\n })\n\n return {\n request: <T extends Record<string, unknown>>(\n type: TRequest,\n payload: Record<string, unknown> = {}\n ): Promise<T> => {\n const requestId = nextRequestId()\n\n return new Promise<T>((resolve, reject) => {\n pending.set(requestId, {\n resolve: value => resolve(value as T),\n reject,\n })\n // Spread payload first so it can't override the routing keys.\n messaging.sendMessage({ ...payload, type, requestId })\n })\n },\n\n send: (type: TRequest, payload: Record<string, unknown> = {}): void => {\n // Spread payload first so it can't override the type.\n messaging.sendMessage({ ...payload, type })\n },\n\n subscribe: <E extends TEvent>(\n eventType: E['type'],\n handler: (event: E) => void\n ): (() => void) => {\n const sub = messaging.addMessageListener(event => {\n if (event?.type === eventType) handler(event as unknown as E)\n })\n return () => sub.remove()\n },\n }\n}\n"]}
@@ -1,15 +1,16 @@
1
- export * from './session';
2
- export * from './theme';
3
- export * from './styles';
4
- export * from './client';
5
- export * from './uri';
1
+ export * from './assert_keys_are_numbers';
2
+ export * from './attachment_kind';
6
3
  export * from './cache';
4
+ export * from './client';
5
+ export * from './convert_attachments_for_create';
6
+ export * from './destructure_chat_group_graph_id';
7
+ export * from './host_bridge';
7
8
  export * from './native_adapters';
8
9
  export * from './pluralize';
9
10
  export * from './reaction_constants';
10
- export * from './destructure_chat_group_graph_id';
11
- export * from './convert_attachments_for_create';
12
- export * from './assert_keys_are_numbers';
13
- export * from './attachment_kind';
11
+ export * from './session';
12
+ export * from './styles';
14
13
  export * from './system_messages';
14
+ export * from './theme';
15
+ export * from './uri';
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,mCAAmC,CAAA;AACjD,cAAc,kCAAkC,CAAA;AAChD,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,kCAAkC,CAAA;AAChD,cAAc,mCAAmC,CAAA;AACjD,cAAc,eAAe,CAAA;AAC7B,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,mBAAmB,CAAA;AACjC,cAAc,SAAS,CAAA;AACvB,cAAc,OAAO,CAAA"}
@@ -1,15 +1,16 @@
1
- export * from './session';
2
- export * from './theme';
3
- export * from './styles';
4
- export * from './client';
5
- export * from './uri';
1
+ export * from './assert_keys_are_numbers';
2
+ export * from './attachment_kind';
6
3
  export * from './cache';
4
+ export * from './client';
5
+ export * from './convert_attachments_for_create';
6
+ export * from './destructure_chat_group_graph_id';
7
+ export * from './host_bridge';
7
8
  export * from './native_adapters';
8
9
  export * from './pluralize';
9
10
  export * from './reaction_constants';
10
- export * from './destructure_chat_group_graph_id';
11
- export * from './convert_attachments_for_create';
12
- export * from './assert_keys_are_numbers';
13
- export * from './attachment_kind';
11
+ export * from './session';
12
+ export * from './styles';
14
13
  export * from './system_messages';
14
+ export * from './theme';
15
+ export * from './uri';
15
16
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,mCAAmC,CAAA;AACjD,cAAc,kCAAkC,CAAA;AAChD,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA","sourcesContent":["export * from './session'\nexport * from './theme'\nexport * from './styles'\nexport * from './client'\nexport * from './uri'\nexport * from './cache'\nexport * from './native_adapters'\nexport * from './pluralize'\nexport * from './reaction_constants'\nexport * from './destructure_chat_group_graph_id'\nexport * from './convert_attachments_for_create'\nexport * from './assert_keys_are_numbers'\nexport * from './attachment_kind'\nexport * from './system_messages'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,kCAAkC,CAAA;AAChD,cAAc,mCAAmC,CAAA;AACjD,cAAc,eAAe,CAAA;AAC7B,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,mBAAmB,CAAA;AACjC,cAAc,SAAS,CAAA;AACvB,cAAc,OAAO,CAAA","sourcesContent":["export * from './assert_keys_are_numbers'\nexport * from './attachment_kind'\nexport * from './cache'\nexport * from './client'\nexport * from './convert_attachments_for_create'\nexport * from './destructure_chat_group_graph_id'\nexport * from './host_bridge'\nexport * from './native_adapters'\nexport * from './pluralize'\nexport * from './reaction_constants'\nexport * from './session'\nexport * from './styles'\nexport * from './system_messages'\nexport * from './theme'\nexport * from './uri'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.34.0",
3
+ "version": "3.35.0-rc.0",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -65,5 +65,5 @@
65
65
  "react-native-url-polyfill": "^2.0.0",
66
66
  "typescript": "~5.9.2"
67
67
  },
68
- "gitHead": "819a3311af600662814f2c10095c4089deac5775"
68
+ "gitHead": "dd9252ef05d2542745a31cf10b45083a9a365834"
69
69
  }
@@ -0,0 +1,164 @@
1
+ import { createHostBridge, HostBridgeMessage, HostBridgeMessaging } from '../../utils/host_bridge'
2
+
3
+ const createFakeMessaging = () => {
4
+ const listeners: ((event: HostBridgeMessage) => void)[] = []
5
+ const sent: HostBridgeMessage[] = []
6
+ const remove = jest.fn()
7
+
8
+ const messaging: HostBridgeMessaging = {
9
+ addMessageListener: handler => {
10
+ listeners.push(handler)
11
+ return { remove }
12
+ },
13
+ sendMessage: message => {
14
+ sent.push(message)
15
+ },
16
+ }
17
+
18
+ return {
19
+ messaging,
20
+ sent,
21
+ remove,
22
+ emit: (event: HostBridgeMessage) => {
23
+ listeners.forEach(l => l(event))
24
+ },
25
+ }
26
+ }
27
+
28
+ describe('createHostBridge', () => {
29
+ describe('request', () => {
30
+ it('resolves with the host reply when requestId matches', async () => {
31
+ const fake = createFakeMessaging()
32
+ const bridge = createHostBridge(fake.messaging)
33
+
34
+ const promise = bridge.request<{ accessToken: string }>('refreshAccessToken')
35
+ const sent = fake.sent[0]
36
+ fake.emit({ requestId: sent.requestId as string, accessToken: 'abc' })
37
+
38
+ await expect(promise).resolves.toEqual({ requestId: sent.requestId, accessToken: 'abc' })
39
+ })
40
+
41
+ it('rejects with an Error when the host reply carries an error', async () => {
42
+ const fake = createFakeMessaging()
43
+ const bridge = createHostBridge(fake.messaging)
44
+
45
+ const promise = bridge.request('refreshAccessToken')
46
+ const sent = fake.sent[0]
47
+ fake.emit({ requestId: sent.requestId as string, error: 'boom' })
48
+
49
+ await expect(promise).rejects.toThrow('boom')
50
+ })
51
+
52
+ it('ignores replies with non-matching requestIds', async () => {
53
+ const fake = createFakeMessaging()
54
+ const bridge = createHostBridge(fake.messaging)
55
+
56
+ const inFlight = bridge.request('refreshAccessToken')
57
+ fake.emit({ requestId: 'unrelated', accessToken: 'wrong' })
58
+
59
+ const sent = fake.sent[0]
60
+ fake.emit({ requestId: sent.requestId as string, accessToken: 'right' })
61
+
62
+ await expect(inFlight).resolves.toMatchObject({ accessToken: 'right' })
63
+ })
64
+
65
+ it('produces unique requestIds across calls', () => {
66
+ const fake = createFakeMessaging()
67
+ const bridge = createHostBridge(fake.messaging)
68
+
69
+ bridge.request('refreshAccessToken')
70
+ bridge.request('refreshAccessToken')
71
+
72
+ expect(fake.sent[0].requestId).not.toEqual(fake.sent[1].requestId)
73
+ })
74
+
75
+ it('forwards the type and payload to sendMessage with a requestId', () => {
76
+ const fake = createFakeMessaging()
77
+ const bridge = createHostBridge(fake.messaging)
78
+
79
+ bridge.request('shouldRefreshAccessToken', { responseCode: 401 })
80
+
81
+ expect(fake.sent[0]).toMatchObject({
82
+ type: 'shouldRefreshAccessToken',
83
+ responseCode: 401,
84
+ })
85
+ expect(typeof fake.sent[0].requestId).toBe('string')
86
+ })
87
+
88
+ it('payload cannot override the type or requestId routing keys', () => {
89
+ const fake = createFakeMessaging()
90
+ const bridge = createHostBridge(fake.messaging)
91
+
92
+ bridge.request('refreshAccessToken', {
93
+ type: 'somethingElse',
94
+ requestId: 'attacker-controlled',
95
+ })
96
+
97
+ const sent = fake.sent[0]
98
+ expect(sent.type).toBe('refreshAccessToken')
99
+ expect(sent.requestId).not.toBe('attacker-controlled')
100
+ expect(typeof sent.requestId).toBe('string')
101
+ })
102
+ })
103
+
104
+ describe('send', () => {
105
+ it('sends type + payload without a requestId', () => {
106
+ const fake = createFakeMessaging()
107
+ const bridge = createHostBridge(fake.messaging)
108
+
109
+ bridge.send('setChannelId', { channelId: 'c-123' })
110
+
111
+ expect(fake.sent).toHaveLength(1)
112
+ expect(fake.sent[0]).toEqual({ type: 'setChannelId', channelId: 'c-123' })
113
+ expect(fake.sent[0].requestId).toBeUndefined()
114
+ })
115
+
116
+ it('payload cannot override the type', () => {
117
+ const fake = createFakeMessaging()
118
+ const bridge = createHostBridge(fake.messaging)
119
+
120
+ bridge.send('setChannelId', { type: 'somethingElse', channelId: 'c-123' })
121
+
122
+ expect(fake.sent[0].type).toBe('setChannelId')
123
+ })
124
+ })
125
+
126
+ describe('subscribe', () => {
127
+ type ConfigEvent = { type: 'chatChangeConfig'; config: { foo: string } }
128
+ type ClearCacheEvent = { type: 'chatClearCache' }
129
+ type AnyEvent = ConfigEvent | ClearCacheEvent
130
+
131
+ it('invokes the handler when the event type matches', () => {
132
+ const fake = createFakeMessaging()
133
+ const bridge = createHostBridge<string, AnyEvent>(fake.messaging)
134
+ const handler = jest.fn()
135
+
136
+ bridge.subscribe<ConfigEvent>('chatChangeConfig', handler)
137
+ fake.emit({ type: 'chatChangeConfig', config: { foo: 'bar' } })
138
+
139
+ expect(handler).toHaveBeenCalledWith({ type: 'chatChangeConfig', config: { foo: 'bar' } })
140
+ })
141
+
142
+ it('does not invoke the handler when the event type differs', () => {
143
+ const fake = createFakeMessaging()
144
+ const bridge = createHostBridge<string, AnyEvent>(fake.messaging)
145
+ const handler = jest.fn()
146
+
147
+ bridge.subscribe<ConfigEvent>('chatChangeConfig', handler)
148
+ fake.emit({ type: 'chatClearCache' })
149
+
150
+ expect(handler).not.toHaveBeenCalled()
151
+ })
152
+
153
+ it('returns an unsubscribe function that removes the listener', () => {
154
+ const fake = createFakeMessaging()
155
+ const bridge = createHostBridge<string, AnyEvent>(fake.messaging)
156
+ const handler = jest.fn()
157
+
158
+ const unsubscribe = bridge.subscribe<ConfigEvent>('chatChangeConfig', handler)
159
+ unsubscribe()
160
+
161
+ expect(fake.remove).toHaveBeenCalledTimes(1)
162
+ })
163
+ })
164
+ })
package/src/index.tsx CHANGED
@@ -6,12 +6,13 @@ export * from './contexts/chat_context'
6
6
  export * from './contexts/session_context'
7
7
  export * from './navigation'
8
8
  export { ScreenLayout } from './navigation/screenLayout'
9
+ export { CustomEvent } from './polyfills/events/CustomEvent'
10
+ export { default as Event } from './polyfills/events/Event'
9
11
  export * from './screens'
10
12
  export { AgeCheckUnderageScreen } from './screens/age_check/age_check_underage_screen' // TODO: add to barrel
11
13
  export * from './types'
12
14
  export { platformFontWeightBold, Session, TemporaryDefaultColorsType, Uri } from './utils'
13
15
  export * from './utils/client'
16
+ export * from './utils/host_bridge'
14
17
  export * from './utils/native_adapters'
15
18
  export { ResponseError } from './utils/response_error'
16
- export { default as Event } from './polyfills/events/Event'
17
- export { CustomEvent } from './polyfills/events/CustomEvent'
@@ -0,0 +1,72 @@
1
+ export type HostBridgeMessage = Record<string, unknown> & { type?: unknown }
2
+
3
+ export type HostBridgeSubscription = { remove: () => void }
4
+
5
+ export type HostBridgeMessaging = {
6
+ addMessageListener: (handler: (event: HostBridgeMessage) => void) => HostBridgeSubscription
7
+ sendMessage: (message: HostBridgeMessage) => void
8
+ }
9
+
10
+ const createIdGenerator = () => {
11
+ let counter = 0
12
+ return () => `req_${Date.now()}_${++counter}`
13
+ }
14
+
15
+ export const createHostBridge = <
16
+ TRequest extends string = string,
17
+ TEvent extends { type: string } = { type: string },
18
+ >(
19
+ messaging: HostBridgeMessaging
20
+ ) => {
21
+ type Resolver = {
22
+ resolve: (value: Record<string, unknown>) => void
23
+ reject: (error: Error) => void
24
+ }
25
+ const pending = new Map<string, Resolver>()
26
+ const nextRequestId = createIdGenerator()
27
+
28
+ messaging.addMessageListener(event => {
29
+ const id = typeof event?.requestId === 'string' ? event.requestId : undefined
30
+ if (!id) return
31
+
32
+ const entry = pending.get(id)
33
+ if (!entry) return
34
+
35
+ pending.delete(id)
36
+ if (event.error) entry.reject(new Error(String(event.error)))
37
+ else entry.resolve(event)
38
+ })
39
+
40
+ return {
41
+ request: <T extends Record<string, unknown>>(
42
+ type: TRequest,
43
+ payload: Record<string, unknown> = {}
44
+ ): Promise<T> => {
45
+ const requestId = nextRequestId()
46
+
47
+ return new Promise<T>((resolve, reject) => {
48
+ pending.set(requestId, {
49
+ resolve: value => resolve(value as T),
50
+ reject,
51
+ })
52
+ // Spread payload first so it can't override the routing keys.
53
+ messaging.sendMessage({ ...payload, type, requestId })
54
+ })
55
+ },
56
+
57
+ send: (type: TRequest, payload: Record<string, unknown> = {}): void => {
58
+ // Spread payload first so it can't override the type.
59
+ messaging.sendMessage({ ...payload, type })
60
+ },
61
+
62
+ subscribe: <E extends TEvent>(
63
+ eventType: E['type'],
64
+ handler: (event: E) => void
65
+ ): (() => void) => {
66
+ const sub = messaging.addMessageListener(event => {
67
+ if (event?.type === eventType) handler(event as unknown as E)
68
+ })
69
+ return () => sub.remove()
70
+ },
71
+ }
72
+ }
@@ -1,14 +1,15 @@
1
- export * from './session'
2
- export * from './theme'
3
- export * from './styles'
4
- export * from './client'
5
- export * from './uri'
1
+ export * from './assert_keys_are_numbers'
2
+ export * from './attachment_kind'
6
3
  export * from './cache'
4
+ export * from './client'
5
+ export * from './convert_attachments_for_create'
6
+ export * from './destructure_chat_group_graph_id'
7
+ export * from './host_bridge'
7
8
  export * from './native_adapters'
8
9
  export * from './pluralize'
9
10
  export * from './reaction_constants'
10
- export * from './destructure_chat_group_graph_id'
11
- export * from './convert_attachments_for_create'
12
- export * from './assert_keys_are_numbers'
13
- export * from './attachment_kind'
11
+ export * from './session'
12
+ export * from './styles'
14
13
  export * from './system_messages'
14
+ export * from './theme'
15
+ export * from './uri'