@symbiote-native/sms 0.0.1 → 0.1.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/build/angular/index.js +1 -1
- package/build/core/index.js +1 -1
- package/build/core/sms.js +1 -1
- package/build/react/index.js +1 -1
- package/build/vue/index.js +1 -1
- package/package.json +8 -5
- package/src/core/sms.test.ts +0 -141
package/build/angular/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @symbiote-native/sms/angular: the Angular entry over the framework-agnostic core. Same
|
|
2
2
|
// reasoning as the React/Vue entries — no per-instance state and no event stream to wrap in an
|
|
3
3
|
// injectable service, so this is a plain re-export.
|
|
4
|
-
export * from '../core';
|
|
4
|
+
export * from '../core/index.js';
|
package/build/core/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { isAvailableAsync, sendSMSAsync } from './sms';
|
|
1
|
+
export { isAvailableAsync, sendSMSAsync } from './sms.js';
|
package/build/core/sms.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Platform, UnavailabilityError } from 'expo-modules-core';
|
|
2
|
-
import { expoSms } from './native-module';
|
|
2
|
+
import { expoSms } from './native-module.js';
|
|
3
3
|
const NATIVE_MODULE_NAME = 'expo-sms';
|
|
4
4
|
// Android's SMSModule puts a single `Intent.EXTRA_STREAM` on the composer intent and reads
|
|
5
5
|
// `attachments[0]` to fill it, so anything past the first would silently never arrive.
|
package/build/react/index.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
// closes and holds nothing afterwards, and there is no event stream to subscribe to — so there
|
|
4
4
|
// is nothing for a hook to own or clean up. Plain re-export, the same shape
|
|
5
5
|
// packages/secure-store's React entry has for the same reason.
|
|
6
|
-
export * from '../core';
|
|
6
|
+
export * from '../core/index.js';
|
package/build/vue/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @symbiote-native/sms/vue: the Vue entry over the framework-agnostic core. Same reasoning as
|
|
2
2
|
// the React entry — no per-instance state and no event stream to wire onto Vue's reactivity, so
|
|
3
3
|
// this is a plain re-export.
|
|
4
|
-
export * from '../core';
|
|
4
|
+
export * from '../core/index.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/sms",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "expo-sms wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, and Angular adapters. Opens the system SMS composer prefilled with recipients and a message.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -40,7 +40,10 @@
|
|
|
40
40
|
"src",
|
|
41
41
|
"build",
|
|
42
42
|
"build-ngc",
|
|
43
|
-
"native-link.json"
|
|
43
|
+
"native-link.json",
|
|
44
|
+
"!src/**/*.test.*",
|
|
45
|
+
"!src/**/*.spec.*",
|
|
46
|
+
"!src/**/*.detox.*"
|
|
44
47
|
],
|
|
45
48
|
"publishConfig": {
|
|
46
49
|
"access": "public"
|
|
@@ -56,7 +59,7 @@
|
|
|
56
59
|
"react": ">=19.0.0",
|
|
57
60
|
"react-native": ">=0.86",
|
|
58
61
|
"vue": ">=3.5.0",
|
|
59
|
-
"@symbiote-native/angular": "0.6.
|
|
62
|
+
"@symbiote-native/angular": "0.6.2",
|
|
60
63
|
"@symbiote-native/react": "0.2.8",
|
|
61
64
|
"@symbiote-native/vue": "0.3.8"
|
|
62
65
|
},
|
|
@@ -92,10 +95,10 @@
|
|
|
92
95
|
"@vue/runtime-core": "^3.5.13",
|
|
93
96
|
"react": "19.2.3",
|
|
94
97
|
"typescript": "~6.0.0",
|
|
95
|
-
"@symbiote-native/
|
|
98
|
+
"@symbiote-native/angular": "0.6.2",
|
|
96
99
|
"@symbiote-native/engine": "0.1.7",
|
|
97
100
|
"@symbiote-native/react": "0.2.8",
|
|
98
|
-
"@symbiote-native/
|
|
101
|
+
"@symbiote-native/test-utils": "0.1.6",
|
|
99
102
|
"@symbiote-native/vue": "0.3.8"
|
|
100
103
|
},
|
|
101
104
|
"scripts": {
|
package/src/core/sms.test.ts
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
const FAKE_NATIVE_SMS = {
|
|
4
|
-
isAvailableAsync: vi.fn(async () => true),
|
|
5
|
-
sendSMSAsync: vi.fn(async () => ({ result: 'sent' })),
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
// Mutated per test — `Platform.OS` is read at call time, so flipping this between cases is how
|
|
9
|
-
// the Android attachment limit gets exercised without a second import of the module under test.
|
|
10
|
-
const FAKE_PLATFORM = { OS: 'ios' };
|
|
11
|
-
|
|
12
|
-
// The real ExpoSMS native module only exists on device — resolving it via requireNativeModule()
|
|
13
|
-
// at import time would throw in this headless run, so the module-lookup file is faked in place
|
|
14
|
-
// of expo-modules-core's runtime resolution, the same pattern
|
|
15
|
-
// packages/secure-store/src/core/secure-store.test.ts uses.
|
|
16
|
-
vi.mock('./native-module', () => ({
|
|
17
|
-
expoSms: FAKE_NATIVE_SMS,
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
|
-
// expo-modules-core's real entry transitively imports 'react-native', whose Flow-typed source
|
|
21
|
-
// Vitest's Oxc transform can't parse — so only the members used as values are faked.
|
|
22
|
-
vi.mock('expo-modules-core', () => ({
|
|
23
|
-
Platform: FAKE_PLATFORM,
|
|
24
|
-
UnavailabilityError: class UnavailabilityError extends Error {
|
|
25
|
-
constructor(moduleName: string, propertyName: string) {
|
|
26
|
-
super(`${propertyName} is not available on ${moduleName}`);
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
const { isAvailableAsync, sendSMSAsync } = await import('./sms');
|
|
32
|
-
|
|
33
|
-
const IMAGE_ATTACHMENT = {
|
|
34
|
-
uri: 'content://media/external/images/media/1',
|
|
35
|
-
mimeType: 'image/png',
|
|
36
|
-
filename: 'myfile.png',
|
|
37
|
-
};
|
|
38
|
-
const AUDIO_ATTACHMENT = {
|
|
39
|
-
uri: 'content://media/external/audio/media/2',
|
|
40
|
-
mimeType: 'audio/mpeg',
|
|
41
|
-
filename: 'myfile.mp3',
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
beforeEach(() => {
|
|
45
|
-
FAKE_PLATFORM.OS = 'ios';
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
afterEach(() => {
|
|
49
|
-
vi.clearAllMocks();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe('isAvailableAsync', () => {
|
|
53
|
-
it('delegates to the native module', async () => {
|
|
54
|
-
await expect(isAvailableAsync()).resolves.toBe(true);
|
|
55
|
-
expect(FAKE_NATIVE_SMS.isAvailableAsync).toHaveBeenCalledTimes(1);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('reports unavailable rather than throwing when the native method is absent', async () => {
|
|
59
|
-
const { isAvailableAsync: native } = FAKE_NATIVE_SMS;
|
|
60
|
-
// @ts-expect-error -- simulating a platform where the native module has no such method
|
|
61
|
-
FAKE_NATIVE_SMS.isAvailableAsync = undefined;
|
|
62
|
-
|
|
63
|
-
await expect(isAvailableAsync()).resolves.toBe(false);
|
|
64
|
-
|
|
65
|
-
FAKE_NATIVE_SMS.isAvailableAsync = native;
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
describe('sendSMSAsync recipients', () => {
|
|
70
|
-
it('normalizes a single address into an array', async () => {
|
|
71
|
-
await sendSMSAsync('0123456789', 'test');
|
|
72
|
-
expect(FAKE_NATIVE_SMS.sendSMSAsync).toHaveBeenLastCalledWith(['0123456789'], 'test', {});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('passes an array of addresses through unchanged', async () => {
|
|
76
|
-
await sendSMSAsync(['0123456789', '9876543210'], 'test');
|
|
77
|
-
expect(FAKE_NATIVE_SMS.sendSMSAsync).toHaveBeenLastCalledWith(
|
|
78
|
-
['0123456789', '9876543210'],
|
|
79
|
-
'test',
|
|
80
|
-
{},
|
|
81
|
-
);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('resolves with the native result', async () => {
|
|
85
|
-
await expect(sendSMSAsync('0123456789', 'test')).resolves.toEqual({ result: 'sent' });
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('rejects a non-string recipient before reaching the native module', async () => {
|
|
89
|
-
// @ts-expect-error -- the guard exists precisely for callers without type checking
|
|
90
|
-
await expect(sendSMSAsync(['0123456789', null], 'test')).rejects.toThrow(TypeError);
|
|
91
|
-
expect(FAKE_NATIVE_SMS.sendSMSAsync).not.toHaveBeenCalled();
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe('sendSMSAsync attachments', () => {
|
|
96
|
-
it('omits the attachments key entirely when none are given', async () => {
|
|
97
|
-
await sendSMSAsync('0123456789', 'test', {});
|
|
98
|
-
expect(FAKE_NATIVE_SMS.sendSMSAsync).toHaveBeenLastCalledWith(['0123456789'], 'test', {});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('normalizes a single attachment into an array', async () => {
|
|
102
|
-
await sendSMSAsync('0123456789', 'test', { attachments: IMAGE_ATTACHMENT });
|
|
103
|
-
expect(FAKE_NATIVE_SMS.sendSMSAsync).toHaveBeenLastCalledWith(['0123456789'], 'test', {
|
|
104
|
-
attachments: [IMAGE_ATTACHMENT],
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('keeps every attachment on iOS', async () => {
|
|
109
|
-
await sendSMSAsync('0123456789', 'test', {
|
|
110
|
-
attachments: [IMAGE_ATTACHMENT, AUDIO_ATTACHMENT],
|
|
111
|
-
});
|
|
112
|
-
expect(FAKE_NATIVE_SMS.sendSMSAsync).toHaveBeenLastCalledWith(['0123456789'], 'test', {
|
|
113
|
-
attachments: [IMAGE_ATTACHMENT, AUDIO_ATTACHMENT],
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('keeps only the first attachment on Android', async () => {
|
|
118
|
-
FAKE_PLATFORM.OS = 'android';
|
|
119
|
-
|
|
120
|
-
await sendSMSAsync('0123456789', 'test', {
|
|
121
|
-
attachments: [IMAGE_ATTACHMENT, AUDIO_ATTACHMENT],
|
|
122
|
-
});
|
|
123
|
-
expect(FAKE_NATIVE_SMS.sendSMSAsync).toHaveBeenLastCalledWith(['0123456789'], 'test', {
|
|
124
|
-
attachments: [IMAGE_ATTACHMENT],
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
describe('sendSMSAsync without the native method', () => {
|
|
130
|
-
it('throws an UnavailabilityError-shaped error', async () => {
|
|
131
|
-
const { sendSMSAsync: native } = FAKE_NATIVE_SMS;
|
|
132
|
-
// @ts-expect-error -- simulating a platform where the native module has no such method
|
|
133
|
-
FAKE_NATIVE_SMS.sendSMSAsync = undefined;
|
|
134
|
-
|
|
135
|
-
await expect(sendSMSAsync('0123456789', 'test')).rejects.toThrow(
|
|
136
|
-
'sendSMSAsync is not available on expo-sms',
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
FAKE_NATIVE_SMS.sendSMSAsync = native;
|
|
140
|
-
});
|
|
141
|
-
});
|