@markwharton/pwa-core 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.
- package/dist/auth/apiKey.d.ts +24 -0
- package/dist/auth/apiKey.js +36 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.js +22 -0
- package/dist/auth/token.d.ts +26 -0
- package/dist/auth/token.js +73 -0
- package/dist/auth/types.d.ts +45 -0
- package/dist/auth/types.js +23 -0
- package/dist/client/ApiError.d.ts +21 -0
- package/dist/client/ApiError.js +34 -0
- package/dist/client/api.d.ts +44 -0
- package/dist/client/api.js +116 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +14 -0
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +14 -0
- package/dist/http/responses.d.ts +40 -0
- package/dist/http/responses.js +83 -0
- package/dist/http/status.d.ts +17 -0
- package/dist/http/status.js +19 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +21 -0
- package/dist/storage/client.d.ts +25 -0
- package/dist/storage/client.js +84 -0
- package/dist/storage/helpers.d.ts +8 -0
- package/dist/storage/helpers.js +14 -0
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.js +11 -0
- package/package.json +42 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key utilities for machine-to-machine authentication
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Extract API key from X-API-Key header
|
|
6
|
+
*/
|
|
7
|
+
export declare function extractApiKey(request: {
|
|
8
|
+
headers: {
|
|
9
|
+
get(name: string): string | null;
|
|
10
|
+
};
|
|
11
|
+
}): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Hash an API key for secure storage
|
|
14
|
+
* Store this hash, not the raw key
|
|
15
|
+
*/
|
|
16
|
+
export declare function hashApiKey(apiKey: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Validate API key against stored hash
|
|
19
|
+
*/
|
|
20
|
+
export declare function validateApiKey(apiKey: string, storedHash: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Generate a new API key (random 32-byte hex string)
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateApiKey(): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractApiKey = extractApiKey;
|
|
4
|
+
exports.hashApiKey = hashApiKey;
|
|
5
|
+
exports.validateApiKey = validateApiKey;
|
|
6
|
+
exports.generateApiKey = generateApiKey;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
/**
|
|
9
|
+
* API Key utilities for machine-to-machine authentication
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Extract API key from X-API-Key header
|
|
13
|
+
*/
|
|
14
|
+
function extractApiKey(request) {
|
|
15
|
+
return request.headers.get('X-API-Key');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Hash an API key for secure storage
|
|
19
|
+
* Store this hash, not the raw key
|
|
20
|
+
*/
|
|
21
|
+
function hashApiKey(apiKey) {
|
|
22
|
+
return (0, crypto_1.createHash)('sha256').update(apiKey).digest('hex');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validate API key against stored hash
|
|
26
|
+
*/
|
|
27
|
+
function validateApiKey(apiKey, storedHash) {
|
|
28
|
+
const keyHash = hashApiKey(apiKey);
|
|
29
|
+
return keyHash === storedHash;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generate a new API key (random 32-byte hex string)
|
|
33
|
+
*/
|
|
34
|
+
function generateApiKey() {
|
|
35
|
+
return (0, crypto_1.randomBytes)(32).toString('hex');
|
|
36
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { type BaseJwtPayload, type UserTokenPayload, type UsernameTokenPayload, type RoleTokenPayload, hasUsername, hasRole, isAdmin } from './types';
|
|
2
|
+
export { initAuth, getJwtSecret, extractToken, validateToken, generateToken, generateLongLivedToken } from './token';
|
|
3
|
+
export { extractApiKey, hashApiKey, validateApiKey, generateApiKey } from './apiKey';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateApiKey = exports.validateApiKey = exports.hashApiKey = exports.extractApiKey = exports.generateLongLivedToken = exports.generateToken = exports.validateToken = exports.extractToken = exports.getJwtSecret = exports.initAuth = exports.isAdmin = exports.hasRole = exports.hasUsername = void 0;
|
|
4
|
+
// Types and type guards
|
|
5
|
+
var types_1 = require("./types");
|
|
6
|
+
Object.defineProperty(exports, "hasUsername", { enumerable: true, get: function () { return types_1.hasUsername; } });
|
|
7
|
+
Object.defineProperty(exports, "hasRole", { enumerable: true, get: function () { return types_1.hasRole; } });
|
|
8
|
+
Object.defineProperty(exports, "isAdmin", { enumerable: true, get: function () { return types_1.isAdmin; } });
|
|
9
|
+
// JWT functions
|
|
10
|
+
var token_1 = require("./token");
|
|
11
|
+
Object.defineProperty(exports, "initAuth", { enumerable: true, get: function () { return token_1.initAuth; } });
|
|
12
|
+
Object.defineProperty(exports, "getJwtSecret", { enumerable: true, get: function () { return token_1.getJwtSecret; } });
|
|
13
|
+
Object.defineProperty(exports, "extractToken", { enumerable: true, get: function () { return token_1.extractToken; } });
|
|
14
|
+
Object.defineProperty(exports, "validateToken", { enumerable: true, get: function () { return token_1.validateToken; } });
|
|
15
|
+
Object.defineProperty(exports, "generateToken", { enumerable: true, get: function () { return token_1.generateToken; } });
|
|
16
|
+
Object.defineProperty(exports, "generateLongLivedToken", { enumerable: true, get: function () { return token_1.generateLongLivedToken; } });
|
|
17
|
+
// API key functions
|
|
18
|
+
var apiKey_1 = require("./apiKey");
|
|
19
|
+
Object.defineProperty(exports, "extractApiKey", { enumerable: true, get: function () { return apiKey_1.extractApiKey; } });
|
|
20
|
+
Object.defineProperty(exports, "hashApiKey", { enumerable: true, get: function () { return apiKey_1.hashApiKey; } });
|
|
21
|
+
Object.defineProperty(exports, "validateApiKey", { enumerable: true, get: function () { return apiKey_1.validateApiKey; } });
|
|
22
|
+
Object.defineProperty(exports, "generateApiKey", { enumerable: true, get: function () { return apiKey_1.generateApiKey; } });
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize JWT secret - call once at startup
|
|
3
|
+
* Fails fast if secret is missing or too short
|
|
4
|
+
*/
|
|
5
|
+
export declare function initAuth(secret: string | undefined, minLength?: number): void;
|
|
6
|
+
/**
|
|
7
|
+
* Get the JWT secret (throws if not initialized)
|
|
8
|
+
*/
|
|
9
|
+
export declare function getJwtSecret(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Extract Bearer token from Authorization header
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractToken(authHeader: string | null): string | null;
|
|
14
|
+
/**
|
|
15
|
+
* Validate and decode a JWT token
|
|
16
|
+
* Generic type allows project-specific payload shapes
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateToken<T extends object>(token: string): T | null;
|
|
19
|
+
/**
|
|
20
|
+
* Generate a JWT token with custom payload
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateToken<T extends object>(payload: T, expiresIn?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Generate a long-lived token (e.g., for machine/API access)
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateLongLivedToken<T extends object>(payload: T, expiresInDays?: number): string;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initAuth = initAuth;
|
|
7
|
+
exports.getJwtSecret = getJwtSecret;
|
|
8
|
+
exports.extractToken = extractToken;
|
|
9
|
+
exports.validateToken = validateToken;
|
|
10
|
+
exports.generateToken = generateToken;
|
|
11
|
+
exports.generateLongLivedToken = generateLongLivedToken;
|
|
12
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
13
|
+
/**
|
|
14
|
+
* JWT token utilities - works with any payload structure
|
|
15
|
+
* Use BaseJwtPayload or extend it for type safety
|
|
16
|
+
*/
|
|
17
|
+
let jwtSecret = null;
|
|
18
|
+
/**
|
|
19
|
+
* Initialize JWT secret - call once at startup
|
|
20
|
+
* Fails fast if secret is missing or too short
|
|
21
|
+
*/
|
|
22
|
+
function initAuth(secret, minLength = 32) {
|
|
23
|
+
if (!secret || secret.length < minLength) {
|
|
24
|
+
throw new Error(`JWT_SECRET must be at least ${minLength} characters`);
|
|
25
|
+
}
|
|
26
|
+
jwtSecret = secret;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the JWT secret (throws if not initialized)
|
|
30
|
+
*/
|
|
31
|
+
function getJwtSecret() {
|
|
32
|
+
if (!jwtSecret) {
|
|
33
|
+
throw new Error('Auth not initialized. Call initAuth() first.');
|
|
34
|
+
}
|
|
35
|
+
return jwtSecret;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Extract Bearer token from Authorization header
|
|
39
|
+
*/
|
|
40
|
+
function extractToken(authHeader) {
|
|
41
|
+
if (!authHeader?.startsWith('Bearer ')) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return authHeader.slice(7);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validate and decode a JWT token
|
|
48
|
+
* Generic type allows project-specific payload shapes
|
|
49
|
+
*/
|
|
50
|
+
function validateToken(token) {
|
|
51
|
+
try {
|
|
52
|
+
const payload = jsonwebtoken_1.default.verify(token, getJwtSecret());
|
|
53
|
+
if (typeof payload === 'object' && payload !== null) {
|
|
54
|
+
return payload;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Generate a JWT token with custom payload
|
|
64
|
+
*/
|
|
65
|
+
function generateToken(payload, expiresIn = '7d') {
|
|
66
|
+
return jsonwebtoken_1.default.sign(payload, getJwtSecret(), { expiresIn });
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Generate a long-lived token (e.g., for machine/API access)
|
|
70
|
+
*/
|
|
71
|
+
function generateLongLivedToken(payload, expiresInDays = 3650) {
|
|
72
|
+
return jsonwebtoken_1.default.sign(payload, getJwtSecret(), { expiresIn: `${expiresInDays}d` });
|
|
73
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base JWT payload - all tokens include these fields
|
|
3
|
+
* Projects extend this with their specific fields
|
|
4
|
+
*/
|
|
5
|
+
export interface BaseJwtPayload {
|
|
6
|
+
iat: number;
|
|
7
|
+
exp: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Standard user token payload
|
|
11
|
+
* Used by: azure-pwa-starter, azure-alert-service (admin), onsite-monitor
|
|
12
|
+
*/
|
|
13
|
+
export interface UserTokenPayload extends BaseJwtPayload {
|
|
14
|
+
authenticated: true;
|
|
15
|
+
tokenType: 'user' | 'machine';
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Username-based token payload
|
|
19
|
+
* Used by: financial-tracker
|
|
20
|
+
*/
|
|
21
|
+
export interface UsernameTokenPayload extends BaseJwtPayload {
|
|
22
|
+
username: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Role-based token payload
|
|
26
|
+
* Used by: azure-alert-service
|
|
27
|
+
*/
|
|
28
|
+
export interface RoleTokenPayload extends BaseJwtPayload {
|
|
29
|
+
authenticated: true;
|
|
30
|
+
tokenType: 'user' | 'machine';
|
|
31
|
+
role: 'admin' | 'viewer';
|
|
32
|
+
viewerTokenId?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Type guard to check if payload has a username
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasUsername(payload: BaseJwtPayload): payload is UsernameTokenPayload;
|
|
38
|
+
/**
|
|
39
|
+
* Type guard to check if payload has a role
|
|
40
|
+
*/
|
|
41
|
+
export declare function hasRole(payload: BaseJwtPayload): payload is RoleTokenPayload;
|
|
42
|
+
/**
|
|
43
|
+
* Type guard to check if payload is admin
|
|
44
|
+
*/
|
|
45
|
+
export declare function isAdmin(payload: BaseJwtPayload): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasUsername = hasUsername;
|
|
4
|
+
exports.hasRole = hasRole;
|
|
5
|
+
exports.isAdmin = isAdmin;
|
|
6
|
+
/**
|
|
7
|
+
* Type guard to check if payload has a username
|
|
8
|
+
*/
|
|
9
|
+
function hasUsername(payload) {
|
|
10
|
+
return 'username' in payload && typeof payload.username === 'string';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Type guard to check if payload has a role
|
|
14
|
+
*/
|
|
15
|
+
function hasRole(payload) {
|
|
16
|
+
return 'role' in payload;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Type guard to check if payload is admin
|
|
20
|
+
*/
|
|
21
|
+
function isAdmin(payload) {
|
|
22
|
+
return hasRole(payload) && payload.role === 'admin';
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for API errors
|
|
3
|
+
* Preserves status code and error message from server
|
|
4
|
+
*/
|
|
5
|
+
export declare class ApiError extends Error {
|
|
6
|
+
status: number;
|
|
7
|
+
details?: string | undefined;
|
|
8
|
+
constructor(status: number, message: string, details?: string | undefined);
|
|
9
|
+
/**
|
|
10
|
+
* Check if this is an authentication error
|
|
11
|
+
*/
|
|
12
|
+
isUnauthorized(): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Check if this is a not found error
|
|
15
|
+
*/
|
|
16
|
+
isNotFound(): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Check if this is a validation error
|
|
19
|
+
*/
|
|
20
|
+
isBadRequest(): boolean;
|
|
21
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApiError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Custom error class for API errors
|
|
6
|
+
* Preserves status code and error message from server
|
|
7
|
+
*/
|
|
8
|
+
class ApiError extends Error {
|
|
9
|
+
constructor(status, message, details) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.details = details;
|
|
13
|
+
this.name = 'ApiError';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check if this is an authentication error
|
|
17
|
+
*/
|
|
18
|
+
isUnauthorized() {
|
|
19
|
+
return this.status === 401;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if this is a not found error
|
|
23
|
+
*/
|
|
24
|
+
isNotFound() {
|
|
25
|
+
return this.status === 404;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Check if this is a validation error
|
|
29
|
+
*/
|
|
30
|
+
isBadRequest() {
|
|
31
|
+
return this.status === 400;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.ApiError = ApiError;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize the API client
|
|
3
|
+
*/
|
|
4
|
+
export declare function initApiClient(config: {
|
|
5
|
+
getToken: () => string | null;
|
|
6
|
+
onUnauthorized?: () => void;
|
|
7
|
+
}): void;
|
|
8
|
+
/**
|
|
9
|
+
* API response wrapper
|
|
10
|
+
*/
|
|
11
|
+
export interface ApiResponse<T> {
|
|
12
|
+
ok: boolean;
|
|
13
|
+
status: number;
|
|
14
|
+
data?: T;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Make an authenticated API call
|
|
19
|
+
*/
|
|
20
|
+
export declare function apiCall<T>(url: string, options?: RequestInit): Promise<T>;
|
|
21
|
+
/**
|
|
22
|
+
* GET request helper
|
|
23
|
+
*/
|
|
24
|
+
export declare function apiGet<T>(url: string): Promise<T>;
|
|
25
|
+
/**
|
|
26
|
+
* POST request helper
|
|
27
|
+
*/
|
|
28
|
+
export declare function apiPost<T>(url: string, body?: unknown): Promise<T>;
|
|
29
|
+
/**
|
|
30
|
+
* PUT request helper
|
|
31
|
+
*/
|
|
32
|
+
export declare function apiPut<T>(url: string, body?: unknown): Promise<T>;
|
|
33
|
+
/**
|
|
34
|
+
* PATCH request helper
|
|
35
|
+
*/
|
|
36
|
+
export declare function apiPatch<T>(url: string, body?: unknown): Promise<T>;
|
|
37
|
+
/**
|
|
38
|
+
* DELETE request helper
|
|
39
|
+
*/
|
|
40
|
+
export declare function apiDelete<T>(url: string): Promise<T>;
|
|
41
|
+
/**
|
|
42
|
+
* Alternative: Response wrapper style (like financial-tracker's authJsonFetch)
|
|
43
|
+
*/
|
|
44
|
+
export declare function apiCallSafe<T>(url: string, options?: RequestInit): Promise<ApiResponse<T>>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initApiClient = initApiClient;
|
|
4
|
+
exports.apiCall = apiCall;
|
|
5
|
+
exports.apiGet = apiGet;
|
|
6
|
+
exports.apiPost = apiPost;
|
|
7
|
+
exports.apiPut = apiPut;
|
|
8
|
+
exports.apiPatch = apiPatch;
|
|
9
|
+
exports.apiDelete = apiDelete;
|
|
10
|
+
exports.apiCallSafe = apiCallSafe;
|
|
11
|
+
const ApiError_1 = require("./ApiError");
|
|
12
|
+
/**
|
|
13
|
+
* Client-side API utilities for authenticated requests
|
|
14
|
+
*/
|
|
15
|
+
// Token getter function - set by consuming app
|
|
16
|
+
let getToken = null;
|
|
17
|
+
// Callback for 401 responses (e.g., redirect to login)
|
|
18
|
+
let onUnauthorized = null;
|
|
19
|
+
/**
|
|
20
|
+
* Initialize the API client
|
|
21
|
+
*/
|
|
22
|
+
function initApiClient(config) {
|
|
23
|
+
getToken = config.getToken;
|
|
24
|
+
onUnauthorized = config.onUnauthorized ?? null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Make an authenticated API call
|
|
28
|
+
*/
|
|
29
|
+
async function apiCall(url, options = {}) {
|
|
30
|
+
const token = getToken?.();
|
|
31
|
+
const headers = {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
...options.headers
|
|
34
|
+
};
|
|
35
|
+
if (token) {
|
|
36
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
37
|
+
}
|
|
38
|
+
const response = await fetch(url, {
|
|
39
|
+
...options,
|
|
40
|
+
headers
|
|
41
|
+
});
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
if (response.status === 401 && onUnauthorized) {
|
|
44
|
+
onUnauthorized();
|
|
45
|
+
}
|
|
46
|
+
let errorMessage = 'Request failed';
|
|
47
|
+
try {
|
|
48
|
+
const errorData = (await response.json());
|
|
49
|
+
errorMessage = errorData.error || errorMessage;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Ignore JSON parse errors
|
|
53
|
+
}
|
|
54
|
+
throw new ApiError_1.ApiError(response.status, errorMessage);
|
|
55
|
+
}
|
|
56
|
+
// Handle empty responses
|
|
57
|
+
const text = await response.text();
|
|
58
|
+
if (!text) {
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
return JSON.parse(text);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* GET request helper
|
|
65
|
+
*/
|
|
66
|
+
async function apiGet(url) {
|
|
67
|
+
return apiCall(url, { method: 'GET' });
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* POST request helper
|
|
71
|
+
*/
|
|
72
|
+
async function apiPost(url, body) {
|
|
73
|
+
return apiCall(url, {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
body: body ? JSON.stringify(body) : undefined
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* PUT request helper
|
|
80
|
+
*/
|
|
81
|
+
async function apiPut(url, body) {
|
|
82
|
+
return apiCall(url, {
|
|
83
|
+
method: 'PUT',
|
|
84
|
+
body: body ? JSON.stringify(body) : undefined
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* PATCH request helper
|
|
89
|
+
*/
|
|
90
|
+
async function apiPatch(url, body) {
|
|
91
|
+
return apiCall(url, {
|
|
92
|
+
method: 'PATCH',
|
|
93
|
+
body: body ? JSON.stringify(body) : undefined
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* DELETE request helper
|
|
98
|
+
*/
|
|
99
|
+
async function apiDelete(url) {
|
|
100
|
+
return apiCall(url, { method: 'DELETE' });
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Alternative: Response wrapper style (like financial-tracker's authJsonFetch)
|
|
104
|
+
*/
|
|
105
|
+
async function apiCallSafe(url, options = {}) {
|
|
106
|
+
try {
|
|
107
|
+
const data = await apiCall(url, options);
|
|
108
|
+
return { ok: true, status: 200, data };
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error instanceof ApiError_1.ApiError) {
|
|
112
|
+
return { ok: false, status: error.status, error: error.message };
|
|
113
|
+
}
|
|
114
|
+
return { ok: false, status: 0, error: 'Network error' };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.apiCallSafe = exports.apiDelete = exports.apiPatch = exports.apiPut = exports.apiPost = exports.apiGet = exports.apiCall = exports.initApiClient = exports.ApiError = void 0;
|
|
4
|
+
var ApiError_1 = require("./ApiError");
|
|
5
|
+
Object.defineProperty(exports, "ApiError", { enumerable: true, get: function () { return ApiError_1.ApiError; } });
|
|
6
|
+
var api_1 = require("./api");
|
|
7
|
+
Object.defineProperty(exports, "initApiClient", { enumerable: true, get: function () { return api_1.initApiClient; } });
|
|
8
|
+
Object.defineProperty(exports, "apiCall", { enumerable: true, get: function () { return api_1.apiCall; } });
|
|
9
|
+
Object.defineProperty(exports, "apiGet", { enumerable: true, get: function () { return api_1.apiGet; } });
|
|
10
|
+
Object.defineProperty(exports, "apiPost", { enumerable: true, get: function () { return api_1.apiPost; } });
|
|
11
|
+
Object.defineProperty(exports, "apiPut", { enumerable: true, get: function () { return api_1.apiPut; } });
|
|
12
|
+
Object.defineProperty(exports, "apiPatch", { enumerable: true, get: function () { return api_1.apiPatch; } });
|
|
13
|
+
Object.defineProperty(exports, "apiDelete", { enumerable: true, get: function () { return api_1.apiDelete; } });
|
|
14
|
+
Object.defineProperty(exports, "apiCallSafe", { enumerable: true, get: function () { return api_1.apiCallSafe; } });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isConflictError = exports.isNotFoundError = exports.handleFunctionError = exports.conflictResponse = exports.notFoundResponse = exports.forbiddenResponse = exports.unauthorizedResponse = exports.badRequestResponse = exports.HTTP_STATUS = void 0;
|
|
4
|
+
var status_1 = require("./status");
|
|
5
|
+
Object.defineProperty(exports, "HTTP_STATUS", { enumerable: true, get: function () { return status_1.HTTP_STATUS; } });
|
|
6
|
+
var responses_1 = require("./responses");
|
|
7
|
+
Object.defineProperty(exports, "badRequestResponse", { enumerable: true, get: function () { return responses_1.badRequestResponse; } });
|
|
8
|
+
Object.defineProperty(exports, "unauthorizedResponse", { enumerable: true, get: function () { return responses_1.unauthorizedResponse; } });
|
|
9
|
+
Object.defineProperty(exports, "forbiddenResponse", { enumerable: true, get: function () { return responses_1.forbiddenResponse; } });
|
|
10
|
+
Object.defineProperty(exports, "notFoundResponse", { enumerable: true, get: function () { return responses_1.notFoundResponse; } });
|
|
11
|
+
Object.defineProperty(exports, "conflictResponse", { enumerable: true, get: function () { return responses_1.conflictResponse; } });
|
|
12
|
+
Object.defineProperty(exports, "handleFunctionError", { enumerable: true, get: function () { return responses_1.handleFunctionError; } });
|
|
13
|
+
Object.defineProperty(exports, "isNotFoundError", { enumerable: true, get: function () { return responses_1.isNotFoundError; } });
|
|
14
|
+
Object.defineProperty(exports, "isConflictError", { enumerable: true, get: function () { return responses_1.isConflictError; } });
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { HttpResponseInit, InvocationContext } from '@azure/functions';
|
|
2
|
+
/**
|
|
3
|
+
* Standard error response structure
|
|
4
|
+
*/
|
|
5
|
+
export interface ErrorResponse {
|
|
6
|
+
error: string;
|
|
7
|
+
details?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create a 400 Bad Request response
|
|
11
|
+
*/
|
|
12
|
+
export declare function badRequestResponse(message: string): HttpResponseInit;
|
|
13
|
+
/**
|
|
14
|
+
* Create a 401 Unauthorized response
|
|
15
|
+
*/
|
|
16
|
+
export declare function unauthorizedResponse(message?: string): HttpResponseInit;
|
|
17
|
+
/**
|
|
18
|
+
* Create a 403 Forbidden response
|
|
19
|
+
*/
|
|
20
|
+
export declare function forbiddenResponse(message?: string): HttpResponseInit;
|
|
21
|
+
/**
|
|
22
|
+
* Create a 404 Not Found response
|
|
23
|
+
*/
|
|
24
|
+
export declare function notFoundResponse(resource: string): HttpResponseInit;
|
|
25
|
+
/**
|
|
26
|
+
* Create a 409 Conflict response
|
|
27
|
+
*/
|
|
28
|
+
export declare function conflictResponse(message: string): HttpResponseInit;
|
|
29
|
+
/**
|
|
30
|
+
* Handle unexpected errors safely (logs details, returns generic message)
|
|
31
|
+
*/
|
|
32
|
+
export declare function handleFunctionError(error: unknown, context: InvocationContext): HttpResponseInit;
|
|
33
|
+
/**
|
|
34
|
+
* Check if an Azure Table Storage error is "not found"
|
|
35
|
+
*/
|
|
36
|
+
export declare function isNotFoundError(error: unknown): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Check if an Azure Table Storage error is "conflict"
|
|
39
|
+
*/
|
|
40
|
+
export declare function isConflictError(error: unknown): boolean;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.badRequestResponse = badRequestResponse;
|
|
4
|
+
exports.unauthorizedResponse = unauthorizedResponse;
|
|
5
|
+
exports.forbiddenResponse = forbiddenResponse;
|
|
6
|
+
exports.notFoundResponse = notFoundResponse;
|
|
7
|
+
exports.conflictResponse = conflictResponse;
|
|
8
|
+
exports.handleFunctionError = handleFunctionError;
|
|
9
|
+
exports.isNotFoundError = isNotFoundError;
|
|
10
|
+
exports.isConflictError = isConflictError;
|
|
11
|
+
const status_1 = require("./status");
|
|
12
|
+
/**
|
|
13
|
+
* Create a 400 Bad Request response
|
|
14
|
+
*/
|
|
15
|
+
function badRequestResponse(message) {
|
|
16
|
+
return {
|
|
17
|
+
status: status_1.HTTP_STATUS.BAD_REQUEST,
|
|
18
|
+
jsonBody: { error: message }
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a 401 Unauthorized response
|
|
23
|
+
*/
|
|
24
|
+
function unauthorizedResponse(message = 'Unauthorized') {
|
|
25
|
+
return {
|
|
26
|
+
status: status_1.HTTP_STATUS.UNAUTHORIZED,
|
|
27
|
+
jsonBody: { error: message }
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Create a 403 Forbidden response
|
|
32
|
+
*/
|
|
33
|
+
function forbiddenResponse(message = 'Forbidden') {
|
|
34
|
+
return {
|
|
35
|
+
status: status_1.HTTP_STATUS.FORBIDDEN,
|
|
36
|
+
jsonBody: { error: message }
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a 404 Not Found response
|
|
41
|
+
*/
|
|
42
|
+
function notFoundResponse(resource) {
|
|
43
|
+
return {
|
|
44
|
+
status: status_1.HTTP_STATUS.NOT_FOUND,
|
|
45
|
+
jsonBody: { error: `${resource} not found` }
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create a 409 Conflict response
|
|
50
|
+
*/
|
|
51
|
+
function conflictResponse(message) {
|
|
52
|
+
return {
|
|
53
|
+
status: status_1.HTTP_STATUS.CONFLICT,
|
|
54
|
+
jsonBody: { error: message }
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Handle unexpected errors safely (logs details, returns generic message)
|
|
59
|
+
*/
|
|
60
|
+
function handleFunctionError(error, context) {
|
|
61
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
62
|
+
context.error(`Function error: ${message}`);
|
|
63
|
+
return {
|
|
64
|
+
status: status_1.HTTP_STATUS.INTERNAL_ERROR,
|
|
65
|
+
jsonBody: { error: 'Internal server error' }
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if an Azure Table Storage error is "not found"
|
|
70
|
+
*/
|
|
71
|
+
function isNotFoundError(error) {
|
|
72
|
+
return (error instanceof Error &&
|
|
73
|
+
'statusCode' in error &&
|
|
74
|
+
error.statusCode === 404);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if an Azure Table Storage error is "conflict"
|
|
78
|
+
*/
|
|
79
|
+
function isConflictError(error) {
|
|
80
|
+
return (error instanceof Error &&
|
|
81
|
+
'statusCode' in error &&
|
|
82
|
+
error.statusCode === 409);
|
|
83
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP status codes - use instead of magic numbers
|
|
3
|
+
*/
|
|
4
|
+
export declare const HTTP_STATUS: {
|
|
5
|
+
readonly OK: 200;
|
|
6
|
+
readonly CREATED: 201;
|
|
7
|
+
readonly NO_CONTENT: 204;
|
|
8
|
+
readonly BAD_REQUEST: 400;
|
|
9
|
+
readonly UNAUTHORIZED: 401;
|
|
10
|
+
readonly FORBIDDEN: 403;
|
|
11
|
+
readonly NOT_FOUND: 404;
|
|
12
|
+
readonly CONFLICT: 409;
|
|
13
|
+
readonly GONE: 410;
|
|
14
|
+
readonly INTERNAL_ERROR: 500;
|
|
15
|
+
readonly SERVICE_UNAVAILABLE: 503;
|
|
16
|
+
};
|
|
17
|
+
export type HttpStatus = typeof HTTP_STATUS[keyof typeof HTTP_STATUS];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HTTP_STATUS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* HTTP status codes - use instead of magic numbers
|
|
6
|
+
*/
|
|
7
|
+
exports.HTTP_STATUS = {
|
|
8
|
+
OK: 200,
|
|
9
|
+
CREATED: 201,
|
|
10
|
+
NO_CONTENT: 204,
|
|
11
|
+
BAD_REQUEST: 400,
|
|
12
|
+
UNAUTHORIZED: 401,
|
|
13
|
+
FORBIDDEN: 403,
|
|
14
|
+
NOT_FOUND: 404,
|
|
15
|
+
CONFLICT: 409,
|
|
16
|
+
GONE: 410,
|
|
17
|
+
INTERNAL_ERROR: 500,
|
|
18
|
+
SERVICE_UNAVAILABLE: 503
|
|
19
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Main entry point - re-export everything
|
|
18
|
+
__exportStar(require("./auth"), exports);
|
|
19
|
+
__exportStar(require("./http"), exports);
|
|
20
|
+
__exportStar(require("./storage"), exports);
|
|
21
|
+
__exportStar(require("./client"), exports);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TableClient } from '@azure/data-tables';
|
|
2
|
+
/**
|
|
3
|
+
* Initialize storage configuration - call once at startup
|
|
4
|
+
*/
|
|
5
|
+
export declare function initStorage(config: {
|
|
6
|
+
accountName?: string;
|
|
7
|
+
connectionString?: string;
|
|
8
|
+
}): void;
|
|
9
|
+
/**
|
|
10
|
+
* Auto-initialize from environment variables
|
|
11
|
+
*/
|
|
12
|
+
export declare function initStorageFromEnv(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Check if using managed identity (Azure) vs connection string (local)
|
|
15
|
+
*/
|
|
16
|
+
export declare function useManagedIdentity(): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Get a TableClient for the specified table
|
|
19
|
+
* Creates table if it doesn't exist, caches client for reuse
|
|
20
|
+
*/
|
|
21
|
+
export declare function getTableClient(tableName: string): Promise<TableClient>;
|
|
22
|
+
/**
|
|
23
|
+
* Clear the client cache (useful for testing)
|
|
24
|
+
*/
|
|
25
|
+
export declare function clearTableClientCache(): void;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initStorage = initStorage;
|
|
4
|
+
exports.initStorageFromEnv = initStorageFromEnv;
|
|
5
|
+
exports.useManagedIdentity = useManagedIdentity;
|
|
6
|
+
exports.getTableClient = getTableClient;
|
|
7
|
+
exports.clearTableClientCache = clearTableClientCache;
|
|
8
|
+
const data_tables_1 = require("@azure/data-tables");
|
|
9
|
+
const identity_1 = require("@azure/identity");
|
|
10
|
+
/**
|
|
11
|
+
* Azure Table Storage client factory with managed identity support
|
|
12
|
+
*/
|
|
13
|
+
// Cache table clients to avoid repeated connections
|
|
14
|
+
const tableClients = new Map();
|
|
15
|
+
// Configuration
|
|
16
|
+
let storageAccountName;
|
|
17
|
+
let connectionString;
|
|
18
|
+
/**
|
|
19
|
+
* Initialize storage configuration - call once at startup
|
|
20
|
+
*/
|
|
21
|
+
function initStorage(config) {
|
|
22
|
+
storageAccountName = config.accountName;
|
|
23
|
+
connectionString = config.connectionString;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Auto-initialize from environment variables
|
|
27
|
+
*/
|
|
28
|
+
function initStorageFromEnv() {
|
|
29
|
+
initStorage({
|
|
30
|
+
accountName: process.env.STORAGE_ACCOUNT_NAME,
|
|
31
|
+
connectionString: process.env.AzureWebJobsStorage
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check if using managed identity (Azure) vs connection string (local)
|
|
36
|
+
*/
|
|
37
|
+
function useManagedIdentity() {
|
|
38
|
+
return !!storageAccountName && !connectionString?.includes('UseDevelopmentStorage');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get a TableClient for the specified table
|
|
42
|
+
* Creates table if it doesn't exist, caches client for reuse
|
|
43
|
+
*/
|
|
44
|
+
async function getTableClient(tableName) {
|
|
45
|
+
// Return cached client if available
|
|
46
|
+
const cached = tableClients.get(tableName);
|
|
47
|
+
if (cached) {
|
|
48
|
+
return cached;
|
|
49
|
+
}
|
|
50
|
+
let client;
|
|
51
|
+
if (useManagedIdentity()) {
|
|
52
|
+
// Azure: Use managed identity
|
|
53
|
+
const credential = new identity_1.DefaultAzureCredential();
|
|
54
|
+
const endpoint = `https://${storageAccountName}.table.core.windows.net`;
|
|
55
|
+
client = new data_tables_1.TableClient(endpoint, tableName, credential);
|
|
56
|
+
}
|
|
57
|
+
else if (connectionString) {
|
|
58
|
+
// Local/Azurite: Use connection string
|
|
59
|
+
client = data_tables_1.TableClient.fromConnectionString(connectionString, tableName);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
throw new Error('Storage not configured. Set STORAGE_ACCOUNT_NAME or AzureWebJobsStorage.');
|
|
63
|
+
}
|
|
64
|
+
// Create table if it doesn't exist
|
|
65
|
+
try {
|
|
66
|
+
await client.createTable();
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
// Ignore "table already exists" errors (409 Conflict)
|
|
70
|
+
const tableError = error;
|
|
71
|
+
if (tableError.statusCode !== 409) {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Cache and return
|
|
76
|
+
tableClients.set(tableName, client);
|
|
77
|
+
return client;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Clear the client cache (useful for testing)
|
|
81
|
+
*/
|
|
82
|
+
function clearTableClientCache() {
|
|
83
|
+
tableClients.clear();
|
|
84
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
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;
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateRowKey = exports.clearTableClientCache = exports.getTableClient = exports.useManagedIdentity = exports.initStorageFromEnv = exports.initStorage = void 0;
|
|
4
|
+
var client_1 = require("./client");
|
|
5
|
+
Object.defineProperty(exports, "initStorage", { enumerable: true, get: function () { return client_1.initStorage; } });
|
|
6
|
+
Object.defineProperty(exports, "initStorageFromEnv", { enumerable: true, get: function () { return client_1.initStorageFromEnv; } });
|
|
7
|
+
Object.defineProperty(exports, "useManagedIdentity", { enumerable: true, get: function () { return client_1.useManagedIdentity; } });
|
|
8
|
+
Object.defineProperty(exports, "getTableClient", { enumerable: true, get: function () { return client_1.getTableClient; } });
|
|
9
|
+
Object.defineProperty(exports, "clearTableClientCache", { enumerable: true, get: function () { return client_1.clearTableClientCache; } });
|
|
10
|
+
var helpers_1 = require("./helpers");
|
|
11
|
+
Object.defineProperty(exports, "generateRowKey", { enumerable: true, get: function () { return helpers_1.generateRowKey; } });
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@markwharton/pwa-core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Shared patterns for Azure PWA projects",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js",
|
|
9
|
+
"./auth": "./dist/auth/index.js",
|
|
10
|
+
"./http": "./dist/http/index.js",
|
|
11
|
+
"./storage": "./dist/storage/index.js",
|
|
12
|
+
"./client": "./dist/client/index.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"clean": "rm -rf dist"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@azure/data-tables": "^13.0.0",
|
|
20
|
+
"@azure/identity": "^4.0.0",
|
|
21
|
+
"jsonwebtoken": "^9.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@azure/data-tables": "^13.2.2",
|
|
25
|
+
"@azure/functions": "^4.5.0",
|
|
26
|
+
"@azure/identity": "^4.5.0",
|
|
27
|
+
"@types/jsonwebtoken": "^9.0.5",
|
|
28
|
+
"@types/node": "^20.10.0",
|
|
29
|
+
"jsonwebtoken": "^9.0.2",
|
|
30
|
+
"typescript": "^5.3.0"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/MarkWharton/pwa-packages.git",
|
|
38
|
+
"directory": "packages/core"
|
|
39
|
+
},
|
|
40
|
+
"author": "Mark Wharton",
|
|
41
|
+
"license": "MIT"
|
|
42
|
+
}
|