@markwharton/pwa-core 1.0.1 → 1.2.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.
@@ -1,3 +1,4 @@
1
+ import { Result } from '../types';
1
2
  /**
2
3
  * API Key utilities for machine-to-machine authentication
3
4
  */
@@ -16,8 +17,10 @@ export declare function extractApiKey(request: {
16
17
  export declare function hashApiKey(apiKey: string): string;
17
18
  /**
18
19
  * Validate API key against stored hash
20
+ *
21
+ * @returns Result indicating success or failure with error message
19
22
  */
20
- export declare function validateApiKey(apiKey: string, storedHash: string): boolean;
23
+ export declare function validateApiKey(apiKey: string, storedHash: string): Result<void>;
21
24
  /**
22
25
  * Generate a new API key (random 32-byte hex string)
23
26
  */
@@ -5,6 +5,7 @@ exports.hashApiKey = hashApiKey;
5
5
  exports.validateApiKey = validateApiKey;
6
6
  exports.generateApiKey = generateApiKey;
7
7
  const crypto_1 = require("crypto");
8
+ const types_1 = require("../types");
8
9
  /**
9
10
  * API Key utilities for machine-to-machine authentication
10
11
  */
@@ -23,10 +24,15 @@ function hashApiKey(apiKey) {
23
24
  }
24
25
  /**
25
26
  * Validate API key against stored hash
27
+ *
28
+ * @returns Result indicating success or failure with error message
26
29
  */
27
30
  function validateApiKey(apiKey, storedHash) {
28
31
  const keyHash = hashApiKey(apiKey);
29
- return keyHash === storedHash;
32
+ if (keyHash === storedHash) {
33
+ return (0, types_1.okVoid)();
34
+ }
35
+ return (0, types_1.err)('Invalid API key');
30
36
  }
31
37
  /**
32
38
  * Generate a new API key (random 32-byte hex string)
@@ -1,3 +1,4 @@
1
+ import { Result } from '../types';
1
2
  /**
2
3
  * Initialize JWT secret - call once at startup
3
4
  * Fails fast if secret is missing or too short
@@ -14,8 +15,10 @@ export declare function extractToken(authHeader: string | null): string | null;
14
15
  /**
15
16
  * Validate and decode a JWT token
16
17
  * Generic type allows project-specific payload shapes
18
+ *
19
+ * @returns Result with decoded payload or error message
17
20
  */
18
- export declare function validateToken<T extends object>(token: string): T | null;
21
+ export declare function validateToken<T extends object>(token: string): Result<T>;
19
22
  /**
20
23
  * Generate a JWT token with custom payload
21
24
  */
@@ -10,6 +10,7 @@ exports.validateToken = validateToken;
10
10
  exports.generateToken = generateToken;
11
11
  exports.generateLongLivedToken = generateLongLivedToken;
12
12
  const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
13
+ const types_1 = require("../types");
13
14
  /**
14
15
  * JWT token utilities - works with any payload structure
15
16
  * Use BaseJwtPayload or extend it for type safety
@@ -46,17 +47,20 @@ function extractToken(authHeader) {
46
47
  /**
47
48
  * Validate and decode a JWT token
48
49
  * Generic type allows project-specific payload shapes
50
+ *
51
+ * @returns Result with decoded payload or error message
49
52
  */
50
53
  function validateToken(token) {
51
54
  try {
52
55
  const payload = jsonwebtoken_1.default.verify(token, getJwtSecret());
53
56
  if (typeof payload === 'object' && payload !== null) {
54
- return payload;
57
+ return (0, types_1.ok)(payload);
55
58
  }
56
- return null;
59
+ return (0, types_1.err)('Invalid token payload');
57
60
  }
58
- catch {
59
- return null;
61
+ catch (error) {
62
+ const message = error instanceof Error ? error.message : 'Token validation failed';
63
+ return (0, types_1.err)(message);
60
64
  }
61
65
  }
62
66
  /**
@@ -32,5 +32,6 @@ export declare function apiPatch<T>(url: string, body?: unknown): Promise<T>;
32
32
  export declare function apiDelete<T>(url: string): Promise<T>;
33
33
  /**
34
34
  * Alternative: Response wrapper style (like financial-tracker's authJsonFetch)
35
+ * Preserves actual HTTP status code on success
35
36
  */
36
37
  export declare function apiCallSafe<T>(url: string, options?: RequestInit): Promise<ApiResponse<T>>;
@@ -101,16 +101,42 @@ async function apiDelete(url) {
101
101
  }
102
102
  /**
103
103
  * Alternative: Response wrapper style (like financial-tracker's authJsonFetch)
104
+ * Preserves actual HTTP status code on success
104
105
  */
105
106
  async function apiCallSafe(url, options = {}) {
106
- try {
107
- const data = await apiCall(url, options);
108
- return { ok: true, status: 200, data };
107
+ const token = getToken?.();
108
+ const headers = {
109
+ 'Content-Type': 'application/json',
110
+ ...options.headers
111
+ };
112
+ if (token) {
113
+ headers['Authorization'] = `Bearer ${token}`;
109
114
  }
110
- catch (error) {
111
- if (error instanceof apiError_1.ApiError) {
112
- return { ok: false, status: error.status, error: error.message };
115
+ try {
116
+ const response = await fetch(url, {
117
+ ...options,
118
+ headers
119
+ });
120
+ if (!response.ok) {
121
+ if (response.status === 401 && onUnauthorized) {
122
+ onUnauthorized();
123
+ }
124
+ let errorMessage = 'Request failed';
125
+ try {
126
+ const errorData = (await response.json());
127
+ errorMessage = errorData.error || errorMessage;
128
+ }
129
+ catch {
130
+ // Ignore JSON parse errors
131
+ }
132
+ return { ok: false, status: response.status, error: errorMessage };
113
133
  }
134
+ // Handle empty responses
135
+ const text = await response.text();
136
+ const data = text ? JSON.parse(text) : undefined;
137
+ return { ok: true, status: response.status, data };
138
+ }
139
+ catch {
114
140
  return { ok: false, status: 0, error: 'Network error' };
115
141
  }
116
142
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './types';
1
2
  export * from './auth';
2
3
  export * from './http';
3
4
  export * from './storage';
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  // Main entry point - re-export everything
18
+ __exportStar(require("./types"), exports);
18
19
  __exportStar(require("./auth"), exports);
19
20
  __exportStar(require("./http"), exports);
20
21
  __exportStar(require("./storage"), exports);
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Shared types for pwa-core
3
+ */
4
+ /**
5
+ * Standard result type for operations that can fail.
6
+ * Used consistently across all modules (auth, push, client).
7
+ *
8
+ * @example
9
+ * // Success
10
+ * { ok: true, data: user }
11
+ *
12
+ * // Failure
13
+ * { ok: false, error: 'Token expired' }
14
+ *
15
+ * // With status code (HTTP/push operations)
16
+ * { ok: false, error: 'Subscription expired', statusCode: 410 }
17
+ */
18
+ export interface Result<T> {
19
+ ok: boolean;
20
+ data?: T;
21
+ error?: string;
22
+ statusCode?: number;
23
+ }
24
+ /**
25
+ * Helper to create a success result
26
+ */
27
+ export declare function ok<T>(data: T): Result<T>;
28
+ /**
29
+ * Helper to create a success result with no data
30
+ */
31
+ export declare function okVoid(): Result<void>;
32
+ /**
33
+ * Helper to create a failure result
34
+ */
35
+ export declare function err<T>(error: string, statusCode?: number): Result<T>;
package/dist/types.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * Shared types for pwa-core
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ok = ok;
7
+ exports.okVoid = okVoid;
8
+ exports.err = err;
9
+ /**
10
+ * Helper to create a success result
11
+ */
12
+ function ok(data) {
13
+ return { ok: true, data };
14
+ }
15
+ /**
16
+ * Helper to create a success result with no data
17
+ */
18
+ function okVoid() {
19
+ return { ok: true };
20
+ }
21
+ /**
22
+ * Helper to create a failure result
23
+ */
24
+ function err(error, statusCode) {
25
+ return statusCode !== undefined
26
+ ? { ok: false, error, statusCode }
27
+ : { ok: false, error };
28
+ }
package/package.json CHANGED
@@ -1,16 +1,36 @@
1
1
  {
2
2
  "name": "@markwharton/pwa-core",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "description": "Shared patterns for Azure PWA projects",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
8
8
  ".": "./dist/index.js",
9
+ "./types": "./dist/types.js",
9
10
  "./auth": "./dist/auth/index.js",
10
11
  "./http": "./dist/http/index.js",
11
12
  "./storage": "./dist/storage/index.js",
12
13
  "./client": "./dist/client/index.js"
13
14
  },
15
+ "typesVersions": {
16
+ "*": {
17
+ "types": [
18
+ "dist/types.d.ts"
19
+ ],
20
+ "auth": [
21
+ "dist/auth/index.d.ts"
22
+ ],
23
+ "http": [
24
+ "dist/http/index.d.ts"
25
+ ],
26
+ "storage": [
27
+ "dist/storage/index.d.ts"
28
+ ],
29
+ "client": [
30
+ "dist/client/index.d.ts"
31
+ ]
32
+ }
33
+ },
14
34
  "scripts": {
15
35
  "build": "tsc",
16
36
  "clean": "rm -rf dist"
@@ -34,7 +54,7 @@
34
54
  ],
35
55
  "repository": {
36
56
  "type": "git",
37
- "url": "https://github.com/MarkWharton/pwa-packages.git",
57
+ "url": "git+https://github.com/MarkWharton/pwa-packages.git",
38
58
  "directory": "packages/core"
39
59
  },
40
60
  "author": "Mark Wharton",
@@ -1,8 +0,0 @@
1
- /**
2
- * Generate a unique row key from an identifier string
3
- * Uses SHA-256 hash for consistent, URL-safe keys
4
- *
5
- * @param identifier - The string to hash (e.g., subscription endpoint, user ID)
6
- * @returns A 32-character hex string suitable for Azure Table Storage row keys
7
- */
8
- export declare function generateRowKey(identifier: string): string;
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateRowKey = generateRowKey;
4
- const crypto_1 = require("crypto");
5
- /**
6
- * Generate a unique row key from an identifier string
7
- * Uses SHA-256 hash for consistent, URL-safe keys
8
- *
9
- * @param identifier - The string to hash (e.g., subscription endpoint, user ID)
10
- * @returns A 32-character hex string suitable for Azure Table Storage row keys
11
- */
12
- function generateRowKey(identifier) {
13
- return (0, crypto_1.createHash)('sha256').update(identifier).digest('hex').substring(0, 32);
14
- }
File without changes
File without changes