@friggframework/core 2.0.0--canary.683.f45da33.0 → 2.0.0--canary.684.e113124.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/credential/use-cases/credential-operations-for-user.js +110 -33
- package/credential/use-cases/reauthorize-credential-for-user.js +10 -13
- package/management-api/openapi/components.js +1 -0
- package/management-api/openapi/v2-operations.js +3 -0
- package/management-api/v2/dependencies.js +2 -2
- package/management-api/v2/dto.js +3 -0
- package/management-api/v2/handlers/credentials.js +6 -2
- package/modules/scope-policy.js +15 -0
- package/modules/use-cases/authorize-entity-for-user.js +4 -2
- package/modules/use-cases/multi-step-authorization.js +4 -1
- package/package.json +5 -5
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
const Boom = require('@hapi/boom');
|
|
2
|
-
const {
|
|
3
|
-
|
|
2
|
+
const {
|
|
3
|
+
createScopePolicy,
|
|
4
|
+
describeRecord,
|
|
5
|
+
visibilityClauses,
|
|
6
|
+
matchesListFilters,
|
|
7
|
+
SCOPES,
|
|
8
|
+
} = require('../../modules/entity-scope');
|
|
4
9
|
const { assertCanManage } = require('../../modules/use-cases/manage-access');
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
|
-
* Management API v2 credential operations. A credential
|
|
8
|
-
*
|
|
9
|
-
*
|
|
12
|
+
* Management API v2 credential operations (ADR-056 §3.4, §3.6). A credential
|
|
13
|
+
* has no module name and no organization of its own:
|
|
14
|
+
*
|
|
15
|
+
* - its `type` and `entityIds` come from the entities that use it that the
|
|
16
|
+
* caller may see, so the same person's account connected in two
|
|
17
|
+
* organizations (one credential, two entities) lists in each organization
|
|
18
|
+
* with that organization's entity only;
|
|
19
|
+
* - who it belongs to is its OWNER (`credential.userId`), never the entities:
|
|
20
|
+
* a credential an individual entity and an organization entity both point at
|
|
21
|
+
* (possible only through legacy data) is described by whoever owns the
|
|
22
|
+
* credential, so the answer cannot change with the order the entities load;
|
|
23
|
+
* - a credential whose entities are all out of sight (another organization's)
|
|
24
|
+
* is a 404, and one with no entities at all (its entity was deleted) is
|
|
25
|
+
* visible to its owner only, as it was before scoping.
|
|
10
26
|
*/
|
|
11
27
|
|
|
12
28
|
const credentialIdOf = (entity) => {
|
|
@@ -39,31 +55,82 @@ function withEntityUsage(credentials, entities) {
|
|
|
39
55
|
});
|
|
40
56
|
}
|
|
41
57
|
|
|
42
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* `{scope, owner, organizationId, access}` of a credential for this caller, or
|
|
60
|
+
* null when its owner is neither the caller nor the active organization. Built
|
|
61
|
+
* by `describeRecord` over the row a connection by this owner has: the
|
|
62
|
+
* organization of a visible entity, else the one a new entity would get.
|
|
63
|
+
*/
|
|
64
|
+
function credentialTenancy(credential, visibleEntities, ctx) {
|
|
65
|
+
const entityOrg = visibleEntities.find(
|
|
66
|
+
(entity) => entity.organizationId !== undefined && entity.organizationId !== null
|
|
67
|
+
)?.organizationId;
|
|
68
|
+
const organizationId =
|
|
69
|
+
entityOrg ?? (ctx.individualAcross === 'all' ? null : ctx.activeOrgId);
|
|
70
|
+
return describeRecord({ userId: credential.userId, organizationId }, ctx, 'entity');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The entities of `entities` the caller may see, each with its `tenancy`. */
|
|
74
|
+
function visibleOf(entities, ctx) {
|
|
75
|
+
const visible = [];
|
|
76
|
+
for (const entity of entities || []) {
|
|
77
|
+
const tenancy = describeRecord(entity, ctx, 'entity');
|
|
78
|
+
if (tenancy) visible.push({ ...entity, tenancy });
|
|
79
|
+
}
|
|
80
|
+
return visible;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The caller's credentials with their type, the entities of them they may see
|
|
85
|
+
* and `tenancy`. Credentials with no entity at all are listed too, for the
|
|
86
|
+
* person and the active organization that own them.
|
|
87
|
+
*/
|
|
43
88
|
class ListCredentialsForUser {
|
|
44
|
-
constructor({ credentialRepository, moduleRepository }) {
|
|
89
|
+
constructor({ credentialRepository, moduleRepository, scopePolicy }) {
|
|
45
90
|
this.credentialRepository = credentialRepository;
|
|
46
91
|
this.moduleRepository = moduleRepository;
|
|
92
|
+
this.scopePolicy = scopePolicy || createScopePolicy();
|
|
47
93
|
}
|
|
48
94
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
95
|
+
/** @param {{scope?: string, owner?: string}} [filters] */
|
|
96
|
+
async execute(user, filters = {}) {
|
|
97
|
+
const ctx = this.scopePolicy.accessContext(user);
|
|
98
|
+
const owners = [...new Set([ctx.callerId, ctx.activeOrgId].filter(Boolean))];
|
|
99
|
+
const [found, perOwner, owned] = await Promise.all([
|
|
100
|
+
this.moduleRepository.findEntitiesByOwnership(visibilityClauses(ctx, 'entity')),
|
|
101
|
+
Promise.all(owners.map((id) => this.credentialRepository.findCredentialsByUserId(id))),
|
|
102
|
+
// Every entity of those owners, in any organization: only to tell a credential
|
|
103
|
+
// with no entity at all from one used elsewhere.
|
|
104
|
+
Promise.all(owners.map((id) => this.moduleRepository.findEntitiesByUserId(id))),
|
|
54
105
|
]);
|
|
55
|
-
|
|
106
|
+
const visible = visibleOf(found, ctx);
|
|
107
|
+
const usedAnywhere = new Set(owned.flat().map(credentialIdOf).filter(Boolean));
|
|
108
|
+
const listed = [];
|
|
109
|
+
for (const credential of perOwner.flat().filter(Boolean)) {
|
|
110
|
+
const id = String(credential.id);
|
|
111
|
+
const referencing = visible.filter((entity) => credentialIdOf(entity) === id);
|
|
112
|
+
if (referencing.length === 0 && usedAnywhere.has(id)) continue;
|
|
113
|
+
const tenancy = credentialTenancy(credential, referencing, ctx);
|
|
114
|
+
if (!tenancy || !matchesListFilters(tenancy, filters)) continue;
|
|
115
|
+
listed.push({ ...withEntityUsage([credential], referencing)[0], tenancy });
|
|
116
|
+
}
|
|
117
|
+
return listed;
|
|
56
118
|
}
|
|
57
119
|
}
|
|
58
120
|
|
|
59
|
-
/** One credential the caller
|
|
121
|
+
/** One credential the caller may see: see the header. 404 otherwise. */
|
|
60
122
|
class GetCredentialForUserV2 {
|
|
61
|
-
constructor({ credentialRepository, moduleRepository }) {
|
|
123
|
+
constructor({ credentialRepository, moduleRepository, scopePolicy }) {
|
|
62
124
|
this.credentialRepository = credentialRepository;
|
|
63
125
|
this.moduleRepository = moduleRepository;
|
|
126
|
+
this.scopePolicy = scopePolicy || createScopePolicy();
|
|
64
127
|
}
|
|
65
128
|
|
|
66
129
|
async execute(credentialId, user) {
|
|
130
|
+
const notFound = () =>
|
|
131
|
+
Boom.notFound(`Credential ${credentialId} not found`, {
|
|
132
|
+
code: 'CREDENTIAL_NOT_FOUND',
|
|
133
|
+
});
|
|
67
134
|
let credential = null;
|
|
68
135
|
try {
|
|
69
136
|
credential = await this.credentialRepository.findCredentialById(
|
|
@@ -74,26 +141,32 @@ class GetCredentialForUserV2 {
|
|
|
74
141
|
throw error;
|
|
75
142
|
}
|
|
76
143
|
}
|
|
77
|
-
if (!credential
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
);
|
|
85
|
-
|
|
144
|
+
if (!credential) throw notFound();
|
|
145
|
+
const ctx = this.scopePolicy.accessContext(user);
|
|
146
|
+
|
|
147
|
+
const referencing =
|
|
148
|
+
(await this.moduleRepository.findEntities({ credentialId: credential.id })) || [];
|
|
149
|
+
const visible = visibleOf(referencing, ctx);
|
|
150
|
+
if (referencing.length > 0 && visible.length === 0) throw notFound();
|
|
151
|
+
const tenancy = credentialTenancy(credential, visible, ctx);
|
|
152
|
+
if (!tenancy) throw notFound();
|
|
153
|
+
return { ...withEntityUsage([credential], visible)[0], tenancy };
|
|
86
154
|
}
|
|
87
155
|
}
|
|
88
156
|
|
|
89
157
|
/**
|
|
90
|
-
* Deletes a credential the caller
|
|
91
|
-
* their credential unset, so they show as needing re-authorization rather
|
|
158
|
+
* Deletes a credential the caller may manage. The entities that used it stay,
|
|
159
|
+
* with their credential unset, so they show as needing re-authorization rather
|
|
92
160
|
* than disappearing from integrations.
|
|
161
|
+
*
|
|
162
|
+
* Refuses with 409 `CREDENTIAL_SHARED` while an entity the caller cannot see
|
|
163
|
+
* still uses it: one credential row serves the same provider account in every
|
|
164
|
+
* organization, and deleting it from one would break the other. The message
|
|
165
|
+
* says nothing about the other connections (not even how many): remove the
|
|
166
|
+
* entities that use it, and it goes with the last one.
|
|
93
167
|
*/
|
|
94
168
|
class DeleteCredentialForUser {
|
|
95
|
-
constructor({ credentialRepository, moduleRepository, getCredentialForUser
|
|
96
|
-
this.scopePolicy = scopePolicy || DEFAULT_SCOPE_POLICY;
|
|
169
|
+
constructor({ credentialRepository, moduleRepository, getCredentialForUser }) {
|
|
97
170
|
this.credentialRepository = credentialRepository;
|
|
98
171
|
this.moduleRepository = moduleRepository;
|
|
99
172
|
this.getCredentialForUser = getCredentialForUser;
|
|
@@ -104,11 +177,15 @@ class DeleteCredentialForUser {
|
|
|
104
177
|
credentialId,
|
|
105
178
|
user
|
|
106
179
|
);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
180
|
+
assertCanManage(credential.tenancy.access, `credential ${credential.id}`);
|
|
181
|
+
const usedBy =
|
|
182
|
+
(await this.moduleRepository.findEntities({ credentialId: credential.id })) || [];
|
|
183
|
+
if (usedBy.length > credential.entityIds.length) {
|
|
184
|
+
throw Boom.conflict(
|
|
185
|
+
`Credential ${credential.id} is still in use by other connections and cannot be deleted from here`,
|
|
186
|
+
{ code: 'CREDENTIAL_SHARED' }
|
|
187
|
+
);
|
|
188
|
+
}
|
|
112
189
|
for (const entityId of credential.entityIds) {
|
|
113
190
|
await this.moduleRepository.unsetCredential(entityId);
|
|
114
191
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const Boom = require('@hapi/boom');
|
|
2
|
-
const { DEFAULT_SCOPE_POLICY } = require('../../modules/scope-policy');
|
|
3
2
|
const { assertCanManage } = require('../../modules/use-cases/manage-access');
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -19,7 +18,9 @@ async function credentialEntityType(getCredentialForUser, credentialId, user) {
|
|
|
19
18
|
return {
|
|
20
19
|
entityType: credential.type,
|
|
21
20
|
credentialId: String(credential.id),
|
|
22
|
-
|
|
21
|
+
// A re-authorization keeps the scope the connection already has.
|
|
22
|
+
fixedScope: credential.tenancy?.scope,
|
|
23
|
+
access: credential.tenancy?.access,
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -31,14 +32,12 @@ class GetCredentialReauthorization {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
async execute(credentialId, user, { step = 1, sessionId, state } = {}) {
|
|
34
|
-
const {
|
|
35
|
-
this.getCredentialForUser,
|
|
36
|
-
credentialId,
|
|
37
|
-
user
|
|
38
|
-
);
|
|
35
|
+
const { entityType, credentialId: boundCredentialId } =
|
|
36
|
+
await credentialEntityType(this.getCredentialForUser, credentialId, user);
|
|
39
37
|
return this.getAuthorizationStep.execute({
|
|
40
38
|
user,
|
|
41
|
-
|
|
39
|
+
entityType,
|
|
40
|
+
credentialId: boundCredentialId,
|
|
42
41
|
step,
|
|
43
42
|
sessionId,
|
|
44
43
|
state,
|
|
@@ -48,21 +47,19 @@ class GetCredentialReauthorization {
|
|
|
48
47
|
|
|
49
48
|
/** POST /api/v2/credentials/:credentialId/reauthorize */
|
|
50
49
|
class ReauthorizeCredentialForUser {
|
|
51
|
-
constructor({ getCredentialForUser, submitAuthorizationStep
|
|
52
|
-
this.scopePolicy = scopePolicy || DEFAULT_SCOPE_POLICY;
|
|
50
|
+
constructor({ getCredentialForUser, submitAuthorizationStep }) {
|
|
53
51
|
this.getCredentialForUser = getCredentialForUser;
|
|
54
52
|
this.submitAuthorizationStep = submitAuthorizationStep;
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
async execute(credentialId, user, { data, step = 1, sessionId } = {}) {
|
|
58
|
-
const {
|
|
56
|
+
const { access, ...binding } = await credentialEntityType(
|
|
59
57
|
this.getCredentialForUser,
|
|
60
58
|
credentialId,
|
|
61
59
|
user
|
|
62
60
|
);
|
|
63
61
|
// A credential an organization owns: the organization's admins only.
|
|
64
|
-
|
|
65
|
-
if (access !== null) assertCanManage(access, `credential ${credentialId}`);
|
|
62
|
+
assertCanManage(access, `credential ${credentialId}`);
|
|
66
63
|
return this.submitAuthorizationStep.execute({
|
|
67
64
|
user,
|
|
68
65
|
...binding,
|
|
@@ -206,6 +206,7 @@ const SCHEMAS = {
|
|
|
206
206
|
authIsValid: nullable({ type: 'boolean' }),
|
|
207
207
|
entityIds: { type: 'array', items: { type: 'string' } },
|
|
208
208
|
entityCount: { type: 'integer', minimum: 0 },
|
|
209
|
+
...tenancyProperties,
|
|
209
210
|
createdAt: nullable({ type: 'string', format: 'date-time' }),
|
|
210
211
|
updatedAt: nullable({ type: 'string', format: 'date-time' }),
|
|
211
212
|
data: {
|
|
@@ -184,6 +184,9 @@ const V2_OPERATIONS = {
|
|
|
184
184
|
// Credentials
|
|
185
185
|
listCredentials: {
|
|
186
186
|
summary: "List the caller's credentials (masked)",
|
|
187
|
+
description:
|
|
188
|
+
'A credential is listed through the entities that use it that the caller may see, so each organization lists only its own connections; one no entity uses is listed to its owner. Each carries `scope`, `owner`, `organizationId` and `access`, taken from who owns the credential.',
|
|
189
|
+
parameters: listFilters,
|
|
187
190
|
responses: { 200: ok('Credentials', ref('ListCredentialsResponse')), ...errors('Unauthorized') },
|
|
188
191
|
},
|
|
189
192
|
getCredential: {
|
|
@@ -124,6 +124,7 @@ function buildV2Dependencies({ appDefinition, config, entityTypeRegistry }) {
|
|
|
124
124
|
const getCredentialForUser = new credentialOps.GetCredentialForUserV2({
|
|
125
125
|
credentialRepository,
|
|
126
126
|
moduleRepository,
|
|
127
|
+
scopePolicy,
|
|
127
128
|
});
|
|
128
129
|
const getAuthorizationRequirements = new GetAuthorizationRequirements({
|
|
129
130
|
moduleDefinitions,
|
|
@@ -246,13 +247,13 @@ function buildV2Dependencies({ appDefinition, config, entityTypeRegistry }) {
|
|
|
246
247
|
listCredentialsForUser: new credentialOps.ListCredentialsForUser({
|
|
247
248
|
credentialRepository,
|
|
248
249
|
moduleRepository,
|
|
250
|
+
scopePolicy,
|
|
249
251
|
}),
|
|
250
252
|
getCredentialForUser,
|
|
251
253
|
deleteCredentialForUser: new credentialOps.DeleteCredentialForUser({
|
|
252
254
|
credentialRepository,
|
|
253
255
|
moduleRepository,
|
|
254
256
|
getCredentialForUser,
|
|
255
|
-
scopePolicy,
|
|
256
257
|
}),
|
|
257
258
|
getCredentialReauthorization: new GetCredentialReauthorization({
|
|
258
259
|
getCredentialForUser,
|
|
@@ -261,7 +262,6 @@ function buildV2Dependencies({ appDefinition, config, entityTypeRegistry }) {
|
|
|
261
262
|
reauthorizeCredentialForUser: new ReauthorizeCredentialForUser({
|
|
262
263
|
getCredentialForUser,
|
|
263
264
|
submitAuthorizationStep,
|
|
264
|
-
scopePolicy,
|
|
265
265
|
}),
|
|
266
266
|
|
|
267
267
|
// Authorization (multi-step)
|
package/management-api/v2/dto.js
CHANGED
|
@@ -75,6 +75,8 @@ const CREDENTIAL_METADATA = new Set([
|
|
|
75
75
|
'type',
|
|
76
76
|
'entityIds',
|
|
77
77
|
'status',
|
|
78
|
+
// Added by the credential use cases (ADR-056 §3.4); never provider data.
|
|
79
|
+
'tenancy',
|
|
78
80
|
]);
|
|
79
81
|
|
|
80
82
|
/**
|
|
@@ -126,6 +128,7 @@ function maskCredential(credential) {
|
|
|
126
128
|
entityCount: entityIds.length,
|
|
127
129
|
createdAt: toIso(credential.createdAt),
|
|
128
130
|
updatedAt: toIso(credential.updatedAt),
|
|
131
|
+
...tenancyFields(credential.tenancy),
|
|
129
132
|
data,
|
|
130
133
|
};
|
|
131
134
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { maskCredential } = require('../dto');
|
|
2
|
+
const { parseListFilters } = require('../request');
|
|
2
3
|
|
|
3
4
|
/** Management API v2 credential handlers, keyed by operationId. */
|
|
4
5
|
function createCredentialHandlers(useCases) {
|
|
@@ -6,8 +7,11 @@ function createCredentialHandlers(useCases) {
|
|
|
6
7
|
useCases;
|
|
7
8
|
|
|
8
9
|
return {
|
|
9
|
-
async listCredentials(
|
|
10
|
-
const credentials = await listCredentialsForUser.execute(
|
|
10
|
+
async listCredentials(req, res, user) {
|
|
11
|
+
const credentials = await listCredentialsForUser.execute(
|
|
12
|
+
user,
|
|
13
|
+
parseListFilters(req.query)
|
|
14
|
+
);
|
|
11
15
|
res.json({ credentials: credentials.map(maskCredential) });
|
|
12
16
|
},
|
|
13
17
|
|
package/modules/scope-policy.js
CHANGED
|
@@ -69,6 +69,20 @@ function createScopePolicy({ ownership, entityTypeRegistry } = {}) {
|
|
|
69
69
|
};
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* The owner and organization for a scope that is already decided: a
|
|
74
|
+
* re-authorization keeps the scope its connection has, whatever the config
|
|
75
|
+
* says now. The admin gate applies as it does on create.
|
|
76
|
+
*/
|
|
77
|
+
const ownershipForScope = ({ scope, user }) => {
|
|
78
|
+
const ctx = contextFor(user);
|
|
79
|
+
return {
|
|
80
|
+
...resolveOwnerForScope(scope, ctx),
|
|
81
|
+
legacyOrgId: ctx.legacyOrgId,
|
|
82
|
+
source: 'fixed',
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
72
86
|
/** Whether `user` may load this stored entity for use (same clauses as the list). */
|
|
73
87
|
const canUseEntity = (user, entity) =>
|
|
74
88
|
describeRecord(entity, contextFor(user), 'entity') !== null;
|
|
@@ -86,6 +100,7 @@ function createScopePolicy({ ownership, entityTypeRegistry } = {}) {
|
|
|
86
100
|
accessContext: contextFor,
|
|
87
101
|
resolveScope: resolveEntityScope,
|
|
88
102
|
resolveOwnership,
|
|
103
|
+
ownershipForScope,
|
|
89
104
|
canUseEntity,
|
|
90
105
|
});
|
|
91
106
|
}
|
|
@@ -19,9 +19,11 @@ class AuthorizeEntityForUser {
|
|
|
19
19
|
* The scope, owner and organization a new entity of `entityType` gets for
|
|
20
20
|
* this caller. Throws a 400/403 when the request cannot have one.
|
|
21
21
|
*
|
|
22
|
-
* @param {{user: Object, entityType: string, scope?: string}} params
|
|
22
|
+
* @param {{user: Object, entityType: string, scope?: string, fixedScope?: string}} params
|
|
23
|
+
* `fixedScope`: a re-authorization keeps the scope its connection has
|
|
23
24
|
*/
|
|
24
|
-
resolveOwnership({ user, entityType, scope }) {
|
|
25
|
+
resolveOwnership({ user, entityType, scope, fixedScope }) {
|
|
26
|
+
if (fixedScope) return this.scopePolicy.ownershipForScope({ scope: fixedScope, user });
|
|
25
27
|
return this.scopePolicy.resolveOwnership({
|
|
26
28
|
entityType,
|
|
27
29
|
requestScope: scope,
|
|
@@ -166,8 +166,10 @@ class SubmitAuthorizationStep {
|
|
|
166
166
|
* @param {Object} params
|
|
167
167
|
* @param {string} [params.scope] - the scope the caller asks for, from the
|
|
168
168
|
* deciding level's allow list (ADR-056 §3.1). Never `global`.
|
|
169
|
+
* @param {string} [params.fixedScope] - re-authorization keeps the scope the
|
|
170
|
+
* credential already has, whatever the config says now.
|
|
169
171
|
*/
|
|
170
|
-
async execute({ user, entityType, data, step = 1, sessionId, credentialId = null, scope }) {
|
|
172
|
+
async execute({ user, entityType, data, step = 1, sessionId, credentialId = null, scope, fixedScope }) {
|
|
171
173
|
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
172
174
|
throw Boom.badRequest('data must be an object', {
|
|
173
175
|
code: 'VALIDATION_ERROR',
|
|
@@ -183,6 +185,7 @@ class SubmitAuthorizationStep {
|
|
|
183
185
|
user,
|
|
184
186
|
entityType,
|
|
185
187
|
scope,
|
|
188
|
+
fixedScope,
|
|
186
189
|
});
|
|
187
190
|
|
|
188
191
|
if (!isMultiStep(definition)) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.
|
|
4
|
+
"version": "2.0.0--canary.684.e113124.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.588.0",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@friggframework/eslint-config": "2.0.0--canary.
|
|
52
|
-
"@friggframework/prettier-config": "2.0.0--canary.
|
|
53
|
-
"@friggframework/test": "2.0.0--canary.
|
|
51
|
+
"@friggframework/eslint-config": "2.0.0--canary.684.e113124.0",
|
|
52
|
+
"@friggframework/prettier-config": "2.0.0--canary.684.e113124.0",
|
|
53
|
+
"@friggframework/test": "2.0.0--canary.684.e113124.0",
|
|
54
54
|
"@prisma/client": "^6.19.3",
|
|
55
55
|
"@types/lodash": "4.17.15",
|
|
56
56
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
@@ -90,5 +90,5 @@
|
|
|
90
90
|
"publishConfig": {
|
|
91
91
|
"access": "public"
|
|
92
92
|
},
|
|
93
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "e1131240a890bf30cfee08ba3786458c9e2d1135"
|
|
94
94
|
}
|