@markwharton/pwa-core 1.1.0 → 1.2.1
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/dist/__tests__/auth/apiKey.test.d.ts +1 -0
- package/dist/__tests__/auth/apiKey.test.js +80 -0
- package/dist/__tests__/auth/token.test.d.ts +1 -0
- package/dist/__tests__/auth/token.test.js +189 -0
- package/dist/__tests__/auth/types.test.d.ts +1 -0
- package/dist/__tests__/auth/types.test.js +77 -0
- package/dist/__tests__/client/api.test.d.ts +1 -0
- package/dist/__tests__/client/api.test.js +269 -0
- package/dist/__tests__/client/apiError.test.d.ts +1 -0
- package/dist/__tests__/client/apiError.test.js +58 -0
- package/dist/__tests__/http/responses.test.d.ts +1 -0
- package/dist/__tests__/http/responses.test.js +112 -0
- package/dist/__tests__/http/status.test.d.ts +1 -0
- package/dist/__tests__/http/status.test.js +27 -0
- package/dist/__tests__/storage/client.test.d.ts +1 -0
- package/dist/__tests__/storage/client.test.js +173 -0
- package/dist/__tests__/storage/keys.test.d.ts +1 -0
- package/dist/__tests__/storage/keys.test.js +47 -0
- package/dist/__tests__/types.test.d.ts +1 -0
- package/dist/__tests__/types.test.js +56 -0
- package/dist/auth/apiKey.d.ts +24 -7
- package/dist/auth/apiKey.js +24 -7
- package/dist/auth/token.d.ts +37 -10
- package/dist/auth/token.js +37 -10
- package/dist/auth/types.d.ts +21 -3
- package/dist/auth/types.js +21 -3
- package/dist/client/api.d.ts +70 -9
- package/dist/client/api.js +70 -9
- package/dist/client/apiError.d.ts +22 -5
- package/dist/client/apiError.js +22 -5
- package/dist/http/responses.d.ts +57 -8
- package/dist/http/responses.js +57 -8
- package/dist/storage/client.d.ts +29 -6
- package/dist/storage/client.js +29 -6
- package/dist/types.d.ts +16 -3
- package/dist/types.js +16 -3
- package/package.json +22 -2
package/dist/http/responses.js
CHANGED
|
@@ -10,7 +10,11 @@ exports.isNotFoundError = isNotFoundError;
|
|
|
10
10
|
exports.isConflictError = isConflictError;
|
|
11
11
|
const status_1 = require("./status");
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Creates a 400 Bad Request response.
|
|
14
|
+
* @param message - The error message to return
|
|
15
|
+
* @returns Azure Functions HttpResponseInit object
|
|
16
|
+
* @example
|
|
17
|
+
* if (!body.email) return badRequestResponse('Email is required');
|
|
14
18
|
*/
|
|
15
19
|
function badRequestResponse(message) {
|
|
16
20
|
return {
|
|
@@ -19,7 +23,11 @@ function badRequestResponse(message) {
|
|
|
19
23
|
};
|
|
20
24
|
}
|
|
21
25
|
/**
|
|
22
|
-
*
|
|
26
|
+
* Creates a 401 Unauthorized response.
|
|
27
|
+
* @param message - The error message (default: 'Unauthorized')
|
|
28
|
+
* @returns Azure Functions HttpResponseInit object
|
|
29
|
+
* @example
|
|
30
|
+
* if (!token) return unauthorizedResponse();
|
|
23
31
|
*/
|
|
24
32
|
function unauthorizedResponse(message = 'Unauthorized') {
|
|
25
33
|
return {
|
|
@@ -28,7 +36,11 @@ function unauthorizedResponse(message = 'Unauthorized') {
|
|
|
28
36
|
};
|
|
29
37
|
}
|
|
30
38
|
/**
|
|
31
|
-
*
|
|
39
|
+
* Creates a 403 Forbidden response.
|
|
40
|
+
* @param message - The error message (default: 'Forbidden')
|
|
41
|
+
* @returns Azure Functions HttpResponseInit object
|
|
42
|
+
* @example
|
|
43
|
+
* if (!isAdmin(payload)) return forbiddenResponse('Admin access required');
|
|
32
44
|
*/
|
|
33
45
|
function forbiddenResponse(message = 'Forbidden') {
|
|
34
46
|
return {
|
|
@@ -37,7 +49,12 @@ function forbiddenResponse(message = 'Forbidden') {
|
|
|
37
49
|
};
|
|
38
50
|
}
|
|
39
51
|
/**
|
|
40
|
-
*
|
|
52
|
+
* Creates a 404 Not Found response.
|
|
53
|
+
* @param resource - The name of the resource that wasn't found
|
|
54
|
+
* @returns Azure Functions HttpResponseInit object
|
|
55
|
+
* @example
|
|
56
|
+
* if (!user) return notFoundResponse('User');
|
|
57
|
+
* // Returns: { error: 'User not found' }
|
|
41
58
|
*/
|
|
42
59
|
function notFoundResponse(resource) {
|
|
43
60
|
return {
|
|
@@ -46,7 +63,11 @@ function notFoundResponse(resource) {
|
|
|
46
63
|
};
|
|
47
64
|
}
|
|
48
65
|
/**
|
|
49
|
-
*
|
|
66
|
+
* Creates a 409 Conflict response.
|
|
67
|
+
* @param message - The conflict error message
|
|
68
|
+
* @returns Azure Functions HttpResponseInit object
|
|
69
|
+
* @example
|
|
70
|
+
* if (existingUser) return conflictResponse('Email already registered');
|
|
50
71
|
*/
|
|
51
72
|
function conflictResponse(message) {
|
|
52
73
|
return {
|
|
@@ -55,7 +76,17 @@ function conflictResponse(message) {
|
|
|
55
76
|
};
|
|
56
77
|
}
|
|
57
78
|
/**
|
|
58
|
-
*
|
|
79
|
+
* Handles unexpected errors safely by logging details and returning a generic message.
|
|
80
|
+
* Use in catch blocks to avoid exposing internal error details to clients.
|
|
81
|
+
* @param error - The caught error
|
|
82
|
+
* @param context - Azure Functions InvocationContext for logging
|
|
83
|
+
* @returns Azure Functions HttpResponseInit with 500 status
|
|
84
|
+
* @example
|
|
85
|
+
* try {
|
|
86
|
+
* await riskyOperation();
|
|
87
|
+
* } catch (error) {
|
|
88
|
+
* return handleFunctionError(error, context);
|
|
89
|
+
* }
|
|
59
90
|
*/
|
|
60
91
|
function handleFunctionError(error, context) {
|
|
61
92
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
@@ -66,7 +97,16 @@ function handleFunctionError(error, context) {
|
|
|
66
97
|
};
|
|
67
98
|
}
|
|
68
99
|
/**
|
|
69
|
-
*
|
|
100
|
+
* Checks if an error is an Azure Table Storage "not found" error.
|
|
101
|
+
* @param error - The caught error
|
|
102
|
+
* @returns True if error has statusCode 404
|
|
103
|
+
* @example
|
|
104
|
+
* try {
|
|
105
|
+
* await tableClient.getEntity(pk, rk);
|
|
106
|
+
* } catch (error) {
|
|
107
|
+
* if (isNotFoundError(error)) return notFoundResponse('Entity');
|
|
108
|
+
* throw error;
|
|
109
|
+
* }
|
|
70
110
|
*/
|
|
71
111
|
function isNotFoundError(error) {
|
|
72
112
|
return (error instanceof Error &&
|
|
@@ -74,7 +114,16 @@ function isNotFoundError(error) {
|
|
|
74
114
|
error.statusCode === 404);
|
|
75
115
|
}
|
|
76
116
|
/**
|
|
77
|
-
*
|
|
117
|
+
* Checks if an error is an Azure Table Storage "conflict" error.
|
|
118
|
+
* @param error - The caught error
|
|
119
|
+
* @returns True if error has statusCode 409
|
|
120
|
+
* @example
|
|
121
|
+
* try {
|
|
122
|
+
* await tableClient.createEntity(entity);
|
|
123
|
+
* } catch (error) {
|
|
124
|
+
* if (isConflictError(error)) return conflictResponse('Entity already exists');
|
|
125
|
+
* throw error;
|
|
126
|
+
* }
|
|
78
127
|
*/
|
|
79
128
|
function isConflictError(error) {
|
|
80
129
|
return (error instanceof Error &&
|
package/dist/storage/client.d.ts
CHANGED
|
@@ -1,25 +1,48 @@
|
|
|
1
1
|
import { TableClient } from '@azure/data-tables';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Initializes Azure Table Storage configuration. Call once at application startup.
|
|
4
|
+
* @param config - Storage configuration options
|
|
5
|
+
* @param config.accountName - Azure Storage account name (for managed identity)
|
|
6
|
+
* @param config.connectionString - Connection string (for local development)
|
|
7
|
+
* @example
|
|
8
|
+
* // Production (Azure with managed identity)
|
|
9
|
+
* initStorage({ accountName: 'mystorageaccount' });
|
|
10
|
+
*
|
|
11
|
+
* // Local development (Azurite)
|
|
12
|
+
* initStorage({ connectionString: 'UseDevelopmentStorage=true' });
|
|
4
13
|
*/
|
|
5
14
|
export declare function initStorage(config: {
|
|
6
15
|
accountName?: string;
|
|
7
16
|
connectionString?: string;
|
|
8
17
|
}): void;
|
|
9
18
|
/**
|
|
10
|
-
*
|
|
19
|
+
* Initializes storage from environment variables.
|
|
20
|
+
* Reads STORAGE_ACCOUNT_NAME and AzureWebJobsStorage.
|
|
21
|
+
* @example
|
|
22
|
+
* initStorageFromEnv(); // Uses process.env automatically
|
|
11
23
|
*/
|
|
12
24
|
export declare function initStorageFromEnv(): void;
|
|
13
25
|
/**
|
|
14
|
-
*
|
|
26
|
+
* Checks if using Azure managed identity vs local connection string.
|
|
27
|
+
* @returns True if using managed identity (production), false for connection string (local)
|
|
15
28
|
*/
|
|
16
29
|
export declare function useManagedIdentity(): boolean;
|
|
17
30
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
31
|
+
* Gets a TableClient for the specified table, creating the table if needed.
|
|
32
|
+
* Clients are cached for reuse across requests.
|
|
33
|
+
* @param tableName - The Azure Table Storage table name
|
|
34
|
+
* @returns A configured TableClient instance
|
|
35
|
+
* @throws Error if storage is not configured
|
|
36
|
+
* @example
|
|
37
|
+
* const client = await getTableClient('users');
|
|
38
|
+
* await client.createEntity({ partitionKey: 'pk', rowKey: 'rk', name: 'John' });
|
|
20
39
|
*/
|
|
21
40
|
export declare function getTableClient(tableName: string): Promise<TableClient>;
|
|
22
41
|
/**
|
|
23
|
-
*
|
|
42
|
+
* Clears the TableClient cache. Primarily useful for testing.
|
|
43
|
+
* @example
|
|
44
|
+
* afterEach(() => {
|
|
45
|
+
* clearTableClientCache();
|
|
46
|
+
* });
|
|
24
47
|
*/
|
|
25
48
|
export declare function clearTableClientCache(): void;
|
package/dist/storage/client.js
CHANGED
|
@@ -16,14 +16,26 @@ const tableClients = new Map();
|
|
|
16
16
|
let storageAccountName;
|
|
17
17
|
let connectionString;
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Initializes Azure Table Storage configuration. Call once at application startup.
|
|
20
|
+
* @param config - Storage configuration options
|
|
21
|
+
* @param config.accountName - Azure Storage account name (for managed identity)
|
|
22
|
+
* @param config.connectionString - Connection string (for local development)
|
|
23
|
+
* @example
|
|
24
|
+
* // Production (Azure with managed identity)
|
|
25
|
+
* initStorage({ accountName: 'mystorageaccount' });
|
|
26
|
+
*
|
|
27
|
+
* // Local development (Azurite)
|
|
28
|
+
* initStorage({ connectionString: 'UseDevelopmentStorage=true' });
|
|
20
29
|
*/
|
|
21
30
|
function initStorage(config) {
|
|
22
31
|
storageAccountName = config.accountName;
|
|
23
32
|
connectionString = config.connectionString;
|
|
24
33
|
}
|
|
25
34
|
/**
|
|
26
|
-
*
|
|
35
|
+
* Initializes storage from environment variables.
|
|
36
|
+
* Reads STORAGE_ACCOUNT_NAME and AzureWebJobsStorage.
|
|
37
|
+
* @example
|
|
38
|
+
* initStorageFromEnv(); // Uses process.env automatically
|
|
27
39
|
*/
|
|
28
40
|
function initStorageFromEnv() {
|
|
29
41
|
initStorage({
|
|
@@ -32,14 +44,21 @@ function initStorageFromEnv() {
|
|
|
32
44
|
});
|
|
33
45
|
}
|
|
34
46
|
/**
|
|
35
|
-
*
|
|
47
|
+
* Checks if using Azure managed identity vs local connection string.
|
|
48
|
+
* @returns True if using managed identity (production), false for connection string (local)
|
|
36
49
|
*/
|
|
37
50
|
function useManagedIdentity() {
|
|
38
51
|
return !!storageAccountName && !connectionString?.includes('UseDevelopmentStorage');
|
|
39
52
|
}
|
|
40
53
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
54
|
+
* Gets a TableClient for the specified table, creating the table if needed.
|
|
55
|
+
* Clients are cached for reuse across requests.
|
|
56
|
+
* @param tableName - The Azure Table Storage table name
|
|
57
|
+
* @returns A configured TableClient instance
|
|
58
|
+
* @throws Error if storage is not configured
|
|
59
|
+
* @example
|
|
60
|
+
* const client = await getTableClient('users');
|
|
61
|
+
* await client.createEntity({ partitionKey: 'pk', rowKey: 'rk', name: 'John' });
|
|
43
62
|
*/
|
|
44
63
|
async function getTableClient(tableName) {
|
|
45
64
|
// Return cached client if available
|
|
@@ -77,7 +96,11 @@ async function getTableClient(tableName) {
|
|
|
77
96
|
return client;
|
|
78
97
|
}
|
|
79
98
|
/**
|
|
80
|
-
*
|
|
99
|
+
* Clears the TableClient cache. Primarily useful for testing.
|
|
100
|
+
* @example
|
|
101
|
+
* afterEach(() => {
|
|
102
|
+
* clearTableClientCache();
|
|
103
|
+
* });
|
|
81
104
|
*/
|
|
82
105
|
function clearTableClientCache() {
|
|
83
106
|
tableClients.clear();
|
package/dist/types.d.ts
CHANGED
|
@@ -22,14 +22,27 @@ export interface Result<T> {
|
|
|
22
22
|
statusCode?: number;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* Creates a success result with data.
|
|
26
|
+
* @param data - The success payload
|
|
27
|
+
* @returns A Result with ok=true and the provided data
|
|
28
|
+
* @example
|
|
29
|
+
* return ok({ user: 'john', role: 'admin' });
|
|
26
30
|
*/
|
|
27
31
|
export declare function ok<T>(data: T): Result<T>;
|
|
28
32
|
/**
|
|
29
|
-
*
|
|
33
|
+
* Creates a success result with no data.
|
|
34
|
+
* @returns A Result with ok=true and no data
|
|
35
|
+
* @example
|
|
36
|
+
* return okVoid(); // { ok: true }
|
|
30
37
|
*/
|
|
31
38
|
export declare function okVoid(): Result<void>;
|
|
32
39
|
/**
|
|
33
|
-
*
|
|
40
|
+
* Creates a failure result with an error message.
|
|
41
|
+
* @param error - The error message
|
|
42
|
+
* @param statusCode - Optional HTTP status code for API/push operations
|
|
43
|
+
* @returns A Result with ok=false and the error details
|
|
44
|
+
* @example
|
|
45
|
+
* return err('Token expired');
|
|
46
|
+
* return err('Subscription gone', 410);
|
|
34
47
|
*/
|
|
35
48
|
export declare function err<T>(error: string, statusCode?: number): Result<T>;
|
package/dist/types.js
CHANGED
|
@@ -7,19 +7,32 @@ exports.ok = ok;
|
|
|
7
7
|
exports.okVoid = okVoid;
|
|
8
8
|
exports.err = err;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Creates a success result with data.
|
|
11
|
+
* @param data - The success payload
|
|
12
|
+
* @returns A Result with ok=true and the provided data
|
|
13
|
+
* @example
|
|
14
|
+
* return ok({ user: 'john', role: 'admin' });
|
|
11
15
|
*/
|
|
12
16
|
function ok(data) {
|
|
13
17
|
return { ok: true, data };
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
|
-
*
|
|
20
|
+
* Creates a success result with no data.
|
|
21
|
+
* @returns A Result with ok=true and no data
|
|
22
|
+
* @example
|
|
23
|
+
* return okVoid(); // { ok: true }
|
|
17
24
|
*/
|
|
18
25
|
function okVoid() {
|
|
19
26
|
return { ok: true };
|
|
20
27
|
}
|
|
21
28
|
/**
|
|
22
|
-
*
|
|
29
|
+
* Creates a failure result with an error message.
|
|
30
|
+
* @param error - The error message
|
|
31
|
+
* @param statusCode - Optional HTTP status code for API/push operations
|
|
32
|
+
* @returns A Result with ok=false and the error details
|
|
33
|
+
* @example
|
|
34
|
+
* return err('Token expired');
|
|
35
|
+
* return err('Subscription gone', 410);
|
|
23
36
|
*/
|
|
24
37
|
function err(error, statusCode) {
|
|
25
38
|
return statusCode !== undefined
|
package/package.json
CHANGED
|
@@ -1,16 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markwharton/pwa-core",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
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",
|