@dodicandra/minesec-rn 1.0.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +444 -0
  3. package/android/build.gradle +54 -0
  4. package/android/src/main/AndroidManifest.xml +12 -0
  5. package/android/src/main/java/expo/modules/minesecrn/MinesecrnHeadlessActivity.kt +5 -0
  6. package/android/src/main/java/expo/modules/minesecrn/MinesecrnModule.kt +87 -0
  7. package/android/src/main/java/expo/modules/minesecrn/PoiRequestMapper.kt +101 -0
  8. package/android/src/main/java/expo/modules/minesecrn/ResultMappers.kt +52 -0
  9. package/app.plugin.js +1 -0
  10. package/build/Minesecrn.types.d.ts +91 -0
  11. package/build/Minesecrn.types.d.ts.map +1 -0
  12. package/build/Minesecrn.types.js +3 -0
  13. package/build/Minesecrn.types.js.map +1 -0
  14. package/build/MinesecrnModule.d.ts +36 -0
  15. package/build/MinesecrnModule.d.ts.map +1 -0
  16. package/build/MinesecrnModule.js +3 -0
  17. package/build/MinesecrnModule.js.map +1 -0
  18. package/build/MinesecrnModule.web.d.ts +11 -0
  19. package/build/MinesecrnModule.web.d.ts.map +1 -0
  20. package/build/MinesecrnModule.web.js +22 -0
  21. package/build/MinesecrnModule.web.js.map +1 -0
  22. package/build/index.d.ts +3 -0
  23. package/build/index.d.ts.map +1 -0
  24. package/build/index.js +3 -0
  25. package/build/index.js.map +1 -0
  26. package/expo-module.config.json +10 -0
  27. package/ios/Minesecrn.podspec +24 -0
  28. package/ios/MinesecrnModule.swift +37 -0
  29. package/package.json +80 -0
  30. package/plugin/build/index.d.ts +22 -0
  31. package/plugin/build/index.d.ts.map +1 -0
  32. package/plugin/build/index.js +219 -0
  33. package/plugin/src/index.ts +239 -0
  34. package/plugin/tsconfig.json +17 -0
  35. package/plugin/tsconfig.tsbuildinfo +1 -0
  36. package/src/Minesecrn.types.ts +126 -0
  37. package/src/MinesecrnModule.ts +52 -0
  38. package/src/MinesecrnModule.web.ts +27 -0
  39. package/src/index.ts +2 -0
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const config_plugins_1 = require("@expo/config-plugins");
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const { getMainApplicationOrThrow } = config_plugins_1.AndroidConfig.Manifest;
40
+ const HEADLESS_ACTIVITY = 'expo.modules.minesecrn.MinesecrnHeadlessActivity';
41
+ const MINESEC_MAVEN_URL = 'https://maven.pkg.github.com/TheMinesec/ms-registry-client';
42
+ const OLD_MINESEC_MAVEN_URL = 'https://maven.theminesec.com/releases';
43
+ const MINESEC_MIN_SDK = 30;
44
+ const MINESEC_SENTINEL = '/* minesec-minSdk */';
45
+ /**
46
+ * Hapus satu maven block yang mengandung urlSubstring.
47
+ * Menghitung nested braces agar aman untuk blok credentials/content bersarang.
48
+ */
49
+ function removeMavenBlock(contents, urlSubstring) {
50
+ const lines = contents.split('\n');
51
+ let i = 0;
52
+ while (i < lines.length) {
53
+ if (lines[i].includes(urlSubstring)) {
54
+ // Cari baris pembuka `maven {` dengan mundur
55
+ let openIdx = i;
56
+ while (openIdx > 0 && !lines[openIdx].trimStart().startsWith('maven')) {
57
+ openIdx--;
58
+ }
59
+ // Hitung brace untuk menemukan penutup `}`
60
+ let depth = 0;
61
+ let closeIdx = openIdx;
62
+ for (let j = openIdx; j < lines.length; j++) {
63
+ for (const ch of lines[j]) {
64
+ if (ch === '{')
65
+ depth++;
66
+ else if (ch === '}')
67
+ depth--;
68
+ }
69
+ if (depth === 0) {
70
+ closeIdx = j;
71
+ break;
72
+ }
73
+ }
74
+ lines.splice(openIdx, closeIdx - openIdx + 1);
75
+ i = openIdx;
76
+ }
77
+ else {
78
+ i++;
79
+ }
80
+ }
81
+ return lines.join('\n');
82
+ }
83
+ const withMinesecManifest = (config, options = {}) => (0, config_plugins_1.withAndroidManifest)(config, (mod) => {
84
+ var _a;
85
+ const manifest = mod.modResults.manifest;
86
+ const enableNfc = (_a = options.enableNfc) !== null && _a !== void 0 ? _a : true;
87
+ if (!manifest['uses-permission'])
88
+ manifest['uses-permission'] = [];
89
+ if (!manifest['uses-feature'])
90
+ manifest['uses-feature'] = [];
91
+ const permissions = manifest['uses-permission'];
92
+ const features = manifest['uses-feature'];
93
+ if (!permissions.some((p) => p.$['android:name'] === 'android.permission.INTERNET')) {
94
+ permissions.push({ $: { 'android:name': 'android.permission.INTERNET' } });
95
+ }
96
+ if (enableNfc) {
97
+ if (!permissions.some((p) => p.$['android:name'] === 'android.permission.NFC')) {
98
+ permissions.push({ $: { 'android:name': 'android.permission.NFC' } });
99
+ }
100
+ if (!features.some((f) => f.$['android:name'] === 'android.hardware.nfc')) {
101
+ features.push({
102
+ $: { 'android:name': 'android.hardware.nfc', 'android:required': 'true' },
103
+ });
104
+ }
105
+ }
106
+ const mainApplication = getMainApplicationOrThrow(mod.modResults);
107
+ if (!mainApplication.activity)
108
+ mainApplication.activity = [];
109
+ const activities = mainApplication.activity;
110
+ // SDK v1 (headless 1.2.37): activity berjalan di proses utama dengan
111
+ // launchMode singleTask, mengikuti contoh resmi ms-example-sdk-headless.
112
+ // Proses terpisah (":headless") hanya untuk SDK v2 (headless-mpoc).
113
+ const existingActivity = activities.find((a) => a.$['android:name'] === HEADLESS_ACTIVITY);
114
+ if (existingActivity) {
115
+ delete existingActivity.$['android:process'];
116
+ existingActivity.$['android:launchMode'] = 'singleTask';
117
+ }
118
+ else {
119
+ activities.push({
120
+ $: {
121
+ 'android:name': HEADLESS_ACTIVITY,
122
+ 'android:exported': 'false',
123
+ 'android:launchMode': 'singleTask',
124
+ },
125
+ });
126
+ }
127
+ return mod;
128
+ });
129
+ const withMinesecRootGradle = (config) => (0, config_plugins_1.withProjectBuildGradle)(config, (mod) => {
130
+ // Hapus blok lama (handle nested braces dengan removeMavenBlock)
131
+ mod.modResults.contents = removeMavenBlock(mod.modResults.contents, OLD_MINESEC_MAVEN_URL);
132
+ mod.modResults.contents = removeMavenBlock(mod.modResults.contents, MINESEC_MAVEN_URL);
133
+ // Inject blok baru dengan credentials yang benar
134
+ const mavenBlock = `
135
+ maven {
136
+ url = uri("${MINESEC_MAVEN_URL}")
137
+ credentials {
138
+ username = (findProperty("username") ?: System.getenv("MINESEC_MAVEN_USER") ?: "").toString()
139
+ password = (findProperty("usertoken") ?: System.getenv("MINESEC_MAVEN_TOKEN") ?: "").toString()
140
+ }
141
+ content {
142
+ includeGroupByRegex "com\\\\.theminesec\\\\..*"
143
+ }
144
+ }`;
145
+ mod.modResults.contents = mod.modResults.contents.replace(/allprojects\s*\{\s*\n(\s*)repositories\s*\{/, `allprojects {\n$1repositories {${mavenBlock}`);
146
+ return mod;
147
+ });
148
+ const withMinesecAppGradle = (config) => (0, config_plugins_1.withAppBuildGradle)(config, (mod) => {
149
+ // Pastikan minSdkVersion >= MINESEC_MIN_SDK; idempoten via sentinel
150
+ if (!mod.modResults.contents.includes(MINESEC_SENTINEL)) {
151
+ mod.modResults.contents = mod.modResults.contents.replace(/minSdkVersion\s+\S+/, `minSdkVersion Math.max(rootProject.ext.minSdkVersion.toInteger(), ${MINESEC_MIN_SDK}) ${MINESEC_SENTINEL}`);
152
+ }
153
+ // Tambah packaging exclusions jika belum ada
154
+ if (mod.modResults.contents.includes('packagingOptions') &&
155
+ !mod.modResults.contents.includes('META-INF/DEPENDENCIES')) {
156
+ const exclusionsBlock = `
157
+ resources {
158
+ excludes += [
159
+ 'META-INF/DEPENDENCIES',
160
+ 'META-INF/LICENSE*',
161
+ 'META-INF/NOTICE*',
162
+ ]
163
+ }`;
164
+ mod.modResults.contents = mod.modResults.contents.replace(/packagingOptions\s*\{/, `packagingOptions {${exclusionsBlock}`);
165
+ }
166
+ return mod;
167
+ });
168
+ const withMinesecGradleProperties = (config, options) => (0, config_plugins_1.withGradleProperties)(config, (mod) => {
169
+ // Hapus entri lama agar tidak duplikat
170
+ mod.modResults = mod.modResults.filter((item) => !(item.type === 'property' && (item.key === 'username' || item.key === 'usertoken')));
171
+ if (options.username) {
172
+ mod.modResults.push({ type: 'property', key: 'username', value: options.username });
173
+ }
174
+ if (options.usertoken) {
175
+ mod.modResults.push({ type: 'property', key: 'usertoken', value: options.usertoken });
176
+ }
177
+ return mod;
178
+ });
179
+ const withMinesecLicenseFile = (config, options) => (0, config_plugins_1.withAndroidManifest)(config, (mod) => {
180
+ const { projectRoot } = mod.modRequest;
181
+ const licenseFileName = options.licenseFileName;
182
+ const srcPath = path.join(projectRoot, licenseFileName);
183
+ const destDir = path.join(projectRoot, 'android', 'app', 'src', 'main', 'assets');
184
+ const destPath = path.join(destDir, path.basename(licenseFileName));
185
+ if (fs.existsSync(srcPath)) {
186
+ if (!fs.existsSync(destDir))
187
+ fs.mkdirSync(destDir, { recursive: true });
188
+ fs.copyFileSync(srcPath, destPath);
189
+ }
190
+ else {
191
+ console.warn(`[minesecrn] License file not found: ${srcPath}. Tempatkan file di project root sebelum build.`);
192
+ }
193
+ return mod;
194
+ });
195
+ /**
196
+ * Expo Config Plugin untuk Minesec Headless SoftPOS SDK.
197
+ *
198
+ * Options (di app.json):
199
+ * enableNfc — tambah NFC permission/feature (default: true). Set false jika konflik dengan lib lain.
200
+ * licenseFileName — nama file lisensi SDK dari project root; dicopy ke android assets saat prebuild.
201
+ * username — Maven username; ditulis ke gradle.properties sebagai "username".
202
+ * usertoken — Maven token; ditulis ke gradle.properties sebagai "usertoken".
203
+ *
204
+ * Untuk production, gunakan ~/.gradle/gradle.properties atau env vars
205
+ * MINESEC_MAVEN_USER / MINESEC_MAVEN_TOKEN daripada menyimpan credentials di app.json.
206
+ */
207
+ const withMinesec = (config, options = {}) => {
208
+ config = withMinesecManifest(config, options);
209
+ config = withMinesecRootGradle(config);
210
+ config = withMinesecAppGradle(config);
211
+ if (options.username || options.usertoken) {
212
+ config = withMinesecGradleProperties(config, options);
213
+ }
214
+ if (options.licenseFileName) {
215
+ config = withMinesecLicenseFile(config, options);
216
+ }
217
+ return config;
218
+ };
219
+ exports.default = withMinesec;
@@ -0,0 +1,239 @@
1
+ import {
2
+ type ConfigPlugin,
3
+ withAndroidManifest,
4
+ withProjectBuildGradle,
5
+ withAppBuildGradle,
6
+ withGradleProperties,
7
+ AndroidConfig,
8
+ } from '@expo/config-plugins';
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+
12
+ const { getMainApplicationOrThrow } = AndroidConfig.Manifest;
13
+
14
+ export interface MinesecPluginOptions {
15
+ enableNfc?: boolean;
16
+ licenseFileName?: string;
17
+ username?: string;
18
+ usertoken?: string;
19
+ }
20
+
21
+ const HEADLESS_ACTIVITY = 'expo.modules.minesecrn.MinesecrnHeadlessActivity';
22
+ const MINESEC_MAVEN_URL = 'https://maven.pkg.github.com/TheMinesec/ms-registry-client';
23
+ const OLD_MINESEC_MAVEN_URL = 'https://maven.theminesec.com/releases';
24
+ const MINESEC_MIN_SDK = 30;
25
+ const MINESEC_SENTINEL = '/* minesec-minSdk */';
26
+
27
+ /**
28
+ * Hapus satu maven block yang mengandung urlSubstring.
29
+ * Menghitung nested braces agar aman untuk blok credentials/content bersarang.
30
+ */
31
+ function removeMavenBlock(contents: string, urlSubstring: string): string {
32
+ const lines = contents.split('\n');
33
+ let i = 0;
34
+ while (i < lines.length) {
35
+ if (lines[i].includes(urlSubstring)) {
36
+ // Cari baris pembuka `maven {` dengan mundur
37
+ let openIdx = i;
38
+ while (openIdx > 0 && !lines[openIdx].trimStart().startsWith('maven')) {
39
+ openIdx--;
40
+ }
41
+ // Hitung brace untuk menemukan penutup `}`
42
+ let depth = 0;
43
+ let closeIdx = openIdx;
44
+ for (let j = openIdx; j < lines.length; j++) {
45
+ for (const ch of lines[j]) {
46
+ if (ch === '{') depth++;
47
+ else if (ch === '}') depth--;
48
+ }
49
+ if (depth === 0) {
50
+ closeIdx = j;
51
+ break;
52
+ }
53
+ }
54
+ lines.splice(openIdx, closeIdx - openIdx + 1);
55
+ i = openIdx;
56
+ } else {
57
+ i++;
58
+ }
59
+ }
60
+ return lines.join('\n');
61
+ }
62
+
63
+ const withMinesecManifest: ConfigPlugin<MinesecPluginOptions> = (config, options = {}) =>
64
+ withAndroidManifest(config, (mod) => {
65
+ const manifest = mod.modResults.manifest;
66
+ const enableNfc = options.enableNfc ?? true;
67
+
68
+ if (!manifest['uses-permission']) manifest['uses-permission'] = [];
69
+ if (!manifest['uses-feature']) manifest['uses-feature'] = [];
70
+
71
+ const permissions = manifest['uses-permission'] as { $: { 'android:name': string } }[];
72
+ const features = manifest['uses-feature'] as {
73
+ $: { 'android:name': string; 'android:required': string };
74
+ }[];
75
+
76
+ if (!permissions.some((p) => p.$['android:name'] === 'android.permission.INTERNET')) {
77
+ permissions.push({ $: { 'android:name': 'android.permission.INTERNET' } });
78
+ }
79
+
80
+ if (enableNfc) {
81
+ if (!permissions.some((p) => p.$['android:name'] === 'android.permission.NFC')) {
82
+ permissions.push({ $: { 'android:name': 'android.permission.NFC' } });
83
+ }
84
+ if (!features.some((f) => f.$['android:name'] === 'android.hardware.nfc')) {
85
+ features.push({
86
+ $: { 'android:name': 'android.hardware.nfc', 'android:required': 'true' },
87
+ });
88
+ }
89
+ }
90
+
91
+ const mainApplication = getMainApplicationOrThrow(mod.modResults);
92
+ if (!mainApplication.activity) mainApplication.activity = [];
93
+
94
+ const activities = mainApplication.activity as { $: Record<string, string> }[];
95
+ // SDK v1 (headless 1.2.37): activity berjalan di proses utama dengan
96
+ // launchMode singleTask, mengikuti contoh resmi ms-example-sdk-headless.
97
+ // Proses terpisah (":headless") hanya untuk SDK v2 (headless-mpoc).
98
+ const existingActivity = activities.find((a) => a.$['android:name'] === HEADLESS_ACTIVITY);
99
+ if (existingActivity) {
100
+ delete existingActivity.$['android:process'];
101
+ existingActivity.$['android:launchMode'] = 'singleTask';
102
+ } else {
103
+ activities.push({
104
+ $: {
105
+ 'android:name': HEADLESS_ACTIVITY,
106
+ 'android:exported': 'false',
107
+ 'android:launchMode': 'singleTask',
108
+ },
109
+ });
110
+ }
111
+
112
+ return mod;
113
+ });
114
+
115
+ const withMinesecRootGradle: ConfigPlugin = (config) =>
116
+ withProjectBuildGradle(config, (mod) => {
117
+ // Hapus blok lama (handle nested braces dengan removeMavenBlock)
118
+ mod.modResults.contents = removeMavenBlock(mod.modResults.contents, OLD_MINESEC_MAVEN_URL);
119
+ mod.modResults.contents = removeMavenBlock(mod.modResults.contents, MINESEC_MAVEN_URL);
120
+
121
+ // Inject blok baru dengan credentials yang benar
122
+ const mavenBlock = `
123
+ maven {
124
+ url = uri("${MINESEC_MAVEN_URL}")
125
+ credentials {
126
+ username = (findProperty("username") ?: System.getenv("MINESEC_MAVEN_USER") ?: "").toString()
127
+ password = (findProperty("usertoken") ?: System.getenv("MINESEC_MAVEN_TOKEN") ?: "").toString()
128
+ }
129
+ content {
130
+ includeGroupByRegex "com\\\\.theminesec\\\\..*"
131
+ }
132
+ }`;
133
+
134
+ mod.modResults.contents = mod.modResults.contents.replace(
135
+ /allprojects\s*\{\s*\n(\s*)repositories\s*\{/,
136
+ `allprojects {\n$1repositories {${mavenBlock}`
137
+ );
138
+
139
+ return mod;
140
+ });
141
+
142
+ const withMinesecAppGradle: ConfigPlugin = (config) =>
143
+ withAppBuildGradle(config, (mod) => {
144
+ // Pastikan minSdkVersion >= MINESEC_MIN_SDK; idempoten via sentinel
145
+ if (!mod.modResults.contents.includes(MINESEC_SENTINEL)) {
146
+ mod.modResults.contents = mod.modResults.contents.replace(
147
+ /minSdkVersion\s+\S+/,
148
+ `minSdkVersion Math.max(rootProject.ext.minSdkVersion.toInteger(), ${MINESEC_MIN_SDK}) ${MINESEC_SENTINEL}`
149
+ );
150
+ }
151
+
152
+ // Tambah packaging exclusions jika belum ada
153
+ if (
154
+ mod.modResults.contents.includes('packagingOptions') &&
155
+ !mod.modResults.contents.includes('META-INF/DEPENDENCIES')
156
+ ) {
157
+ const exclusionsBlock = `
158
+ resources {
159
+ excludes += [
160
+ 'META-INF/DEPENDENCIES',
161
+ 'META-INF/LICENSE*',
162
+ 'META-INF/NOTICE*',
163
+ ]
164
+ }`;
165
+ mod.modResults.contents = mod.modResults.contents.replace(
166
+ /packagingOptions\s*\{/,
167
+ `packagingOptions {${exclusionsBlock}`
168
+ );
169
+ }
170
+
171
+ return mod;
172
+ });
173
+
174
+ const withMinesecGradleProperties: ConfigPlugin<MinesecPluginOptions> = (config, options) =>
175
+ withGradleProperties(config, (mod) => {
176
+ // Hapus entri lama agar tidak duplikat
177
+ mod.modResults = mod.modResults.filter(
178
+ (item) => !(item.type === 'property' && (item.key === 'username' || item.key === 'usertoken'))
179
+ );
180
+
181
+ if (options.username) {
182
+ mod.modResults.push({ type: 'property', key: 'username', value: options.username });
183
+ }
184
+ if (options.usertoken) {
185
+ mod.modResults.push({ type: 'property', key: 'usertoken', value: options.usertoken });
186
+ }
187
+
188
+ return mod;
189
+ });
190
+
191
+ const withMinesecLicenseFile: ConfigPlugin<MinesecPluginOptions> = (config, options) =>
192
+ withAndroidManifest(config, (mod) => {
193
+ const { projectRoot } = mod.modRequest;
194
+ const licenseFileName = options.licenseFileName!;
195
+ const srcPath = path.join(projectRoot, licenseFileName);
196
+ const destDir = path.join(projectRoot, 'android', 'app', 'src', 'main', 'assets');
197
+ const destPath = path.join(destDir, path.basename(licenseFileName));
198
+
199
+ if (fs.existsSync(srcPath)) {
200
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
201
+ fs.copyFileSync(srcPath, destPath);
202
+ } else {
203
+ console.warn(
204
+ `[minesecrn] License file not found: ${srcPath}. Tempatkan file di project root sebelum build.`
205
+ );
206
+ }
207
+
208
+ return mod;
209
+ });
210
+
211
+ /**
212
+ * Expo Config Plugin untuk Minesec Headless SoftPOS SDK.
213
+ *
214
+ * Options (di app.json):
215
+ * enableNfc — tambah NFC permission/feature (default: true). Set false jika konflik dengan lib lain.
216
+ * licenseFileName — nama file lisensi SDK dari project root; dicopy ke android assets saat prebuild.
217
+ * username — Maven username; ditulis ke gradle.properties sebagai "username".
218
+ * usertoken — Maven token; ditulis ke gradle.properties sebagai "usertoken".
219
+ *
220
+ * Untuk production, gunakan ~/.gradle/gradle.properties atau env vars
221
+ * MINESEC_MAVEN_USER / MINESEC_MAVEN_TOKEN daripada menyimpan credentials di app.json.
222
+ */
223
+ const withMinesec: ConfigPlugin<MinesecPluginOptions> = (config, options = {}) => {
224
+ config = withMinesecManifest(config, options);
225
+ config = withMinesecRootGradle(config);
226
+ config = withMinesecAppGradle(config);
227
+
228
+ if (options.username || options.usertoken) {
229
+ config = withMinesecGradleProperties(config, options);
230
+ }
231
+
232
+ if (options.licenseFileName) {
233
+ config = withMinesecLicenseFile(config, options);
234
+ }
235
+
236
+ return config;
237
+ };
238
+
239
+ export default withMinesec;
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["esnext"],
4
+ "target": "ES2019",
5
+ "module": "commonjs",
6
+ "moduleResolution": "node",
7
+ "rootDir": "./src",
8
+ "outDir": "./build",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "types": ["node"]
15
+ },
16
+ "include": ["./src"]
17
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/index.ts"],"version":"5.9.3"}
@@ -0,0 +1,126 @@
1
+ // ─── Amount ───────────────────────────────────────────────────────────────────
2
+
3
+ export type Amount = {
4
+ /** Nilai transaksi dalam string desimal, contoh: "1.00" */
5
+ value: string;
6
+ /** Kode mata uang ISO 4217, contoh: "HKD", "USD", "IDR" */
7
+ currencyCode: string;
8
+ };
9
+
10
+ // ─── Transaction Type ──────────────────────────────────────────────────────────
11
+
12
+ export type TranType = 'SALE' | 'AUTH' | 'REFUND';
13
+
14
+ // ─── CvmSignatureMode ─────────────────────────────────────────────────────────
15
+
16
+ export type CvmSignatureMode = 'ELECTRONIC_SIGNATURE' | 'SIGN_ON_PAPER';
17
+
18
+ // ─── PoiRequest variants ───────────────────────────────────────────────────────
19
+
20
+ /** Memulai transaksi baru dengan NFC tap — membutuhkan UI HeadlessActivity */
21
+ export type PoiRequestActionNew = {
22
+ type: 'ActionNew';
23
+ tranType: TranType;
24
+ amount: Amount;
25
+ /** Profile ID dari Minesec backend untuk routing transaksi */
26
+ profileId: string;
27
+ primaryTid?: string;
28
+ description?: string;
29
+ /** Referensi POS internal untuk rekonsiliasi */
30
+ posReference?: string;
31
+ cvmSignatureMode?: CvmSignatureMode;
32
+ tapToOwnDevice?: boolean;
33
+ installmentPlan?: number;
34
+ extra?: Record<string, string>;
35
+ };
36
+
37
+ /** Void transaksi sebelum settlement — tidak perlu NFC */
38
+ export type PoiRequestActionVoid = {
39
+ type: 'ActionVoid';
40
+ tranId: string;
41
+ };
42
+
43
+ /** Refund tanpa tap ulang — hanya MPGS gateway yang support */
44
+ export type PoiRequestActionLinkedRefund = {
45
+ type: 'ActionLinkedRefund';
46
+ tranId: string;
47
+ /** Jika null, refund penuh */
48
+ amount?: Amount;
49
+ };
50
+
51
+ /** Adjustment jumlah (tip, incremental auth) */
52
+ export type PoiRequestActionAdjust = {
53
+ type: 'ActionAdjust';
54
+ tranId: string;
55
+ /** Total jumlah baru setelah adjustment */
56
+ amount: Amount;
57
+ };
58
+
59
+ /** Capture pre-authorized transaction */
60
+ export type PoiRequestActionAuthComp = {
61
+ type: 'ActionAuthComp';
62
+ tranId: string;
63
+ amount: Amount;
64
+ };
65
+
66
+ export type PoiRequest =
67
+ | PoiRequestActionNew
68
+ | PoiRequestActionVoid
69
+ | PoiRequestActionLinkedRefund
70
+ | PoiRequestActionAdjust
71
+ | PoiRequestActionAuthComp;
72
+
73
+ /** PoiRequest yang bisa digunakan tanpa UI (HeadlessService) */
74
+ export type PoiRequestBackground = Exclude<PoiRequest, PoiRequestActionNew>;
75
+
76
+ // ─── Reference untuk query transaksi ──────────────────────────────────────────
77
+
78
+ export type TransactionReferenceType = 'tranId' | 'posReference';
79
+
80
+ // ─── Result types ─────────────────────────────────────────────────────────────
81
+
82
+ export type MinesecResult<T> =
83
+ | { success: true; value: T }
84
+ | {
85
+ success: false;
86
+ code: number;
87
+ message: string;
88
+ contextual?: string;
89
+ extra?: Record<string, string>;
90
+ };
91
+
92
+ // ─── SDK Init ─────────────────────────────────────────────────────────────────
93
+
94
+ export type SdkInitResult = {
95
+ sdkVersion: string;
96
+ sdkId: string;
97
+ };
98
+
99
+ // ─── Setup Result ──────────────────────────────────────────────────────────────
100
+
101
+ export type SetupResult = {
102
+ sdkRes: MinesecResult<SdkInitResult>;
103
+ emvRes: MinesecResult<unknown>[];
104
+ capkRes: MinesecResult<unknown>[];
105
+ termRes: MinesecResult<unknown>;
106
+ keyRes: MinesecResult<unknown>[];
107
+ };
108
+
109
+ // ─── Transaction ───────────────────────────────────────────────────────────────
110
+
111
+ export type Transaction = {
112
+ id: string;
113
+ status: string | null;
114
+ tranType: string | null;
115
+ amount: Amount | null;
116
+ posReference: string | null;
117
+ approvalCode: string | null;
118
+ /** Metode pembayaran, contoh: "VISA", "MASTERCARD" */
119
+ paymentMethod: string | null;
120
+ /** Nomor kartu yang disamarkan */
121
+ accountMasked: string | null;
122
+ rrn: string | null;
123
+ batchNo: string | null;
124
+ createdAt: string | null;
125
+ updatedAt: string | null;
126
+ };
@@ -0,0 +1,52 @@
1
+ import { NativeModule, requireNativeModule } from 'expo';
2
+
3
+ import type {
4
+ MinesecResult,
5
+ PoiRequest,
6
+ PoiRequestBackground,
7
+ SdkInitResult,
8
+ SetupResult,
9
+ Transaction,
10
+ TransactionReferenceType,
11
+ } from './Minesecrn.types';
12
+
13
+ declare class MinesecrnModule extends NativeModule<Record<string, never>> {
14
+ /**
15
+ * Inisialisasi Minesec SDK. Harus dipanggil setiap kali aplikasi launch.
16
+ * @param licenseFileName Nama file .license di folder assets, contoh: "license.license"
17
+ */
18
+ initSoftPos(licenseFileName: string): Promise<MinesecResult<SdkInitResult>>;
19
+
20
+ /**
21
+ * Setup awal SDK — download EMV params, CAPK, terminal config, dan inject keys.
22
+ * Cukup dipanggil sekali per instalasi.
23
+ * @param withTestCapk Set true untuk development/staging environment
24
+ */
25
+ initialSetup(withTestCapk?: boolean): Promise<SetupResult>;
26
+
27
+ /**
28
+ * Launch HeadlessActivity untuk memproses transaksi dengan UI dan NFC.
29
+ * Mendukung ActionNew, ActionVoid, ActionLinkedRefund, ActionAdjust, ActionAuthComp.
30
+ * @param request PoiRequest object
31
+ */
32
+ launchTransaction(request: PoiRequest): Promise<MinesecResult<Transaction>>;
33
+
34
+ /**
35
+ * Eksekusi aksi background tanpa UI (void, refund, adjust, auth-complete).
36
+ * Gunakan HeadlessService di backend — tidak ada NFC tap.
37
+ * @param request PoiRequest non-ActionNew
38
+ */
39
+ createAction(request: PoiRequestBackground): Promise<MinesecResult<Transaction>>;
40
+
41
+ /**
42
+ * Query transaksi berdasarkan referensi.
43
+ * @param refType 'tranId' (prefix tran_) atau 'posReference'
44
+ * @param refValue Nilai referensi
45
+ */
46
+ getTransaction(
47
+ refType: TransactionReferenceType,
48
+ refValue: string
49
+ ): Promise<MinesecResult<Transaction>>;
50
+ }
51
+
52
+ export default requireNativeModule<MinesecrnModule>('Minesecrn');
@@ -0,0 +1,27 @@
1
+ import { NativeModule, registerWebModule } from 'expo';
2
+
3
+ // Minesec Headless SDK tidak tersedia di platform web atau iOS.
4
+ // Semua method akan throw error jika dipanggil di luar Android.
5
+ class MinesecrnModule extends NativeModule<Record<string, never>> {
6
+ async initSoftPos(_licenseFileName: string): Promise<never> {
7
+ throw new Error('Minesec Headless SDK is only available on Android');
8
+ }
9
+
10
+ async initialSetup(_withTestCapk?: boolean): Promise<never> {
11
+ throw new Error('Minesec Headless SDK is only available on Android');
12
+ }
13
+
14
+ async launchTransaction(_request: unknown): Promise<never> {
15
+ throw new Error('Minesec Headless SDK is only available on Android');
16
+ }
17
+
18
+ async createAction(_request: unknown): Promise<never> {
19
+ throw new Error('Minesec Headless SDK is only available on Android');
20
+ }
21
+
22
+ async getTransaction(_refType: string, _refValue: string): Promise<never> {
23
+ throw new Error('Minesec Headless SDK is only available on Android');
24
+ }
25
+ }
26
+
27
+ export default registerWebModule(MinesecrnModule, 'Minesecrn');
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default } from './MinesecrnModule';
2
+ export * from './Minesecrn.types';