@lorion-org/provider-selection 1.0.0-beta.1 → 1.0.0-beta.5

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/README.md CHANGED
@@ -3,10 +3,12 @@
3
3
  `@lorion-org/provider-selection` is a small framework-free core for selecting one
4
4
  provider per capability from multiple candidates.
5
5
 
6
- It solves six things:
6
+ It solves these things:
7
7
 
8
8
  - collect provider candidates by capability
9
+ - collect provider-owned defaults from descriptors
9
10
  - collect provider preferences from descriptors or config-like records
11
+ - collect explicit provider preferences from selected provider ids
10
12
  - optionally collect and resolve in one call
11
13
  - pick one provider with configured and fallback preferences
12
14
  - report misconfigured provider selections
@@ -15,19 +17,20 @@ It solves six things:
15
17
  Selection order is always:
16
18
 
17
19
  1. configured provider
18
- 2. fallback provider
19
- 3. first provider in deterministic sort order
20
+ 2. explicitly selected provider
21
+ 3. fallback provider
22
+ 4. first provider in deterministic sort order
20
23
 
21
24
  If a configured provider is set but not present among the candidates, the package
22
25
  does not silently fall back. It reports a mismatch and leaves that capability
23
26
  unselected.
24
27
 
25
- Playground examples in this repository:
28
+ Example descriptors in this repository:
26
29
 
27
- - `packages/nuxt/playground/layer-extensions/payment-provider-stripe/extension.json`
28
- - `packages/nuxt/playground/layer-extensions/payment-provider-invoice/extension.json`
29
- - `packages/react/playground/capabilities/payment-provider-stripe/capability.json`
30
- - `packages/react/playground/capabilities/payment-provider-invoice/capability.json`
30
+ - `examples/nuxt/layer-extensions/payment-provider-stripe/extension.json`
31
+ - `examples/nuxt/layer-extensions/payment-provider-invoice/extension.json`
32
+ - `examples/react-runtime/capabilities/payment-provider-stripe/capability.json`
33
+ - `examples/react-runtime/capabilities/payment-provider-invoice/capability.json`
31
34
 
32
35
  It does not know anything about:
33
36
 
@@ -45,19 +48,77 @@ pnpm add @lorion-org/provider-selection
45
48
 
46
49
  ## Example
47
50
 
51
+ Use provider-owned defaults when a provider descriptor should decide the normal
52
+ provider for a capability:
53
+
54
+ ```ts
55
+ import {
56
+ collectProviderDefaults,
57
+ resolveItemProviderSelection,
58
+ } from '@lorion-org/provider-selection';
59
+
60
+ const descriptors = [
61
+ { id: 'payment-provider-stripe', providesFor: 'checkout', defaultFor: 'checkout' },
62
+ { id: 'payment-provider-invoice', providesFor: 'checkout' },
63
+ ];
64
+
65
+ const fallbackProviders = collectProviderDefaults({
66
+ items: descriptors,
67
+ getDefaultFor: (item) => item.defaultFor,
68
+ getProviderId: (item) => item.id,
69
+ });
70
+
71
+ const result = resolveItemProviderSelection({
72
+ items: descriptors,
73
+ getCapabilityId: (item) => item.providesFor,
74
+ getProviderId: (item) => item.id,
75
+ fallbackProviders,
76
+ });
77
+ ```
78
+
79
+ This selects Stripe with mode `fallback`. `providesFor` and `defaultFor` both
80
+ accept a string or string array, so one provider can serve multiple capabilities.
81
+
82
+ Use explicit selected providers for seed-owned overrides. This is useful when a
83
+ host app lets users select descriptors through a normal feature or profile seed,
84
+ and a selected descriptor is also a provider for a capability:
85
+
86
+ ```ts
87
+ import {
88
+ collectSelectedProviderPreferences,
89
+ resolveItemProviderSelection,
90
+ } from '@lorion-org/provider-selection';
91
+
92
+ const selectedProviders = collectSelectedProviderPreferences({
93
+ items: descriptors,
94
+ getCapabilityId: (descriptor) => descriptor.providesFor,
95
+ getProviderId: (descriptor) => descriptor.id,
96
+ selectedProviderIds: ['payment-provider-invoice'],
97
+ });
98
+
99
+ const result = resolveItemProviderSelection({
100
+ items: descriptors,
101
+ getCapabilityId: (descriptor) => descriptor.providesFor,
102
+ getProviderId: (descriptor) => descriptor.id,
103
+ fallbackProviders,
104
+ selectedProviders,
105
+ });
106
+ ```
107
+
108
+ This selects Invoice with mode `selected`, even though Stripe owns the fallback
109
+ default. Configured providers still have higher priority.
110
+
111
+ Use configured providers for deployment-owned overrides:
112
+
48
113
  ```ts
49
114
  import { resolveItemProviderSelection } from '@lorion-org/provider-selection';
50
115
 
51
116
  const result = resolveItemProviderSelection({
52
- items: [
53
- { providesFor: 'payment-checkout', id: 'payment-provider-stripe' },
54
- { providesFor: 'payment-checkout', id: 'payment-provider-invoice' },
55
- ],
117
+ items: descriptors,
56
118
  getCapabilityId: (item) => item.providesFor,
57
119
  getProviderId: (item) => item.id,
58
- configuredProviders: {
59
- 'payment-checkout': 'payment-provider-stripe',
60
- },
120
+ configuredProviders: { checkout: 'payment-provider-invoice' },
121
+ fallbackProviders,
61
122
  });
62
123
 
63
124
  result.selections;
@@ -74,27 +135,34 @@ import { resolveProviderSelection } from '@lorion-org/provider-selection';
74
135
 
75
136
  const result = resolveProviderSelection({
76
137
  providersByCapability: new Map([
77
- ['payment-checkout', ['payment-provider-invoice', 'payment-provider-stripe']],
138
+ ['checkout', ['payment-provider-invoice', 'payment-provider-stripe']],
78
139
  ]),
79
140
  configuredProviders: {
80
- 'payment-checkout': 'missing-provider',
141
+ checkout: 'missing-provider',
81
142
  },
82
143
  });
83
144
 
84
145
  result.selections;
85
146
  result.mismatches;
86
- // => [{ capabilityId: 'payment-checkout', configuredProviderId: 'missing-provider' }]
147
+ // => [{ capabilityId: 'checkout', configuredProviderId: 'missing-provider' }]
87
148
  ```
88
149
 
89
- If provider preferences are stored on descriptors, collect them before resolving:
150
+ If profile or descriptor preferences are stored on descriptors, collect them as
151
+ fallback preferences before resolving:
90
152
 
91
153
  ```ts
92
154
  import {
155
+ collectProviderDefaults,
93
156
  collectProviderPreferences,
94
157
  resolveItemProviderSelection,
95
158
  } from '@lorion-org/provider-selection';
96
159
 
97
- const configuredProviders = collectProviderPreferences({
160
+ const providerDefaults = collectProviderDefaults({
161
+ items: descriptors,
162
+ getDefaultFor: (descriptor) => descriptor.defaultFor,
163
+ getProviderId: (descriptor) => descriptor.id,
164
+ });
165
+ const descriptorPreferences = collectProviderPreferences({
98
166
  items: descriptors,
99
167
  getProviderPreferences: (descriptor) => descriptor.providerPreferences,
100
168
  });
@@ -103,7 +171,10 @@ const result = resolveItemProviderSelection({
103
171
  items: descriptors,
104
172
  getCapabilityId: (descriptor) => descriptor.providesFor,
105
173
  getProviderId: (descriptor) => descriptor.id,
106
- configuredProviders,
174
+ fallbackProviders: {
175
+ ...providerDefaults,
176
+ ...descriptorPreferences,
177
+ },
107
178
  });
108
179
  ```
109
180
 
@@ -112,9 +183,22 @@ const result = resolveItemProviderSelection({
112
183
  ```ts
113
184
  type CapabilityId = string;
114
185
  type ProviderId = string;
115
- type ProviderSelectionMode = 'configured' | 'fallback' | 'first';
186
+ type ProviderSelectionMode = 'configured' | 'selected' | 'fallback' | 'first';
116
187
  type ProviderPreferenceMap = Partial<Record<CapabilityId, ProviderId>>;
117
188
  type ProvidersByCapability = Map<CapabilityId, ProviderId[]>;
189
+ type ProviderCollectionInput<T> = {
190
+ items: Iterable<T>;
191
+ getCapabilityId: (item: T) => unknown;
192
+ getProviderId: (item: T) => ProviderId;
193
+ };
194
+ type SelectedProviderPreferenceCollectionInput<T> = ProviderCollectionInput<T> & {
195
+ selectedProviderIds: Iterable<ProviderId>;
196
+ };
197
+ type ProviderDefaultCollectionInput<T> = {
198
+ items: Iterable<T>;
199
+ getDefaultFor: (item: T) => unknown;
200
+ getProviderId: (item: T) => ProviderId;
201
+ };
118
202
 
119
203
  type ProviderSelection = {
120
204
  capabilityId: CapabilityId;
@@ -141,9 +225,12 @@ type ItemProviderSelectionResolution = ProviderSelectionResolution & {
141
225
 
142
226
  The package exposes:
143
227
 
228
+ - `collectProviderDefaults()`
144
229
  - `collectProviderPreferences()`
145
230
  - `collectProvidersByCapability()`
231
+ - `collectSelectedProviderPreferences()`
146
232
  - `resolveItemProviderSelection()`
233
+ - `resolveSelectedProviderRelationPreferences()`
147
234
  - `resolveProviderSelection()`
148
235
 
149
236
  ## Local commands
package/dist/index.cjs CHANGED
@@ -20,15 +20,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ collectProviderDefaults: () => collectProviderDefaults,
23
24
  collectProviderPreferences: () => collectProviderPreferences,
24
25
  collectProvidersByCapability: () => collectProvidersByCapability,
26
+ collectSelectedProviderPreferences: () => collectSelectedProviderPreferences,
25
27
  resolveItemProviderSelection: () => resolveItemProviderSelection,
26
- resolveProviderSelection: () => resolveProviderSelection
28
+ resolveProviderSelection: () => resolveProviderSelection,
29
+ resolveSelectedProviderRelationPreferences: () => resolveSelectedProviderRelationPreferences
27
30
  });
28
31
  module.exports = __toCommonJS(index_exports);
29
32
  function toSortedUniqueProviderIds(providerIds) {
30
33
  return Array.from(new Set(Array.from(providerIds).filter(Boolean))).sort();
31
34
  }
35
+ function toCapabilityIds(value) {
36
+ const entries = Array.isArray(value) ? value : [value];
37
+ return entries.filter((entry) => typeof entry === "string" && entry.length > 0);
38
+ }
32
39
  function isRecord(value) {
33
40
  return typeof value === "object" && value !== null && !Array.isArray(value);
34
41
  }
@@ -47,6 +54,13 @@ function getSelectedProvider(input) {
47
54
  }
48
55
  return void 0;
49
56
  }
57
+ const selectedProviderId = input.selectedProviders?.[input.capabilityId];
58
+ if (selectedProviderId && input.candidateProviderIds.includes(selectedProviderId)) {
59
+ return {
60
+ selectedProviderId,
61
+ mode: "selected"
62
+ };
63
+ }
50
64
  const fallbackProviderId = input.fallbackProviders?.[input.capabilityId];
51
65
  if (fallbackProviderId && input.candidateProviderIds.includes(fallbackProviderId)) {
52
66
  return {
@@ -69,7 +83,8 @@ function selectProviders(input) {
69
83
  capabilityId,
70
84
  candidateProviderIds: normalizedCandidateProviderIds,
71
85
  ...input.configuredProviders ? { configuredProviders: input.configuredProviders } : {},
72
- ...input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {}
86
+ ...input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {},
87
+ ...input.selectedProviders ? { selectedProviders: input.selectedProviders } : {}
73
88
  });
74
89
  if (!selected) {
75
90
  continue;
@@ -124,14 +139,13 @@ function getExcludedProviders(selections) {
124
139
  function collectProvidersByCapability(input) {
125
140
  const providersByCapability = /* @__PURE__ */ new Map();
126
141
  for (const item of input.items) {
127
- const capabilityId = input.getCapabilityId(item);
128
- if (!capabilityId) {
129
- continue;
130
- }
131
142
  const providerId = input.getProviderId(item);
132
- const currentProviderIds = providersByCapability.get(capabilityId) ?? [];
133
- currentProviderIds.push(providerId);
134
- providersByCapability.set(capabilityId, toSortedUniqueProviderIds(currentProviderIds));
143
+ const capabilityIds = toCapabilityIds(input.getCapabilityId(item));
144
+ for (const capabilityId of capabilityIds) {
145
+ const currentProviderIds = providersByCapability.get(capabilityId) ?? [];
146
+ currentProviderIds.push(providerId);
147
+ providersByCapability.set(capabilityId, toSortedUniqueProviderIds(currentProviderIds));
148
+ }
135
149
  }
136
150
  return providersByCapability;
137
151
  }
@@ -151,6 +165,52 @@ function collectProviderPreferences(input) {
151
165
  }
152
166
  return preferences;
153
167
  }
168
+ function normalizeDefaultFor(value) {
169
+ const entries = Array.isArray(value) ? value : [value];
170
+ return entries.filter((entry) => typeof entry === "string" && entry.length > 0);
171
+ }
172
+ function collectProviderDefaults(input) {
173
+ let defaults = {};
174
+ for (const item of input.items) {
175
+ const providerId = input.getProviderId(item);
176
+ const capabilityIds = normalizeDefaultFor(input.getDefaultFor(item));
177
+ defaults = {
178
+ ...defaults,
179
+ ...Object.fromEntries(capabilityIds.map((capabilityId) => [capabilityId, providerId]))
180
+ };
181
+ }
182
+ return defaults;
183
+ }
184
+ function collectSelectedProviderPreferences(input) {
185
+ const selectedProviderIds = new Set(input.selectedProviderIds);
186
+ const selectedItems = Array.from(input.items).filter((item) => selectedProviderIds.has(input.getProviderId(item))).sort((left, right) => input.getProviderId(left).localeCompare(input.getProviderId(right)));
187
+ const preferences = {};
188
+ for (const item of selectedItems) {
189
+ const providerId = input.getProviderId(item);
190
+ for (const capabilityId of toCapabilityIds(input.getCapabilityId(item))) {
191
+ if (!preferences[capabilityId]) {
192
+ preferences[capabilityId] = providerId;
193
+ }
194
+ }
195
+ }
196
+ return preferences;
197
+ }
198
+ function resolveSelectedProviderRelationPreferences(input) {
199
+ const selectedProviders = input.selectedProviders ?? {};
200
+ const selectedCapabilityIds = new Set(Object.keys(selectedProviders));
201
+ const defaultFor = toCapabilityIds(input.defaultFor).filter(
202
+ (capabilityId) => !selectedProviders[capabilityId] || selectedProviders[capabilityId] === input.providerId
203
+ );
204
+ const providerPreferences = Object.fromEntries(
205
+ Object.entries(input.providerPreferences ?? {}).filter(
206
+ ([capabilityId]) => !selectedCapabilityIds.has(capabilityId)
207
+ )
208
+ );
209
+ return {
210
+ ...defaultFor.length ? { defaultFor: Array.isArray(input.defaultFor) ? defaultFor : defaultFor[0] } : {},
211
+ ...Object.keys(providerPreferences).length ? { providerPreferences } : {}
212
+ };
213
+ }
154
214
  function resolveProviderSelection(input) {
155
215
  const selections = selectProviders(input);
156
216
  const mismatches = findConfiguredProviderMismatches(input);
@@ -166,7 +226,8 @@ function resolveItemProviderSelection(input) {
166
226
  const resolution = resolveProviderSelection({
167
227
  providersByCapability,
168
228
  ...input.configuredProviders ? { configuredProviders: input.configuredProviders } : {},
169
- ...input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {}
229
+ ...input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {},
230
+ ...input.selectedProviders ? { selectedProviders: input.selectedProviders } : {}
170
231
  });
171
232
  return {
172
233
  providersByCapability,
@@ -175,8 +236,11 @@ function resolveItemProviderSelection(input) {
175
236
  }
176
237
  // Annotate the CommonJS export names for ESM import in node:
177
238
  0 && (module.exports = {
239
+ collectProviderDefaults,
178
240
  collectProviderPreferences,
179
241
  collectProvidersByCapability,
242
+ collectSelectedProviderPreferences,
180
243
  resolveItemProviderSelection,
181
- resolveProviderSelection
244
+ resolveProviderSelection,
245
+ resolveSelectedProviderRelationPreferences
182
246
  });
package/dist/index.d.cts CHANGED
@@ -1,11 +1,29 @@
1
1
  type CapabilityId = string;
2
2
  type ProviderId = string;
3
- type ProviderSelectionMode = 'configured' | 'fallback' | 'first';
3
+ type ProviderSelectionMode = 'configured' | 'selected' | 'fallback' | 'first';
4
4
  type ProviderPreferenceMap = Partial<Record<CapabilityId, ProviderId>>;
5
5
  type ProviderPreferenceCollectionInput<T> = {
6
6
  items: Iterable<T>;
7
7
  getProviderPreferences: (item: T) => unknown;
8
8
  };
9
+ type ProviderDefaultCollectionInput<T> = {
10
+ items: Iterable<T>;
11
+ getDefaultFor: (item: T) => unknown;
12
+ getProviderId: (item: T) => ProviderId;
13
+ };
14
+ type SelectedProviderPreferenceCollectionInput<T> = ProviderCollectionInput<T> & {
15
+ selectedProviderIds: Iterable<ProviderId>;
16
+ };
17
+ type SelectedProviderRelationPreferenceInput = {
18
+ defaultFor?: CapabilityId | CapabilityId[] | undefined;
19
+ providerId: ProviderId;
20
+ providerPreferences?: ProviderPreferenceMap | undefined;
21
+ selectedProviders?: ProviderPreferenceMap;
22
+ };
23
+ type SelectedProviderRelationPreferences = {
24
+ defaultFor?: CapabilityId | CapabilityId[];
25
+ providerPreferences?: ProviderPreferenceMap;
26
+ };
9
27
  type ProviderSelection = {
10
28
  capabilityId: CapabilityId;
11
29
  selectedProviderId: ProviderId;
@@ -27,21 +45,26 @@ type ItemProviderSelectionResolution = ProviderSelectionResolution & {
27
45
  };
28
46
  type ProviderCollectionInput<T> = {
29
47
  items: Iterable<T>;
30
- getCapabilityId: (item: T) => CapabilityId | undefined;
48
+ getCapabilityId: (item: T) => CapabilityId | CapabilityId[] | undefined;
31
49
  getProviderId: (item: T) => ProviderId;
32
50
  };
33
51
  type ResolveProviderSelectionInput = {
34
52
  providersByCapability: ProvidersByCapability;
35
53
  configuredProviders?: ProviderPreferenceMap;
36
54
  fallbackProviders?: ProviderPreferenceMap;
55
+ selectedProviders?: ProviderPreferenceMap;
37
56
  };
38
57
  type ResolveItemProviderSelectionInput<T> = ProviderCollectionInput<T> & {
39
58
  configuredProviders?: ProviderPreferenceMap;
40
59
  fallbackProviders?: ProviderPreferenceMap;
60
+ selectedProviders?: ProviderPreferenceMap;
41
61
  };
42
62
  declare function collectProvidersByCapability<T>(input: ProviderCollectionInput<T>): ProvidersByCapability;
43
63
  declare function collectProviderPreferences<T>(input: ProviderPreferenceCollectionInput<T>): ProviderPreferenceMap;
64
+ declare function collectProviderDefaults<T>(input: ProviderDefaultCollectionInput<T>): ProviderPreferenceMap;
65
+ declare function collectSelectedProviderPreferences<T>(input: SelectedProviderPreferenceCollectionInput<T>): ProviderPreferenceMap;
66
+ declare function resolveSelectedProviderRelationPreferences(input: SelectedProviderRelationPreferenceInput): SelectedProviderRelationPreferences;
44
67
  declare function resolveProviderSelection(input: ResolveProviderSelectionInput): ProviderSelectionResolution;
45
68
  declare function resolveItemProviderSelection<T>(input: ResolveItemProviderSelectionInput<T>): ItemProviderSelectionResolution;
46
69
 
47
- export { type CapabilityId, type ItemProviderSelectionResolution, type ProviderId, type ProviderMismatch, type ProviderPreferenceCollectionInput, type ProviderPreferenceMap, type ProviderSelection, type ProviderSelectionMode, type ProviderSelectionResolution, type ProvidersByCapability, type ResolveItemProviderSelectionInput, type ResolveProviderSelectionInput, collectProviderPreferences, collectProvidersByCapability, resolveItemProviderSelection, resolveProviderSelection };
70
+ export { type CapabilityId, type ItemProviderSelectionResolution, type ProviderDefaultCollectionInput, type ProviderId, type ProviderMismatch, type ProviderPreferenceCollectionInput, type ProviderPreferenceMap, type ProviderSelection, type ProviderSelectionMode, type ProviderSelectionResolution, type ProvidersByCapability, type ResolveItemProviderSelectionInput, type ResolveProviderSelectionInput, type SelectedProviderPreferenceCollectionInput, type SelectedProviderRelationPreferenceInput, type SelectedProviderRelationPreferences, collectProviderDefaults, collectProviderPreferences, collectProvidersByCapability, collectSelectedProviderPreferences, resolveItemProviderSelection, resolveProviderSelection, resolveSelectedProviderRelationPreferences };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,29 @@
1
1
  type CapabilityId = string;
2
2
  type ProviderId = string;
3
- type ProviderSelectionMode = 'configured' | 'fallback' | 'first';
3
+ type ProviderSelectionMode = 'configured' | 'selected' | 'fallback' | 'first';
4
4
  type ProviderPreferenceMap = Partial<Record<CapabilityId, ProviderId>>;
5
5
  type ProviderPreferenceCollectionInput<T> = {
6
6
  items: Iterable<T>;
7
7
  getProviderPreferences: (item: T) => unknown;
8
8
  };
9
+ type ProviderDefaultCollectionInput<T> = {
10
+ items: Iterable<T>;
11
+ getDefaultFor: (item: T) => unknown;
12
+ getProviderId: (item: T) => ProviderId;
13
+ };
14
+ type SelectedProviderPreferenceCollectionInput<T> = ProviderCollectionInput<T> & {
15
+ selectedProviderIds: Iterable<ProviderId>;
16
+ };
17
+ type SelectedProviderRelationPreferenceInput = {
18
+ defaultFor?: CapabilityId | CapabilityId[] | undefined;
19
+ providerId: ProviderId;
20
+ providerPreferences?: ProviderPreferenceMap | undefined;
21
+ selectedProviders?: ProviderPreferenceMap;
22
+ };
23
+ type SelectedProviderRelationPreferences = {
24
+ defaultFor?: CapabilityId | CapabilityId[];
25
+ providerPreferences?: ProviderPreferenceMap;
26
+ };
9
27
  type ProviderSelection = {
10
28
  capabilityId: CapabilityId;
11
29
  selectedProviderId: ProviderId;
@@ -27,21 +45,26 @@ type ItemProviderSelectionResolution = ProviderSelectionResolution & {
27
45
  };
28
46
  type ProviderCollectionInput<T> = {
29
47
  items: Iterable<T>;
30
- getCapabilityId: (item: T) => CapabilityId | undefined;
48
+ getCapabilityId: (item: T) => CapabilityId | CapabilityId[] | undefined;
31
49
  getProviderId: (item: T) => ProviderId;
32
50
  };
33
51
  type ResolveProviderSelectionInput = {
34
52
  providersByCapability: ProvidersByCapability;
35
53
  configuredProviders?: ProviderPreferenceMap;
36
54
  fallbackProviders?: ProviderPreferenceMap;
55
+ selectedProviders?: ProviderPreferenceMap;
37
56
  };
38
57
  type ResolveItemProviderSelectionInput<T> = ProviderCollectionInput<T> & {
39
58
  configuredProviders?: ProviderPreferenceMap;
40
59
  fallbackProviders?: ProviderPreferenceMap;
60
+ selectedProviders?: ProviderPreferenceMap;
41
61
  };
42
62
  declare function collectProvidersByCapability<T>(input: ProviderCollectionInput<T>): ProvidersByCapability;
43
63
  declare function collectProviderPreferences<T>(input: ProviderPreferenceCollectionInput<T>): ProviderPreferenceMap;
64
+ declare function collectProviderDefaults<T>(input: ProviderDefaultCollectionInput<T>): ProviderPreferenceMap;
65
+ declare function collectSelectedProviderPreferences<T>(input: SelectedProviderPreferenceCollectionInput<T>): ProviderPreferenceMap;
66
+ declare function resolveSelectedProviderRelationPreferences(input: SelectedProviderRelationPreferenceInput): SelectedProviderRelationPreferences;
44
67
  declare function resolveProviderSelection(input: ResolveProviderSelectionInput): ProviderSelectionResolution;
45
68
  declare function resolveItemProviderSelection<T>(input: ResolveItemProviderSelectionInput<T>): ItemProviderSelectionResolution;
46
69
 
47
- export { type CapabilityId, type ItemProviderSelectionResolution, type ProviderId, type ProviderMismatch, type ProviderPreferenceCollectionInput, type ProviderPreferenceMap, type ProviderSelection, type ProviderSelectionMode, type ProviderSelectionResolution, type ProvidersByCapability, type ResolveItemProviderSelectionInput, type ResolveProviderSelectionInput, collectProviderPreferences, collectProvidersByCapability, resolveItemProviderSelection, resolveProviderSelection };
70
+ export { type CapabilityId, type ItemProviderSelectionResolution, type ProviderDefaultCollectionInput, type ProviderId, type ProviderMismatch, type ProviderPreferenceCollectionInput, type ProviderPreferenceMap, type ProviderSelection, type ProviderSelectionMode, type ProviderSelectionResolution, type ProvidersByCapability, type ResolveItemProviderSelectionInput, type ResolveProviderSelectionInput, type SelectedProviderPreferenceCollectionInput, type SelectedProviderRelationPreferenceInput, type SelectedProviderRelationPreferences, collectProviderDefaults, collectProviderPreferences, collectProvidersByCapability, collectSelectedProviderPreferences, resolveItemProviderSelection, resolveProviderSelection, resolveSelectedProviderRelationPreferences };
package/dist/index.js CHANGED
@@ -2,6 +2,10 @@
2
2
  function toSortedUniqueProviderIds(providerIds) {
3
3
  return Array.from(new Set(Array.from(providerIds).filter(Boolean))).sort();
4
4
  }
5
+ function toCapabilityIds(value) {
6
+ const entries = Array.isArray(value) ? value : [value];
7
+ return entries.filter((entry) => typeof entry === "string" && entry.length > 0);
8
+ }
5
9
  function isRecord(value) {
6
10
  return typeof value === "object" && value !== null && !Array.isArray(value);
7
11
  }
@@ -20,6 +24,13 @@ function getSelectedProvider(input) {
20
24
  }
21
25
  return void 0;
22
26
  }
27
+ const selectedProviderId = input.selectedProviders?.[input.capabilityId];
28
+ if (selectedProviderId && input.candidateProviderIds.includes(selectedProviderId)) {
29
+ return {
30
+ selectedProviderId,
31
+ mode: "selected"
32
+ };
33
+ }
23
34
  const fallbackProviderId = input.fallbackProviders?.[input.capabilityId];
24
35
  if (fallbackProviderId && input.candidateProviderIds.includes(fallbackProviderId)) {
25
36
  return {
@@ -42,7 +53,8 @@ function selectProviders(input) {
42
53
  capabilityId,
43
54
  candidateProviderIds: normalizedCandidateProviderIds,
44
55
  ...input.configuredProviders ? { configuredProviders: input.configuredProviders } : {},
45
- ...input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {}
56
+ ...input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {},
57
+ ...input.selectedProviders ? { selectedProviders: input.selectedProviders } : {}
46
58
  });
47
59
  if (!selected) {
48
60
  continue;
@@ -97,14 +109,13 @@ function getExcludedProviders(selections) {
97
109
  function collectProvidersByCapability(input) {
98
110
  const providersByCapability = /* @__PURE__ */ new Map();
99
111
  for (const item of input.items) {
100
- const capabilityId = input.getCapabilityId(item);
101
- if (!capabilityId) {
102
- continue;
103
- }
104
112
  const providerId = input.getProviderId(item);
105
- const currentProviderIds = providersByCapability.get(capabilityId) ?? [];
106
- currentProviderIds.push(providerId);
107
- providersByCapability.set(capabilityId, toSortedUniqueProviderIds(currentProviderIds));
113
+ const capabilityIds = toCapabilityIds(input.getCapabilityId(item));
114
+ for (const capabilityId of capabilityIds) {
115
+ const currentProviderIds = providersByCapability.get(capabilityId) ?? [];
116
+ currentProviderIds.push(providerId);
117
+ providersByCapability.set(capabilityId, toSortedUniqueProviderIds(currentProviderIds));
118
+ }
108
119
  }
109
120
  return providersByCapability;
110
121
  }
@@ -124,6 +135,52 @@ function collectProviderPreferences(input) {
124
135
  }
125
136
  return preferences;
126
137
  }
138
+ function normalizeDefaultFor(value) {
139
+ const entries = Array.isArray(value) ? value : [value];
140
+ return entries.filter((entry) => typeof entry === "string" && entry.length > 0);
141
+ }
142
+ function collectProviderDefaults(input) {
143
+ let defaults = {};
144
+ for (const item of input.items) {
145
+ const providerId = input.getProviderId(item);
146
+ const capabilityIds = normalizeDefaultFor(input.getDefaultFor(item));
147
+ defaults = {
148
+ ...defaults,
149
+ ...Object.fromEntries(capabilityIds.map((capabilityId) => [capabilityId, providerId]))
150
+ };
151
+ }
152
+ return defaults;
153
+ }
154
+ function collectSelectedProviderPreferences(input) {
155
+ const selectedProviderIds = new Set(input.selectedProviderIds);
156
+ const selectedItems = Array.from(input.items).filter((item) => selectedProviderIds.has(input.getProviderId(item))).sort((left, right) => input.getProviderId(left).localeCompare(input.getProviderId(right)));
157
+ const preferences = {};
158
+ for (const item of selectedItems) {
159
+ const providerId = input.getProviderId(item);
160
+ for (const capabilityId of toCapabilityIds(input.getCapabilityId(item))) {
161
+ if (!preferences[capabilityId]) {
162
+ preferences[capabilityId] = providerId;
163
+ }
164
+ }
165
+ }
166
+ return preferences;
167
+ }
168
+ function resolveSelectedProviderRelationPreferences(input) {
169
+ const selectedProviders = input.selectedProviders ?? {};
170
+ const selectedCapabilityIds = new Set(Object.keys(selectedProviders));
171
+ const defaultFor = toCapabilityIds(input.defaultFor).filter(
172
+ (capabilityId) => !selectedProviders[capabilityId] || selectedProviders[capabilityId] === input.providerId
173
+ );
174
+ const providerPreferences = Object.fromEntries(
175
+ Object.entries(input.providerPreferences ?? {}).filter(
176
+ ([capabilityId]) => !selectedCapabilityIds.has(capabilityId)
177
+ )
178
+ );
179
+ return {
180
+ ...defaultFor.length ? { defaultFor: Array.isArray(input.defaultFor) ? defaultFor : defaultFor[0] } : {},
181
+ ...Object.keys(providerPreferences).length ? { providerPreferences } : {}
182
+ };
183
+ }
127
184
  function resolveProviderSelection(input) {
128
185
  const selections = selectProviders(input);
129
186
  const mismatches = findConfiguredProviderMismatches(input);
@@ -139,7 +196,8 @@ function resolveItemProviderSelection(input) {
139
196
  const resolution = resolveProviderSelection({
140
197
  providersByCapability,
141
198
  ...input.configuredProviders ? { configuredProviders: input.configuredProviders } : {},
142
- ...input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {}
199
+ ...input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {},
200
+ ...input.selectedProviders ? { selectedProviders: input.selectedProviders } : {}
143
201
  });
144
202
  return {
145
203
  providersByCapability,
@@ -147,8 +205,11 @@ function resolveItemProviderSelection(input) {
147
205
  };
148
206
  }
149
207
  export {
208
+ collectProviderDefaults,
150
209
  collectProviderPreferences,
151
210
  collectProvidersByCapability,
211
+ collectSelectedProviderPreferences,
152
212
  resolveItemProviderSelection,
153
- resolveProviderSelection
213
+ resolveProviderSelection,
214
+ resolveSelectedProviderRelationPreferences
154
215
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lorion-org/provider-selection",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.5",
4
4
  "description": "Framework-free capability provider selection primitives.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -22,6 +22,10 @@
22
22
  "types": "./dist/index.d.ts",
23
23
  "exports": {
24
24
  ".": {
25
+ "lorion-source": {
26
+ "types": "./src/index.ts",
27
+ "default": "./src/index.ts"
28
+ },
25
29
  "import": {
26
30
  "types": "./dist/index.d.ts",
27
31
  "default": "./dist/index.js"
@@ -34,8 +38,9 @@
34
38
  },
35
39
  "files": [
36
40
  "dist",
37
- "examples",
38
- "LICENSE"
41
+ "LICENSE",
42
+ "src/**/*.ts",
43
+ "!src/**/*.spec.ts"
39
44
  ],
40
45
  "keywords": [
41
46
  "provider",
package/src/index.ts ADDED
@@ -0,0 +1,355 @@
1
+ export type CapabilityId = string;
2
+ export type ProviderId = string;
3
+
4
+ export type ProviderSelectionMode = 'configured' | 'selected' | 'fallback' | 'first';
5
+ export type ProviderPreferenceMap = Partial<Record<CapabilityId, ProviderId>>;
6
+ export type ProviderPreferenceCollectionInput<T> = {
7
+ items: Iterable<T>;
8
+ getProviderPreferences: (item: T) => unknown;
9
+ };
10
+ export type ProviderDefaultCollectionInput<T> = {
11
+ items: Iterable<T>;
12
+ getDefaultFor: (item: T) => unknown;
13
+ getProviderId: (item: T) => ProviderId;
14
+ };
15
+ export type SelectedProviderPreferenceCollectionInput<T> = ProviderCollectionInput<T> & {
16
+ selectedProviderIds: Iterable<ProviderId>;
17
+ };
18
+ export type SelectedProviderRelationPreferenceInput = {
19
+ defaultFor?: CapabilityId | CapabilityId[] | undefined;
20
+ providerId: ProviderId;
21
+ providerPreferences?: ProviderPreferenceMap | undefined;
22
+ selectedProviders?: ProviderPreferenceMap;
23
+ };
24
+
25
+ export type SelectedProviderRelationPreferences = {
26
+ defaultFor?: CapabilityId | CapabilityId[];
27
+ providerPreferences?: ProviderPreferenceMap;
28
+ };
29
+
30
+ export type ProviderSelection = {
31
+ capabilityId: CapabilityId;
32
+ selectedProviderId: ProviderId;
33
+ candidateProviderIds: ProviderId[];
34
+ mode: ProviderSelectionMode;
35
+ };
36
+
37
+ export type ProviderMismatch = {
38
+ capabilityId: CapabilityId;
39
+ configuredProviderId: ProviderId;
40
+ };
41
+
42
+ export type ProvidersByCapability = Map<CapabilityId, ProviderId[]>;
43
+
44
+ export type ProviderSelectionResolution = {
45
+ selections: Map<CapabilityId, ProviderSelection>;
46
+ mismatches: ProviderMismatch[];
47
+ excludedProviderIds: ProviderId[];
48
+ };
49
+ export type ItemProviderSelectionResolution = ProviderSelectionResolution & {
50
+ providersByCapability: ProvidersByCapability;
51
+ };
52
+
53
+ type ProviderCollectionInput<T> = {
54
+ items: Iterable<T>;
55
+ getCapabilityId: (item: T) => CapabilityId | CapabilityId[] | undefined;
56
+ getProviderId: (item: T) => ProviderId;
57
+ };
58
+
59
+ export type ResolveProviderSelectionInput = {
60
+ providersByCapability: ProvidersByCapability;
61
+ configuredProviders?: ProviderPreferenceMap;
62
+ fallbackProviders?: ProviderPreferenceMap;
63
+ selectedProviders?: ProviderPreferenceMap;
64
+ };
65
+
66
+ export type ResolveItemProviderSelectionInput<T> = ProviderCollectionInput<T> & {
67
+ configuredProviders?: ProviderPreferenceMap;
68
+ fallbackProviders?: ProviderPreferenceMap;
69
+ selectedProviders?: ProviderPreferenceMap;
70
+ };
71
+
72
+ function toSortedUniqueProviderIds(providerIds: Iterable<ProviderId>): ProviderId[] {
73
+ return Array.from(new Set(Array.from(providerIds).filter(Boolean))).sort();
74
+ }
75
+
76
+ function toCapabilityIds(value: CapabilityId | CapabilityId[] | undefined): CapabilityId[] {
77
+ const entries = Array.isArray(value) ? value : [value];
78
+
79
+ return entries.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0);
80
+ }
81
+
82
+ function isRecord(value: unknown): value is Record<string, unknown> {
83
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
84
+ }
85
+
86
+ function getSelectedProvider(input: {
87
+ capabilityId: CapabilityId;
88
+ candidateProviderIds: ProviderId[];
89
+ configuredProviders?: ProviderPreferenceMap;
90
+ fallbackProviders?: ProviderPreferenceMap;
91
+ selectedProviders?: ProviderPreferenceMap;
92
+ }): { selectedProviderId: ProviderId; mode: ProviderSelectionMode } | undefined {
93
+ const firstProviderId = input.candidateProviderIds[0];
94
+ if (!firstProviderId) {
95
+ return undefined;
96
+ }
97
+
98
+ const configuredProviderId = input.configuredProviders?.[input.capabilityId];
99
+ if (configuredProviderId) {
100
+ if (input.candidateProviderIds.includes(configuredProviderId)) {
101
+ return {
102
+ selectedProviderId: configuredProviderId,
103
+ mode: 'configured',
104
+ };
105
+ }
106
+
107
+ return undefined;
108
+ }
109
+
110
+ const selectedProviderId = input.selectedProviders?.[input.capabilityId];
111
+ if (selectedProviderId && input.candidateProviderIds.includes(selectedProviderId)) {
112
+ return {
113
+ selectedProviderId,
114
+ mode: 'selected',
115
+ };
116
+ }
117
+
118
+ const fallbackProviderId = input.fallbackProviders?.[input.capabilityId];
119
+ if (fallbackProviderId && input.candidateProviderIds.includes(fallbackProviderId)) {
120
+ return {
121
+ selectedProviderId: fallbackProviderId,
122
+ mode: 'fallback',
123
+ };
124
+ }
125
+
126
+ return {
127
+ selectedProviderId: firstProviderId,
128
+ mode: 'first',
129
+ };
130
+ }
131
+
132
+ function selectProviders(
133
+ input: ResolveProviderSelectionInput,
134
+ ): Map<CapabilityId, ProviderSelection> {
135
+ const selections: Map<CapabilityId, ProviderSelection> = new Map();
136
+
137
+ for (const [capabilityId, candidateProviderIds] of Array.from(
138
+ input.providersByCapability.entries(),
139
+ ).sort(([left], [right]) => left.localeCompare(right))) {
140
+ const normalizedCandidateProviderIds = toSortedUniqueProviderIds(candidateProviderIds);
141
+ const selected = getSelectedProvider({
142
+ capabilityId,
143
+ candidateProviderIds: normalizedCandidateProviderIds,
144
+ ...(input.configuredProviders ? { configuredProviders: input.configuredProviders } : {}),
145
+ ...(input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {}),
146
+ ...(input.selectedProviders ? { selectedProviders: input.selectedProviders } : {}),
147
+ });
148
+
149
+ if (!selected) {
150
+ continue;
151
+ }
152
+
153
+ selections.set(capabilityId, {
154
+ capabilityId,
155
+ selectedProviderId: selected.selectedProviderId,
156
+ candidateProviderIds: normalizedCandidateProviderIds,
157
+ mode: selected.mode,
158
+ });
159
+ }
160
+
161
+ return selections;
162
+ }
163
+
164
+ function findConfiguredProviderMismatches(
165
+ input: ResolveProviderSelectionInput,
166
+ ): ProviderMismatch[] {
167
+ const mismatches: ProviderMismatch[] = [];
168
+
169
+ for (const [capabilityId, configuredProviderId] of Object.entries(
170
+ input.configuredProviders ?? {},
171
+ ).sort(([left], [right]) => left.localeCompare(right))) {
172
+ if (!configuredProviderId) {
173
+ continue;
174
+ }
175
+
176
+ const candidateProviderIds = toSortedUniqueProviderIds(
177
+ input.providersByCapability.get(capabilityId) ?? [],
178
+ );
179
+ if (!candidateProviderIds.length) {
180
+ continue;
181
+ }
182
+
183
+ if (candidateProviderIds.includes(configuredProviderId)) {
184
+ continue;
185
+ }
186
+
187
+ mismatches.push({
188
+ capabilityId,
189
+ configuredProviderId,
190
+ });
191
+ }
192
+
193
+ return mismatches;
194
+ }
195
+
196
+ function getExcludedProviders(selections: Iterable<ProviderSelection>): ProviderId[] {
197
+ const excludedProviderIds: ProviderId[] = [];
198
+
199
+ for (const selection of selections) {
200
+ if (selection.candidateProviderIds.length <= 1) {
201
+ continue;
202
+ }
203
+
204
+ for (const candidateProviderId of selection.candidateProviderIds) {
205
+ if (candidateProviderId !== selection.selectedProviderId) {
206
+ excludedProviderIds.push(candidateProviderId);
207
+ }
208
+ }
209
+ }
210
+
211
+ return toSortedUniqueProviderIds(excludedProviderIds);
212
+ }
213
+
214
+ export function collectProvidersByCapability<T>(
215
+ input: ProviderCollectionInput<T>,
216
+ ): ProvidersByCapability {
217
+ const providersByCapability: ProvidersByCapability = new Map();
218
+
219
+ for (const item of input.items) {
220
+ const providerId = input.getProviderId(item);
221
+ const capabilityIds = toCapabilityIds(input.getCapabilityId(item));
222
+
223
+ for (const capabilityId of capabilityIds) {
224
+ const currentProviderIds = providersByCapability.get(capabilityId) ?? [];
225
+ currentProviderIds.push(providerId);
226
+ providersByCapability.set(capabilityId, toSortedUniqueProviderIds(currentProviderIds));
227
+ }
228
+ }
229
+
230
+ return providersByCapability;
231
+ }
232
+
233
+ export function collectProviderPreferences<T>(
234
+ input: ProviderPreferenceCollectionInput<T>,
235
+ ): ProviderPreferenceMap {
236
+ let preferences: ProviderPreferenceMap = {};
237
+
238
+ for (const item of input.items) {
239
+ const value = input.getProviderPreferences(item);
240
+
241
+ if (!isRecord(value)) continue;
242
+
243
+ preferences = {
244
+ ...preferences,
245
+ ...Object.fromEntries(
246
+ Object.entries(value).filter(
247
+ (entry): entry is [string, string] => typeof entry[1] === 'string' && entry[1].length > 0,
248
+ ),
249
+ ),
250
+ };
251
+ }
252
+
253
+ return preferences;
254
+ }
255
+
256
+ function normalizeDefaultFor(value: unknown): CapabilityId[] {
257
+ const entries = Array.isArray(value) ? value : [value];
258
+
259
+ return entries.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0);
260
+ }
261
+
262
+ export function collectProviderDefaults<T>(
263
+ input: ProviderDefaultCollectionInput<T>,
264
+ ): ProviderPreferenceMap {
265
+ let defaults: ProviderPreferenceMap = {};
266
+
267
+ for (const item of input.items) {
268
+ const providerId = input.getProviderId(item);
269
+ const capabilityIds = normalizeDefaultFor(input.getDefaultFor(item));
270
+
271
+ defaults = {
272
+ ...defaults,
273
+ ...Object.fromEntries(capabilityIds.map((capabilityId) => [capabilityId, providerId])),
274
+ };
275
+ }
276
+
277
+ return defaults;
278
+ }
279
+
280
+ export function collectSelectedProviderPreferences<T>(
281
+ input: SelectedProviderPreferenceCollectionInput<T>,
282
+ ): ProviderPreferenceMap {
283
+ const selectedProviderIds = new Set(input.selectedProviderIds);
284
+ const selectedItems = Array.from(input.items)
285
+ .filter((item) => selectedProviderIds.has(input.getProviderId(item)))
286
+ .sort((left, right) => input.getProviderId(left).localeCompare(input.getProviderId(right)));
287
+ const preferences: ProviderPreferenceMap = {};
288
+
289
+ for (const item of selectedItems) {
290
+ const providerId = input.getProviderId(item);
291
+
292
+ for (const capabilityId of toCapabilityIds(input.getCapabilityId(item))) {
293
+ if (!preferences[capabilityId]) {
294
+ preferences[capabilityId] = providerId;
295
+ }
296
+ }
297
+ }
298
+
299
+ return preferences;
300
+ }
301
+
302
+ export function resolveSelectedProviderRelationPreferences(
303
+ input: SelectedProviderRelationPreferenceInput,
304
+ ): SelectedProviderRelationPreferences {
305
+ const selectedProviders = input.selectedProviders ?? {};
306
+ const selectedCapabilityIds = new Set(Object.keys(selectedProviders));
307
+ const defaultFor = toCapabilityIds(input.defaultFor).filter(
308
+ (capabilityId) =>
309
+ !selectedProviders[capabilityId] || selectedProviders[capabilityId] === input.providerId,
310
+ );
311
+ const providerPreferences = Object.fromEntries(
312
+ Object.entries(input.providerPreferences ?? {}).filter(
313
+ ([capabilityId]) => !selectedCapabilityIds.has(capabilityId),
314
+ ),
315
+ );
316
+
317
+ return {
318
+ ...(defaultFor.length
319
+ ? { defaultFor: Array.isArray(input.defaultFor) ? defaultFor : defaultFor[0] }
320
+ : {}),
321
+ ...(Object.keys(providerPreferences).length ? { providerPreferences } : {}),
322
+ };
323
+ }
324
+
325
+ export function resolveProviderSelection(
326
+ input: ResolveProviderSelectionInput,
327
+ ): ProviderSelectionResolution {
328
+ const selections = selectProviders(input);
329
+ const mismatches = findConfiguredProviderMismatches(input);
330
+ const excludedProviderIds = getExcludedProviders(selections.values());
331
+
332
+ return {
333
+ selections,
334
+ mismatches,
335
+ excludedProviderIds,
336
+ };
337
+ }
338
+
339
+ export function resolveItemProviderSelection<T>(
340
+ input: ResolveItemProviderSelectionInput<T>,
341
+ ): ItemProviderSelectionResolution {
342
+ const providersByCapability = collectProvidersByCapability(input);
343
+
344
+ const resolution = resolveProviderSelection({
345
+ providersByCapability,
346
+ ...(input.configuredProviders ? { configuredProviders: input.configuredProviders } : {}),
347
+ ...(input.fallbackProviders ? { fallbackProviders: input.fallbackProviders } : {}),
348
+ ...(input.selectedProviders ? { selectedProviders: input.selectedProviders } : {}),
349
+ });
350
+
351
+ return {
352
+ providersByCapability,
353
+ ...resolution,
354
+ };
355
+ }
@@ -1,38 +0,0 @@
1
- import { resolveItemProviderSelection } from '@lorion-org/provider-selection';
2
-
3
- type PaymentProviderDescriptor = {
4
- id: string;
5
- providesFor?: string;
6
- };
7
-
8
- const descriptors: PaymentProviderDescriptor[] = [
9
- {
10
- id: 'payment-provider-stripe',
11
- providesFor: 'payment-checkout',
12
- },
13
- {
14
- id: 'payment-provider-invoice',
15
- providesFor: 'payment-checkout',
16
- },
17
- ];
18
-
19
- const result = resolveItemProviderSelection({
20
- items: descriptors,
21
- getCapabilityId: (descriptor) => descriptor.providesFor,
22
- getProviderId: (descriptor) => descriptor.id,
23
- configuredProviders: {
24
- 'payment-checkout': 'payment-provider-stripe',
25
- },
26
- });
27
-
28
- console.log(result.providersByCapability);
29
- // Map { 'payment-checkout' => ['payment-provider-invoice', 'payment-provider-stripe'] }
30
-
31
- console.log(result.selections);
32
- // Map { 'payment-checkout' => { selectedProviderId: 'payment-provider-stripe', mode: 'configured', ... } }
33
-
34
- console.log(result.mismatches);
35
- // []
36
-
37
- console.log(result.excludedProviderIds);
38
- // ['payment-provider-invoice']
@@ -1,42 +0,0 @@
1
- import {
2
- collectProviderPreferences,
3
- resolveItemProviderSelection,
4
- } from '@lorion-org/provider-selection';
5
-
6
- type PlaygroundDescriptor = {
7
- id: string;
8
- providerPreferences?: Record<string, string>;
9
- providesFor?: string;
10
- };
11
-
12
- const descriptors: PlaygroundDescriptor[] = [
13
- {
14
- id: 'web',
15
- providerPreferences: {
16
- 'payment-checkout': 'payment-provider-stripe',
17
- },
18
- },
19
- {
20
- id: 'payment-provider-stripe',
21
- providesFor: 'payment-checkout',
22
- },
23
- {
24
- id: 'payment-provider-invoice',
25
- providesFor: 'payment-checkout',
26
- },
27
- ];
28
-
29
- const configuredProviders = collectProviderPreferences({
30
- items: descriptors,
31
- getProviderPreferences: (descriptor) => descriptor.providerPreferences,
32
- });
33
-
34
- const result = resolveItemProviderSelection({
35
- items: descriptors,
36
- getCapabilityId: (descriptor) => descriptor.providesFor,
37
- getProviderId: (descriptor) => descriptor.id,
38
- configuredProviders,
39
- });
40
-
41
- console.log(Object.fromEntries(result.selections));
42
- // { 'payment-checkout': { selectedProviderId: 'payment-provider-stripe', mode: 'configured', ... } }