universal-api-layer 0.7.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.
@@ -0,0 +1,142 @@
1
+ import "../chunk-HDW7BOZI.js";
2
+ import "../chunk-DXYWZQW5.js";
3
+ import {
4
+ ApiError
5
+ } from "../chunk-YTM3FV65.js";
6
+
7
+ // src/angular/index.ts
8
+ import {
9
+ DestroyRef,
10
+ InjectionToken,
11
+ inject,
12
+ makeEnvironmentProviders,
13
+ signal
14
+ } from "@angular/core";
15
+ import { Observable } from "rxjs";
16
+ var API_CLIENT = new InjectionToken(
17
+ "universal-api-layer client"
18
+ );
19
+ function provideApiClient(value) {
20
+ return makeEnvironmentProviders([
21
+ {
22
+ provide: API_CLIENT,
23
+ ...typeof value === "function" ? { useFactory: value } : { useValue: value }
24
+ },
25
+ {
26
+ provide: ApiService,
27
+ useFactory: () => {
28
+ const service = new ApiService(injectApiClient());
29
+ inject(DestroyRef).onDestroy(() => service.dispose());
30
+ return service;
31
+ }
32
+ }
33
+ ]);
34
+ }
35
+ function injectApiClient() {
36
+ return inject(API_CLIENT);
37
+ }
38
+ function injectApiSession(client = injectApiClient()) {
39
+ const destroy = inject(DestroyRef);
40
+ const state = signal(client.getSessionSnapshot());
41
+ destroy.onDestroy(
42
+ client.subscribeSession(() => state.set(client.getSessionSnapshot()))
43
+ );
44
+ return state.asReadonly();
45
+ }
46
+ var ApiService = class {
47
+ constructor(client) {
48
+ this.client = client;
49
+ }
50
+ client;
51
+ lifetime = new AbortController();
52
+ /** Automatically called when the providing injector is destroyed. */
53
+ dispose() {
54
+ this.lifetime.abort(
55
+ new ApiError(
56
+ "Angular API provider destroyed",
57
+ 0,
58
+ {},
59
+ void 0,
60
+ "cancelled"
61
+ )
62
+ );
63
+ }
64
+ operation(external, work) {
65
+ return new Observable((subscriber) => {
66
+ const revision = this.client.getSessionSnapshot().revision;
67
+ const controller = new AbortController();
68
+ const signals = [this.lifetime.signal, external].filter(
69
+ (value) => value !== void 0
70
+ );
71
+ const cleanups = signals.map((source) => {
72
+ const abort = () => controller.abort(source.reason);
73
+ if (source.aborted) abort();
74
+ else source.addEventListener("abort", abort, { once: true });
75
+ return () => source.removeEventListener("abort", abort);
76
+ });
77
+ void Promise.resolve().then(async () => {
78
+ if (subscriber.closed) return;
79
+ if (controller.signal.aborted)
80
+ throw new ApiError(
81
+ "Angular API operation cancelled",
82
+ 0,
83
+ {},
84
+ void 0,
85
+ "cancelled",
86
+ controller.signal.reason
87
+ );
88
+ this.client.assertSession(revision);
89
+ await work(controller.signal, subscriber, revision);
90
+ this.client.assertSession(revision);
91
+ if (!subscriber.closed) subscriber.complete();
92
+ }).catch((error) => {
93
+ if (!subscriber.closed) subscriber.error(error);
94
+ });
95
+ return () => {
96
+ for (const cleanup of cleanups) cleanup();
97
+ controller.abort(
98
+ new ApiError(
99
+ "Angular API subscription cancelled",
100
+ 0,
101
+ {},
102
+ void 0,
103
+ "cancelled"
104
+ )
105
+ );
106
+ };
107
+ });
108
+ }
109
+ request$(url, options = {}) {
110
+ return this.operation(
111
+ options.signal,
112
+ async (signal2, subscriber, revision) => {
113
+ const result = await this.client.request(url, { ...options, signal: signal2 });
114
+ this.client.assertSession(revision);
115
+ if (!subscriber.closed) subscriber.next(result);
116
+ }
117
+ );
118
+ }
119
+ stream$(url, options = {}) {
120
+ return this.operation(
121
+ options.signal,
122
+ async (signal2, subscriber, revision) => {
123
+ for await (const value of this.client.stream(url, {
124
+ ...options,
125
+ signal: signal2
126
+ })) {
127
+ if (subscriber.closed) break;
128
+ this.client.assertSession(revision);
129
+ subscriber.next(value);
130
+ if (subscriber.closed) break;
131
+ }
132
+ }
133
+ );
134
+ }
135
+ };
136
+ export {
137
+ API_CLIENT,
138
+ ApiService,
139
+ injectApiClient,
140
+ injectApiSession,
141
+ provideApiClient
142
+ };
@@ -0,0 +1,92 @@
1
+ import {
2
+ ApiError
3
+ } from "./chunk-YTM3FV65.js";
4
+
5
+ // src/core/callbacks.ts
6
+ function abortable(operation, signal) {
7
+ return new Promise((resolve, reject) => {
8
+ if (signal.aborted) {
9
+ reject(signal.reason);
10
+ return;
11
+ }
12
+ const abort = () => reject(signal.reason);
13
+ signal.addEventListener("abort", abort, { once: true });
14
+ Promise.resolve().then(() => {
15
+ signal.throwIfAborted();
16
+ return operation();
17
+ }).then(
18
+ (value) => {
19
+ signal.removeEventListener("abort", abort);
20
+ if (signal.aborted) reject(signal.reason);
21
+ else resolve(value);
22
+ },
23
+ (error) => {
24
+ signal.removeEventListener("abort", abort);
25
+ reject(error);
26
+ }
27
+ );
28
+ });
29
+ }
30
+ function invokeCallback(callback) {
31
+ try {
32
+ return callback();
33
+ } catch (cause) {
34
+ throw new ApiError(
35
+ "API callback failed",
36
+ 0,
37
+ {},
38
+ void 0,
39
+ "callback",
40
+ cause
41
+ );
42
+ }
43
+ }
44
+ async function invokeAsyncCallback(callback) {
45
+ try {
46
+ await callback();
47
+ } catch (cause) {
48
+ throw new ApiError(
49
+ "API callback failed",
50
+ 0,
51
+ {},
52
+ void 0,
53
+ "callback",
54
+ cause
55
+ );
56
+ }
57
+ }
58
+
59
+ // src/core/validation.ts
60
+ async function validateResponse(schema, value, status) {
61
+ try {
62
+ let output;
63
+ if (typeof schema === "function") output = await schema(value);
64
+ else if ("~standard" in schema) {
65
+ const result = await schema["~standard"].validate(value);
66
+ if (result.issues) throw result;
67
+ output = result.value;
68
+ } else if (schema.parseAsync) output = await schema.parseAsync(value);
69
+ else output = schema.parse(value);
70
+ if (output === void 0)
71
+ throw new Error(
72
+ "Response schemas must return a validated value; use null for empty responses"
73
+ );
74
+ return output;
75
+ } catch (cause) {
76
+ throw new ApiError(
77
+ "Response validation failed",
78
+ status,
79
+ {},
80
+ void 0,
81
+ "validation",
82
+ cause
83
+ );
84
+ }
85
+ }
86
+
87
+ export {
88
+ abortable,
89
+ invokeCallback,
90
+ invokeAsyncCallback,
91
+ validateResponse
92
+ };