@medipass/checkout-sdk 3.1.0 → 3.3.0-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medipass/checkout-sdk",
3
- "version": "3.1.0",
3
+ "version": "3.3.0-beta.7",
4
4
  "description": "Medipass Checkout SDK",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -11,11 +11,12 @@
11
11
  "develop": "nodemon -w src -x 'yarn build'",
12
12
  "lint": "eslint \"**/*.{ts,tsx}\"",
13
13
  "lint:fix": "eslint \"**/*.{ts,tsx}\" --fix",
14
- "prepublishOnly": "yarn build"
14
+ "prepublishOnly": "yarn build",
15
+ "release": "node scripts/release.mjs"
15
16
  },
16
17
  "dependencies": {
17
- "@medipass/utils": "11.80.7",
18
- "@medipass/web-sdk": "11.64.8"
18
+ "@medipass/utils": "11.88.0",
19
+ "@medipass/web-sdk": "12.5.1"
19
20
  },
20
21
  "devDependencies": {
21
22
  "@rollup/plugin-commonjs": "25.0.3",
@@ -0,0 +1,285 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-undef */
3
+
4
+ import { execSync } from 'child_process';
5
+ import { readFileSync, writeFileSync } from 'fs';
6
+ import * as readline from 'readline';
7
+
8
+ const args = process.argv.slice(2);
9
+ const dryRun = args.includes('--dry-run');
10
+
11
+ const rl = readline.createInterface({
12
+ input: process.stdin,
13
+ output: process.stdout,
14
+ });
15
+
16
+ const question = prompt => new Promise(resolve => rl.question(prompt, resolve));
17
+
18
+ const exec = (cmd, options = {}) => {
19
+ if (dryRun) {
20
+ console.log(`\n[DRY RUN] Would execute: ${cmd}`);
21
+ return;
22
+ }
23
+ console.log(`\n> ${cmd}`);
24
+ return execSync(cmd, { stdio: 'inherit', ...options });
25
+ };
26
+
27
+ const execOutput = cmd => execSync(cmd, { encoding: 'utf-8' }).trim();
28
+
29
+ const getCurrentBranch = () => execOutput('git rev-parse --abbrev-ref HEAD');
30
+
31
+ const getPackageJson = () => {
32
+ const content = readFileSync('package.json', 'utf-8');
33
+ return JSON.parse(content);
34
+ };
35
+
36
+ const writePackageJson = pkg => {
37
+ writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
38
+ };
39
+
40
+ const parseVersion = version => {
41
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-([a-z]+)\.(\d+))?$/);
42
+ if (!match) throw new Error(`Invalid version format: ${version}`);
43
+ return {
44
+ major: parseInt(match[1]),
45
+ minor: parseInt(match[2]),
46
+ patch: parseInt(match[3]),
47
+ preId: match[4] || null,
48
+ preNum: match[5] ? parseInt(match[5]) : null,
49
+ };
50
+ };
51
+
52
+ const formatVersion = ({ major, minor, patch, preId, preNum }) => {
53
+ const base = `${major}.${minor}.${patch}`;
54
+ return preId ? `${base}-${preId}.${preNum}` : base;
55
+ };
56
+
57
+ const bumpVersion = (currentVersion, releaseType, preId = 'beta', preTarget = 'patch') => {
58
+ const v = parseVersion(currentVersion);
59
+
60
+ switch (releaseType) {
61
+ case 'major':
62
+ // If current is a pre-release for a major bump, graduate it
63
+ if (v.preId && v.minor === 0 && v.patch === 0) {
64
+ return formatVersion({ major: v.major, minor: 0, patch: 0, preId: null, preNum: null });
65
+ }
66
+ return formatVersion({ major: v.major + 1, minor: 0, patch: 0, preId: null, preNum: null });
67
+ case 'minor':
68
+ // If current is a pre-release for a minor bump, graduate it
69
+ if (v.preId && v.patch === 0) {
70
+ return formatVersion({ major: v.major, minor: v.minor, patch: 0, preId: null, preNum: null });
71
+ }
72
+ return formatVersion({ major: v.major, minor: v.minor + 1, patch: 0, preId: null, preNum: null });
73
+ case 'patch':
74
+ // If current is a pre-release, graduate it to stable (strip the pre-release suffix)
75
+ if (v.preId) {
76
+ return formatVersion({ major: v.major, minor: v.minor, patch: v.patch, preId: null, preNum: null });
77
+ }
78
+ return formatVersion({ major: v.major, minor: v.minor, patch: v.patch + 1, preId: null, preNum: null });
79
+ case 'pre':
80
+ // If already a pre-release, just bump the pre-release number
81
+ if (v.preId) {
82
+ return formatVersion({ ...v, preNum: v.preNum + 1 });
83
+ }
84
+ // Otherwise, bump based on preTarget and add pre-release suffix
85
+ switch (preTarget) {
86
+ case 'major':
87
+ return formatVersion({ major: v.major + 1, minor: 0, patch: 0, preId, preNum: 0 });
88
+ case 'minor':
89
+ return formatVersion({ major: v.major, minor: v.minor + 1, patch: 0, preId, preNum: 0 });
90
+ case 'patch':
91
+ default:
92
+ return formatVersion({ major: v.major, minor: v.minor, patch: v.patch + 1, preId, preNum: 0 });
93
+ }
94
+ default:
95
+ throw new Error(`Unknown release type: ${releaseType}`);
96
+ }
97
+ };
98
+
99
+ const hasUncommittedChanges = () => {
100
+ try {
101
+ const status = execOutput('git status --porcelain');
102
+ return status.length > 0;
103
+ } catch {
104
+ return false;
105
+ }
106
+ };
107
+
108
+ const checkNpmPublishAccess = () => {
109
+ try {
110
+ execSync(`npm publish --dry-run --ignore-scripts 2>&1`, { encoding: 'utf-8' });
111
+ return { ok: true };
112
+ } catch (err) {
113
+ const output = err.stdout || err.stderr || err.message || '';
114
+ if (output.includes('ENEEDAUTH') || output.includes('need auth')) {
115
+ return { ok: false, reason: 'not-authenticated' };
116
+ }
117
+ if (output.includes('403') || output.includes('not authorized')) {
118
+ return { ok: false, reason: 'no-access' };
119
+ }
120
+ // Other errors (like "already exists") mean auth is fine
121
+ if (output.includes('already exists') || output.includes('EPUBLISHCONFLICT')) {
122
+ return { ok: true };
123
+ }
124
+ return { ok: false, reason: 'unknown', message: output };
125
+ }
126
+ };
127
+
128
+ const main = async () => {
129
+ console.log('\n📦 Release CLI for @medipass/checkout-sdk\n');
130
+
131
+ if (dryRun) {
132
+ console.log('🧪 DRY RUN MODE - No changes will be made\n');
133
+ }
134
+
135
+ const currentBranch = getCurrentBranch();
136
+ const pkg = getPackageJson();
137
+ const currentVersion = pkg.version;
138
+
139
+ console.log(`Current branch: ${currentBranch}`);
140
+ console.log(`Current version: ${currentVersion}\n`);
141
+
142
+ if (hasUncommittedChanges()) {
143
+ console.error('Error: You have uncommitted changes. Please commit or stash them first.');
144
+ process.exit(1);
145
+ }
146
+
147
+ console.log('Release types:');
148
+ console.log(' 1. pre - Pre-release (e.g., 3.2.1-beta.0) - feature branch only');
149
+ console.log(' 2. patch - Patch release (e.g., 3.2.1) - master branch only');
150
+ console.log(' 3. minor - Minor release (e.g., 3.3.0) - master branch only');
151
+ console.log(' 4. major - Major release (e.g., 4.0.0) - master branch only');
152
+ console.log('');
153
+
154
+ const typeChoice = await question('Select release type (1-4): ');
155
+ const releaseTypes = { 1: 'pre', 2: 'patch', 3: 'minor', 4: 'major' };
156
+ const releaseType = releaseTypes[typeChoice];
157
+
158
+ if (!releaseType) {
159
+ console.error('Invalid selection.');
160
+ process.exit(1);
161
+ }
162
+
163
+ if (releaseType === 'pre') {
164
+ if (currentBranch === 'master') {
165
+ console.error('\nError: Pre-releases must be done on a feature branch, not master.');
166
+ process.exit(1);
167
+ }
168
+ } else {
169
+ if (currentBranch !== 'master') {
170
+ console.error(`\nError: ${releaseType} releases must be done on the master branch.`);
171
+ console.error(`Current branch: ${currentBranch}`);
172
+ console.error('Please checkout master and merge your changes first.');
173
+ process.exit(1);
174
+ }
175
+ }
176
+
177
+ let preId = 'beta';
178
+ let preTarget = 'patch';
179
+ if (releaseType === 'pre') {
180
+ const parsed = parseVersion(currentVersion);
181
+
182
+ // Only ask for target if not already a pre-release
183
+ if (!parsed.preId) {
184
+ console.log('\nPre-release target version:');
185
+ console.log(' 1. patch (e.g., 3.2.0 -> 3.2.1-beta.0)');
186
+ console.log(' 2. minor (e.g., 3.2.0 -> 3.3.0-beta.0)');
187
+ console.log(' 3. major (e.g., 3.2.0 -> 4.0.0-beta.0)');
188
+ const targetChoice = await question('Select target (1-3, default: 1): ');
189
+ const targets = { 1: 'patch', 2: 'minor', 3: 'major' };
190
+ preTarget = targets[targetChoice] || 'patch';
191
+ }
192
+
193
+ const customPreId = await question('Pre-release identifier (default: beta): ');
194
+ if (customPreId.trim()) {
195
+ preId = customPreId.trim().toLowerCase();
196
+ }
197
+ }
198
+
199
+ const newVersion = bumpVersion(currentVersion, releaseType, preId, preTarget);
200
+
201
+ console.log(`\nVersion bump: ${currentVersion} -> ${newVersion}`);
202
+ const confirm = await question('Proceed? (y/n): ');
203
+
204
+ if (confirm.toLowerCase() !== 'y') {
205
+ console.log('Aborted.');
206
+ process.exit(0);
207
+ }
208
+
209
+ console.log('\n--- Building (pre-publish check) ---');
210
+ exec('yarn build');
211
+
212
+ console.log('\n--- Checking NPM publish access ---');
213
+ if (!dryRun) {
214
+ const access = checkNpmPublishAccess();
215
+ if (!access.ok) {
216
+ if (access.reason === 'not-authenticated') {
217
+ console.error('Error: You are not logged in to NPM.');
218
+ console.error('Please run: npm login');
219
+ } else if (access.reason === 'no-access') {
220
+ console.error(`Error: You don't have publish access to ${pkg.name}.`);
221
+ console.error('Please contact the package owner to grant you access.');
222
+ } else {
223
+ console.error('Error: NPM publish check failed.');
224
+ if (access.message) console.error(access.message);
225
+ }
226
+ process.exit(1);
227
+ }
228
+ console.log('NPM publish access: OK');
229
+ } else {
230
+ console.log('[DRY RUN] Skipping NPM publish access check');
231
+ }
232
+
233
+ console.log('\n--- Updating version ---');
234
+ if (dryRun) {
235
+ console.log(`[DRY RUN] Would update package.json to version ${newVersion}`);
236
+ } else {
237
+ pkg.version = newVersion;
238
+ writePackageJson(pkg);
239
+ console.log(`Updated package.json to version ${newVersion}`);
240
+ }
241
+
242
+ console.log('\n--- Rebuilding with new version ---');
243
+ exec('yarn build');
244
+
245
+ console.log('\n--- Committing version bump ---');
246
+ exec('git add package.json');
247
+ exec(`git commit -m "${newVersion}"`);
248
+
249
+ console.log('\n--- Creating git tag ---');
250
+ const tagName = `v${newVersion}`;
251
+ exec(`git tag ${tagName}`);
252
+ console.log(`Created tag: ${tagName}`);
253
+
254
+ console.log('\n--- Publishing to NPM ---');
255
+ const otp = await question('Enter OTP code (or press Enter if 2FA not enabled): ');
256
+ const otpFlag = otp.trim() ? ` --otp=${otp.trim()}` : '';
257
+
258
+ if (releaseType === 'pre') {
259
+ exec(`npm publish --tag next --ignore-scripts${otpFlag}`);
260
+ } else {
261
+ exec(`npm publish --ignore-scripts${otpFlag}`);
262
+ }
263
+
264
+ const pushConfirm = await question('\nPush commit and tag to remote? (y/n): ');
265
+ if (pushConfirm.toLowerCase() === 'y') {
266
+ exec('git push');
267
+ exec(`git push origin ${tagName}`);
268
+ console.log('\nPushed to remote.');
269
+ }
270
+
271
+ console.log(`\n✅ Successfully released ${newVersion}`);
272
+ console.log(` Tag: ${tagName}`);
273
+ if (releaseType === 'pre') {
274
+ console.log(' NPM tag: next');
275
+ console.log(` Install with: npm install @medipass/checkout-sdk@next`);
276
+ }
277
+
278
+ rl.close();
279
+ };
280
+
281
+ main().catch(err => {
282
+ console.error('\nError:', err.message);
283
+ rl.close();
284
+ process.exit(1);
285
+ });
package/src/constants.ts CHANGED
@@ -18,6 +18,7 @@ export const EVENTS = {
18
18
  SUCCESS: 'success',
19
19
  fAILURE: 'failure',
20
20
  CANCEL: 'cancel',
21
+ EXPIRED: 'expired',
21
22
  } as const;
22
23
 
23
24
  export const ERROR_MESSAGES = {
package/src/index.ts CHANGED
@@ -19,12 +19,14 @@ interface CheckoutSdk {
19
19
  onSuccess: ((args: { transactionId: string }) => void) | null;
20
20
  onFailure: ((args: { transactionId: string }) => void) | null;
21
21
  onCancel: ((args: { transactionId: string }) => void) | null;
22
+ onExpired: ((args: { transactionId: string }) => void) | null;
22
23
  onClose: (() => void) | null;
23
24
  init: (args: {
24
25
  env: typeof ENVS[keyof typeof ENVS];
25
26
  onSuccess: (args: { transactionId: string }) => void;
26
27
  onFailure: (args: { transactionId: string }) => void;
27
28
  onCancel: (args: { transactionId: string }) => void;
29
+ onExpired: (args: { transactionId: string }) => void;
28
30
  onClose: () => void;
29
31
  }) => void;
30
32
  createCheckout: (args: { paymentRequestUrl: string }) => void;
@@ -39,15 +41,17 @@ const checkoutSDK: CheckoutSdk = {
39
41
  onSuccess: null,
40
42
  onFailure: null,
41
43
  onCancel: null,
44
+ onExpired: null,
42
45
  onClose: null,
43
46
 
44
- init({ env, onSuccess, onFailure, onCancel, onClose }) {
47
+ init({ env, onSuccess, onFailure, onCancel, onExpired, onClose }) {
45
48
  if (!env) return;
46
49
 
47
50
  this.env = env;
48
51
  this.onSuccess = onSuccess;
49
52
  this.onFailure = onFailure;
50
53
  this.onCancel = onCancel;
54
+ this.onExpired = onExpired;
51
55
  this.onClose = onClose;
52
56
 
53
57
  // Open a blank window
@@ -102,6 +106,7 @@ const checkoutSDK: CheckoutSdk = {
102
106
  const onSuccess = this.onSuccess;
103
107
  const onFailure = this.onFailure;
104
108
  const onCancel = this.onCancel;
109
+ const onExpired = this.onExpired;
105
110
  const onClose = this.onClose;
106
111
 
107
112
  ////////////////////////////////////////////////////////////
@@ -186,6 +191,17 @@ const checkoutSDK: CheckoutSdk = {
186
191
  }, 1500);
187
192
  return transactionId;
188
193
  }
194
+
195
+ if (event === EVENTS.EXPIRED) {
196
+ // Give 1.5 seconds for the user to see the expired page before auto-closing the pop-up.
197
+ setTimeout(() => {
198
+ onExpired && onExpired({ transactionId });
199
+ if (_windowReferenceObject) {
200
+ _windowReferenceObject.close();
201
+ }
202
+ }, 1500);
203
+ return transactionId;
204
+ }
189
205
  };
190
206
 
191
207
  return _windowReferenceObject;