@itzsudhan/creem-expo 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/README.md +45 -0
- package/app.plugin.js +202 -0
- package/dist/chunk-BF74I2QD.mjs +857 -0
- package/dist/express-BAx2zfw7.d.mts +84 -0
- package/dist/express-jb3wXcce.d.ts +84 -0
- package/dist/index.d.mts +164 -0
- package/dist/index.d.ts +164 -0
- package/dist/index.js +1132 -0
- package/dist/index.mjs +1078 -0
- package/dist/server/express.d.mts +5 -0
- package/dist/server/express.d.ts +5 -0
- package/dist/server/express.js +888 -0
- package/dist/server/express.mjs +10 -0
- package/dist/server/index.d.mts +15 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.js +898 -0
- package/dist/server/index.mjs +25 -0
- package/dist/types-NcFyNrWp.d.mts +271 -0
- package/dist/types-NcFyNrWp.d.ts +271 -0
- package/package.json +106 -0
- package/src/client/apiClient.ts +195 -0
- package/src/client/components/CreemCheckoutButton.tsx +91 -0
- package/src/client/components/CreemCheckoutModal.tsx +81 -0
- package/src/client/components/CreemManageSubscriptionButton.tsx +58 -0
- package/src/client/context.tsx +57 -0
- package/src/client/hooks/useCreemCheckout.ts +478 -0
- package/src/client/hooks/useCreemSubscription.ts +194 -0
- package/src/client/utils/checkoutState.ts +99 -0
- package/src/client/utils/linking.ts +232 -0
- package/src/errors.ts +61 -0
- package/src/index.ts +19 -0
- package/src/server/core.ts +815 -0
- package/src/server/createCreemClient.ts +16 -0
- package/src/server/express.ts +187 -0
- package/src/server/fetchHandlers.ts +191 -0
- package/src/server/index.ts +6 -0
- package/src/server/json.ts +44 -0
- package/src/server/signatures.ts +18 -0
- package/src/types.ts +402 -0
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @itzsudhan/creem-expo
|
|
2
|
+
|
|
3
|
+
Expo-first Creem payments for Expo-managed apps, React Native, and Expo Router projects.
|
|
4
|
+
|
|
5
|
+
Install:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @itzsudhan/creem-expo
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
What you get:
|
|
12
|
+
|
|
13
|
+
- Expo config plugin for `expo prebuild`
|
|
14
|
+
- `useCreemCheckout()`
|
|
15
|
+
- `useCreemSubscription()`
|
|
16
|
+
- browser checkout via `expo-web-browser`
|
|
17
|
+
- modal checkout via `react-native-webview`
|
|
18
|
+
- deep-link handling with `expo-linking`
|
|
19
|
+
- server helpers for checkout creation, verification, webhooks, and subscriptions
|
|
20
|
+
|
|
21
|
+
Quick example:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import {
|
|
25
|
+
CreemProvider,
|
|
26
|
+
createCreemApiClient,
|
|
27
|
+
useCreemCheckout,
|
|
28
|
+
} from "@itzsudhan/creem-expo";
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Use the config plugin:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
export default {
|
|
35
|
+
expo: {
|
|
36
|
+
plugins: [["@itzsudhan/creem-expo", { scheme: "myapp" }]],
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Full repo, examples, and guides:
|
|
42
|
+
|
|
43
|
+
- GitHub: https://github.com/SudhanPlayz/creem-expo
|
|
44
|
+
- Guide: https://github.com/SudhanPlayz/creem-expo/blob/main/GUIDE.md
|
|
45
|
+
- Docs index: https://github.com/SudhanPlayz/creem-expo/blob/main/docs/README.md
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
const {
|
|
2
|
+
createRunOncePlugin,
|
|
3
|
+
withAndroidManifest,
|
|
4
|
+
withInfoPlist,
|
|
5
|
+
} = require("@expo/config-plugins");
|
|
6
|
+
|
|
7
|
+
const PACKAGE_NAME = "@itzsudhan/creem-expo";
|
|
8
|
+
const PLUGIN_NAME = "creem-expo";
|
|
9
|
+
|
|
10
|
+
const normalizeSchemes = (scheme) => {
|
|
11
|
+
if (!scheme) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (Array.isArray(scheme)) {
|
|
16
|
+
return scheme.filter(Boolean);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return [scheme];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const getFirstScheme = (config) => normalizeSchemes(config.scheme)[0];
|
|
23
|
+
|
|
24
|
+
const validateScheme = (scheme) => {
|
|
25
|
+
const normalized = String(scheme ?? "").trim();
|
|
26
|
+
|
|
27
|
+
if (!normalized) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`${PACKAGE_NAME} requires a non-empty scheme. Pass \`plugins: [["${PACKAGE_NAME}", { scheme: "myapp" }]]\`, set \`expo.scheme\`, or provide both native identifiers for fallback.`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!/^[a-z][a-z0-9+.-]*$/i.test(normalized)) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`${PACKAGE_NAME} received an invalid scheme "${scheme}". Schemes must start with a letter and may contain letters, numbers, "+", "-", or ".".`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return normalized;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const resolveScheme = (config, props = {}) => {
|
|
43
|
+
const explicitScheme = props.scheme ?? getFirstScheme(config);
|
|
44
|
+
|
|
45
|
+
if (explicitScheme) {
|
|
46
|
+
return validateScheme(explicitScheme);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const fallbackScheme =
|
|
50
|
+
config.ios?.bundleIdentifier ?? config.android?.package ?? undefined;
|
|
51
|
+
|
|
52
|
+
if (!fallbackScheme) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`${PACKAGE_NAME} requires either a plugin \`scheme\`, \`expo.scheme\`, or at least one of \`ios.bundleIdentifier\` / \`android.package\` so a redirect scheme can be resolved.`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return validateScheme(fallbackScheme);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const ensureScheme = (config, nextScheme) => {
|
|
62
|
+
const merged = normalizeSchemes(config.scheme);
|
|
63
|
+
|
|
64
|
+
if (!merged.includes(nextScheme)) {
|
|
65
|
+
merged.push(nextScheme);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
config.scheme = merged.length === 1 ? merged[0] : merged;
|
|
69
|
+
return merged;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const ensureExtra = (config, resolvedScheme, schemes) => {
|
|
73
|
+
config.extra = {
|
|
74
|
+
...(config.extra ?? {}),
|
|
75
|
+
creem: {
|
|
76
|
+
...(config.extra?.creem ?? {}),
|
|
77
|
+
scheme: resolvedScheme,
|
|
78
|
+
schemes,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const patchIosPlist = (infoPlist, resolvedScheme) => {
|
|
84
|
+
const nextInfoPlist = {
|
|
85
|
+
...(infoPlist ?? {}),
|
|
86
|
+
};
|
|
87
|
+
const urlTypes = nextInfoPlist.CFBundleURLTypes ?? [];
|
|
88
|
+
const hasScheme = urlTypes.some((entry) =>
|
|
89
|
+
(entry.CFBundleURLSchemes ?? []).includes(resolvedScheme)
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (!hasScheme) {
|
|
93
|
+
urlTypes.push({
|
|
94
|
+
CFBundleURLName: PLUGIN_NAME,
|
|
95
|
+
CFBundleURLSchemes: [resolvedScheme],
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
nextInfoPlist.CFBundleURLTypes = urlTypes;
|
|
100
|
+
return nextInfoPlist;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const findAndroidActivity = (application) => {
|
|
104
|
+
const activities = application?.activity ?? [];
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
activities.find((activity) =>
|
|
108
|
+
(activity["intent-filter"] ?? []).some((filter) =>
|
|
109
|
+
(filter.action ?? []).some(
|
|
110
|
+
(entry) => entry.$["android:name"] === "android.intent.action.MAIN"
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
) ??
|
|
114
|
+
activities[0]
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const patchAndroidManifest = (androidManifest, resolvedScheme) => {
|
|
119
|
+
const application = androidManifest?.manifest?.application?.[0];
|
|
120
|
+
|
|
121
|
+
if (!application) {
|
|
122
|
+
return androidManifest;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const activity = findAndroidActivity(application);
|
|
126
|
+
|
|
127
|
+
if (!activity) {
|
|
128
|
+
return androidManifest;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const filters = activity["intent-filter"] ?? [];
|
|
132
|
+
const hasScheme = filters.some((filter) =>
|
|
133
|
+
(filter.data ?? []).some(
|
|
134
|
+
(entry) => entry.$["android:scheme"] === resolvedScheme
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
if (!hasScheme) {
|
|
139
|
+
filters.push({
|
|
140
|
+
action: [{ $: { "android:name": "android.intent.action.VIEW" } }],
|
|
141
|
+
category: [
|
|
142
|
+
{ $: { "android:name": "android.intent.category.DEFAULT" } },
|
|
143
|
+
{ $: { "android:name": "android.intent.category.BROWSABLE" } },
|
|
144
|
+
],
|
|
145
|
+
data: [{ $: { "android:scheme": resolvedScheme } }],
|
|
146
|
+
});
|
|
147
|
+
activity["intent-filter"] = filters;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return androidManifest;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const applyPatchedModResults = (patchedConfig, patcher, resolvedScheme) => {
|
|
154
|
+
patchedConfig.modResults = patcher(patchedConfig.modResults, resolvedScheme);
|
|
155
|
+
return patchedConfig;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const applyInfoPlistMod = (patchedConfig, resolvedScheme) =>
|
|
159
|
+
applyPatchedModResults(patchedConfig, patchIosPlist, resolvedScheme);
|
|
160
|
+
|
|
161
|
+
const applyAndroidManifestMod = (patchedConfig, resolvedScheme) =>
|
|
162
|
+
applyPatchedModResults(patchedConfig, patchAndroidManifest, resolvedScheme);
|
|
163
|
+
|
|
164
|
+
const withCreemExpoBase = (config, props = {}) => {
|
|
165
|
+
const nextConfig = { ...config };
|
|
166
|
+
const resolvedScheme = resolveScheme(nextConfig, props);
|
|
167
|
+
const schemes = ensureScheme(nextConfig, resolvedScheme);
|
|
168
|
+
|
|
169
|
+
ensureExtra(nextConfig, resolvedScheme, schemes);
|
|
170
|
+
const withPatchedIos = withInfoPlist(nextConfig, (patchedConfig) =>
|
|
171
|
+
applyInfoPlistMod(patchedConfig, resolvedScheme)
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
return withAndroidManifest(
|
|
175
|
+
withPatchedIos,
|
|
176
|
+
(patchedConfig) => applyAndroidManifestMod(patchedConfig, resolvedScheme)
|
|
177
|
+
);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const withCreemExpo = createRunOncePlugin(
|
|
181
|
+
withCreemExpoBase,
|
|
182
|
+
PACKAGE_NAME,
|
|
183
|
+
require("./package.json").version
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
module.exports = withCreemExpo;
|
|
187
|
+
module.exports.default = withCreemExpo;
|
|
188
|
+
module.exports.__internal = {
|
|
189
|
+
normalizeSchemes,
|
|
190
|
+
getFirstScheme,
|
|
191
|
+
validateScheme,
|
|
192
|
+
resolveScheme,
|
|
193
|
+
ensureScheme,
|
|
194
|
+
ensureExtra,
|
|
195
|
+
patchIosPlist,
|
|
196
|
+
findAndroidActivity,
|
|
197
|
+
patchAndroidManifest,
|
|
198
|
+
applyPatchedModResults,
|
|
199
|
+
applyInfoPlistMod,
|
|
200
|
+
applyAndroidManifestMod,
|
|
201
|
+
withCreemExpoBase,
|
|
202
|
+
};
|