@flaredev/core 0.12.2 → 0.14.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.
|
@@ -907,6 +907,46 @@ function allowedActions(policy, role) {
|
|
|
907
907
|
};
|
|
908
908
|
}
|
|
909
909
|
|
|
910
|
+
// src/resource/grants.ts
|
|
911
|
+
function isRestricted(policy) {
|
|
912
|
+
return Boolean(policy);
|
|
913
|
+
}
|
|
914
|
+
function withGrants(policy, resource, grants) {
|
|
915
|
+
if (!policy) return void 0;
|
|
916
|
+
const added = {
|
|
917
|
+
read: new Set(policy.read),
|
|
918
|
+
create: new Set(policy.create),
|
|
919
|
+
update: new Set(policy.update),
|
|
920
|
+
delete: new Set(policy.delete)
|
|
921
|
+
};
|
|
922
|
+
let changed = false;
|
|
923
|
+
for (const grant of grants) {
|
|
924
|
+
if (grant.resource !== resource) continue;
|
|
925
|
+
const bucket = added[grant.action];
|
|
926
|
+
if (!bucket || bucket.has(grant.role)) continue;
|
|
927
|
+
bucket.add(grant.role);
|
|
928
|
+
changed = true;
|
|
929
|
+
}
|
|
930
|
+
if (!changed) return policy;
|
|
931
|
+
return {
|
|
932
|
+
...policy,
|
|
933
|
+
read: [...added.read],
|
|
934
|
+
create: [...added.create],
|
|
935
|
+
update: [...added.update],
|
|
936
|
+
delete: [...added.delete]
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
function grantIndex(grants) {
|
|
940
|
+
const index = /* @__PURE__ */ new Map();
|
|
941
|
+
for (const grant of grants) {
|
|
942
|
+
const key = `${grant.resource}.${grant.action}`;
|
|
943
|
+
const roles = index.get(key) ?? /* @__PURE__ */ new Set();
|
|
944
|
+
roles.add(grant.role);
|
|
945
|
+
index.set(key, roles);
|
|
946
|
+
}
|
|
947
|
+
return index;
|
|
948
|
+
}
|
|
949
|
+
|
|
910
950
|
export {
|
|
911
951
|
STRING_FORMATS,
|
|
912
952
|
TEXT_FORMATS,
|
|
@@ -972,5 +1012,8 @@ export {
|
|
|
972
1012
|
definePolicy,
|
|
973
1013
|
can,
|
|
974
1014
|
ownershipFilter,
|
|
975
|
-
allowedActions
|
|
1015
|
+
allowedActions,
|
|
1016
|
+
isRestricted,
|
|
1017
|
+
withGrants,
|
|
1018
|
+
grantIndex
|
|
976
1019
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { R as Rate, b as RateLimitConfig, a as RateLimitDecision, c as RateLimitStore, d as RateLimitedAction, e as RateSyntaxError, f as fixedWindow, p as parseRate, r as rateFor, g as rateLimitKey, h as ratesIn } from './rate-limit-ClbdZioJ.js';
|
|
2
|
-
import { F as Field, C as CreateInput, U as UpdateInput, R as Resource, S as StoredField } from './policy-
|
|
3
|
-
export { B as BelongsToField,
|
|
2
|
+
import { F as Field, C as CreateInput, U as UpdateInput, R as Resource, S as StoredField, f as PolicyAction, b as Policy } from './policy-eVpUpYxV.js';
|
|
3
|
+
export { B as BelongsToField, g as BooleanField, h as ClientResource, D as DEFAULT_FILE_MAX_BYTES, i as DateField, j as DateTimeField, E as EnumField, k as FILE_CATEGORIES, l as FieldCondition, m as FieldKind, n as FieldValue, o as FileCategory, q as FileField, r as FloatField, H as HasManyField, I as ISSUE_CODES, s as IntField, c as IssueCode, J as JsonField, t as JsonOptions, M as MultiSelectField, N as NUMBER_FORMATS, u as NumberFormat, d as PROBLEM_CODES, v as PolicyConfig, x as PolicyError, y as PolicyOwnership, e as ProblemBody, P as ProblemCode, a as ProblemIssue, z as RESERVED_FIELD_NAMES, A as RecordOf, G as ResourceConfig, K as ResourceDefinitionError, L as STRING_FORMATS, O as StringField, Q as StringFormat, T as TEXT_FORMATS, V as TagsField, W as TagsOptions, X as TextField, Y as TextFormat, Z as allowedActions, _ as can, $ as clientResource, a0 as columnName, a1 as conditionHolds, a2 as defaultFieldLabel, a3 as definePolicy, a4 as defineResource, a5 as describeCondition, a6 as field, a7 as fileMaxBytes, a8 as mimeTypesFor, a9 as ownershipFilter, p as problemResponse, aa as storedFields, w as wantsJson } from './policy-eVpUpYxV.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -591,6 +591,49 @@ declare const isSlug: (value: string) => boolean;
|
|
|
591
591
|
/** "My First Post!" → "my-first-post". */
|
|
592
592
|
declare function slugify(value: string): string;
|
|
593
593
|
|
|
594
|
+
/**
|
|
595
|
+
* Permissions granted from the dashboard, on top of the policies in your code.
|
|
596
|
+
*
|
|
597
|
+
* Flare's policies are files — `policies/invoice.policy.ts` — and that is deliberate:
|
|
598
|
+
* who may do what is reviewable in a pull request, travels with the repository, and is
|
|
599
|
+
* the same on every machine before anything is deployed. Managing roles from a running
|
|
600
|
+
* app means permissions in a database, and a database is none of those things.
|
|
601
|
+
*
|
|
602
|
+
* So the two compose rather than compete. **The policy file is the floor and the
|
|
603
|
+
* database only ever widens it.** A grant adds a role to an action; nothing in the
|
|
604
|
+
* dashboard can take away access the code gives, and nothing in the dashboard can make
|
|
605
|
+
* a resource restricted that the code left open. That last point matters more than it
|
|
606
|
+
* sounds — see {@link withGrants}.
|
|
607
|
+
*/
|
|
608
|
+
/** One row of "this role may do this to this resource". */
|
|
609
|
+
interface PermissionGrant {
|
|
610
|
+
role: string;
|
|
611
|
+
/** The resource's descriptor name, e.g. "Invoice". */
|
|
612
|
+
resource: string;
|
|
613
|
+
/** "list" is read, so it is not a grant of its own. */
|
|
614
|
+
action: Exclude<PolicyAction, "list">;
|
|
615
|
+
}
|
|
616
|
+
/** Whether a resource is restricted at all — i.e. whether granting on it does anything. */
|
|
617
|
+
declare function isRestricted(policy: Policy | undefined | null): boolean;
|
|
618
|
+
/**
|
|
619
|
+
* A resource's policy with dashboard grants folded in.
|
|
620
|
+
*
|
|
621
|
+
* Returns `undefined` unchanged when there is no policy file, and that is the whole
|
|
622
|
+
* subtlety of this feature: a resource with no policy is open to every signed-in user,
|
|
623
|
+
* so a grant on it would be a tick-box that changes nothing. Pretending otherwise — by
|
|
624
|
+
* inventing a policy from the grants — would be worse than useless: an app would start
|
|
625
|
+
* refusing people the moment somebody opened the roles screen, and the reason would be
|
|
626
|
+
* in a table nobody reads. The UI's job is to say "this resource is open; restrict it
|
|
627
|
+
* with `flare gen policy`", and this function's job is to not lie.
|
|
628
|
+
*/
|
|
629
|
+
declare function withGrants(policy: Policy | undefined | null, resource: string, grants: Iterable<PermissionGrant>): Policy | undefined;
|
|
630
|
+
/**
|
|
631
|
+
* Every (resource, action) a role is granted, as a lookup the UI can tick boxes from.
|
|
632
|
+
*
|
|
633
|
+
* Keyed `"Resource.action"` because that is what a matrix cell is.
|
|
634
|
+
*/
|
|
635
|
+
declare function grantIndex(grants: Iterable<PermissionGrant>): Map<string, Set<string>>;
|
|
636
|
+
|
|
594
637
|
/**
|
|
595
638
|
* Sample data for seeds. Small on purpose: a handful of word lists and a seeded
|
|
596
639
|
* random number generator, so a million rows cost nothing to produce and the same
|
|
@@ -742,6 +785,6 @@ type SeedUser = (user: SeedUserInput) => Promise<CredentialUserRows["user"]>;
|
|
|
742
785
|
type Seed = (context: SeedContext) => void | Promise<void>;
|
|
743
786
|
declare function defineSeed(seed: Seed): Seed;
|
|
744
787
|
|
|
745
|
-
declare const FLARE_VERSION = "0.
|
|
788
|
+
declare const FLARE_VERSION = "0.14.0";
|
|
746
789
|
|
|
747
|
-
export { AUTH_USER, type BelongsToRelation, type Country, CreateInput, type CredentialUserRows, DEFAULT_MONEY_EXPONENT, type EnumTranslation, FLARE_VERSION, type Fake, Field, type FormValues, type FormatOptions, type HasManyRelation, type InsertMany, type MailMessage, type MailResult, type Mailer, type MailerOptions, PBKDF2_ITERATIONS, type ReadUrlOptions, RelationError, type RelationGraph, Resource, type ResourceRelations, type ResourceValidators, SNIFF_BYTES, SUBSCRIPTION_STATUSES, type Seed, type SeedContext, type SeedUser, type SeedUserInput, type Storage, type StorageBucket, type StorageObjectBody, type StorageOptions, StoredField, type SubscriptionLike, type SubscriptionState, type SubscriptionStatus, type Tone, type TransactionalEmail, UpdateInput, type UploadUrlOptions, camelCase, checkoutPaid, countries, countryName, createFake, createMailer, createObjectKey, createStorage, createValidators, credentialUserRows, currentPeriodEnd, defaultAuthUserOnDelete, defineSeed, enumMemberCollision, enumTranslations, fake, fieldSchema, fileKeyPrefix, flagEmoji, formValuesToInput, formatPhone, formatValue, fromMinorUnits, grantsAccess, hasTooManyPlaces, hashPassword, humanize, importSigningKey, initialFormValues, isAuthUserTarget, isColor, isCountryCode, isDomain, isLiveSubscription, isPhoneNumber, isSlug, issuesByField, kebabCase, matchesContentType, moneyExponent, normalizeDomain, optionLabel, parseMultiValue, pascalCase, pluralize, prismaEnumMember, randomLetters, relationGraph, renderTransactionalEmail, shouldApplySubscription, signToken, slugify, snakeCase, sniffMatches, splitPhone, statusTone, subscriptionPriceId, subscriptionState, toE164, toMinorUnits, toSubscriptionStatus, verifyPassword, verifyToken, words };
|
|
790
|
+
export { AUTH_USER, type BelongsToRelation, type Country, CreateInput, type CredentialUserRows, DEFAULT_MONEY_EXPONENT, type EnumTranslation, FLARE_VERSION, type Fake, Field, type FormValues, type FormatOptions, type HasManyRelation, type InsertMany, type MailMessage, type MailResult, type Mailer, type MailerOptions, PBKDF2_ITERATIONS, type PermissionGrant, Policy, PolicyAction, type ReadUrlOptions, RelationError, type RelationGraph, Resource, type ResourceRelations, type ResourceValidators, SNIFF_BYTES, SUBSCRIPTION_STATUSES, type Seed, type SeedContext, type SeedUser, type SeedUserInput, type Storage, type StorageBucket, type StorageObjectBody, type StorageOptions, StoredField, type SubscriptionLike, type SubscriptionState, type SubscriptionStatus, type Tone, type TransactionalEmail, UpdateInput, type UploadUrlOptions, camelCase, checkoutPaid, countries, countryName, createFake, createMailer, createObjectKey, createStorage, createValidators, credentialUserRows, currentPeriodEnd, defaultAuthUserOnDelete, defineSeed, enumMemberCollision, enumTranslations, fake, fieldSchema, fileKeyPrefix, flagEmoji, formValuesToInput, formatPhone, formatValue, fromMinorUnits, grantIndex, grantsAccess, hasTooManyPlaces, hashPassword, humanize, importSigningKey, initialFormValues, isAuthUserTarget, isColor, isCountryCode, isDomain, isLiveSubscription, isPhoneNumber, isRestricted, isSlug, issuesByField, kebabCase, matchesContentType, moneyExponent, normalizeDomain, optionLabel, parseMultiValue, pascalCase, pluralize, prismaEnumMember, randomLetters, relationGraph, renderTransactionalEmail, shouldApplySubscription, signToken, slugify, snakeCase, sniffMatches, splitPhone, statusTone, subscriptionPriceId, subscriptionState, toE164, toMinorUnits, toSubscriptionStatus, verifyPassword, verifyToken, withGrants, words };
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
formatPhone,
|
|
36
36
|
formatValue,
|
|
37
37
|
fromMinorUnits,
|
|
38
|
+
grantIndex,
|
|
38
39
|
hasTooManyPlaces,
|
|
39
40
|
humanize,
|
|
40
41
|
initialFormValues,
|
|
@@ -43,6 +44,7 @@ import {
|
|
|
43
44
|
isCountryCode,
|
|
44
45
|
isDomain,
|
|
45
46
|
isPhoneNumber,
|
|
47
|
+
isRestricted,
|
|
46
48
|
isSlug,
|
|
47
49
|
issuesByField,
|
|
48
50
|
kebabCase,
|
|
@@ -63,8 +65,9 @@ import {
|
|
|
63
65
|
storedFields,
|
|
64
66
|
toE164,
|
|
65
67
|
toMinorUnits,
|
|
68
|
+
withGrants,
|
|
66
69
|
words
|
|
67
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-QEK4KWKL.js";
|
|
68
71
|
import {
|
|
69
72
|
ISSUE_CODES,
|
|
70
73
|
PROBLEM_CODES,
|
|
@@ -892,7 +895,7 @@ function createFake(seed = 20260101) {
|
|
|
892
895
|
var fake = createFake();
|
|
893
896
|
|
|
894
897
|
// src/index.ts
|
|
895
|
-
var FLARE_VERSION = "0.
|
|
898
|
+
var FLARE_VERSION = "0.14.0";
|
|
896
899
|
export {
|
|
897
900
|
AUTH_USER,
|
|
898
901
|
DEFAULT_FILE_MAX_BYTES,
|
|
@@ -947,6 +950,7 @@ export {
|
|
|
947
950
|
formatPhone,
|
|
948
951
|
formatValue,
|
|
949
952
|
fromMinorUnits,
|
|
953
|
+
grantIndex,
|
|
950
954
|
grantsAccess,
|
|
951
955
|
hasTooManyPlaces,
|
|
952
956
|
hashPassword,
|
|
@@ -959,6 +963,7 @@ export {
|
|
|
959
963
|
isDomain,
|
|
960
964
|
isLiveSubscription,
|
|
961
965
|
isPhoneNumber,
|
|
966
|
+
isRestricted,
|
|
962
967
|
isSlug,
|
|
963
968
|
issuesByField,
|
|
964
969
|
kebabCase,
|
|
@@ -996,5 +1001,6 @@ export {
|
|
|
996
1001
|
verifyPassword,
|
|
997
1002
|
verifyToken,
|
|
998
1003
|
wantsJson,
|
|
1004
|
+
withGrants,
|
|
999
1005
|
words
|
|
1000
1006
|
};
|
|
@@ -702,4 +702,4 @@ declare function ownershipFilter(policy: Policy | undefined | null, user: {
|
|
|
702
702
|
/** Actions `role` may perform, for hiding UI it can't use. */
|
|
703
703
|
declare function allowedActions(policy: Policy | undefined | null, role: string | null | undefined): Record<Exclude<PolicyAction, "list">, boolean>;
|
|
704
704
|
|
|
705
|
-
export { clientResource as $, type RecordOf as A, type BelongsToField as B, type CreateInput as C, DEFAULT_FILE_MAX_BYTES as D, type EnumField as E, type Field as F, type ResourceConfig as G, type HasManyField as H, ISSUE_CODES as I, type JsonField as J, ResourceDefinitionError as K, STRING_FORMATS as L, type MultiSelectField as M, NUMBER_FORMATS as N, type StringField as O, type ProblemCode as P, type StringFormat as Q, type Resource as R, type StoredField as S, TEXT_FORMATS as T, type UpdateInput as U, type TagsField as V, type TagsOptions as W, type TextField as X, type TextFormat as Y, allowedActions as Z, can as _, type ProblemIssue as a, columnName as a0, conditionHolds as a1, defaultFieldLabel as a2, definePolicy as a3, defineResource as a4, describeCondition as a5, field as a6, fileMaxBytes as a7, mimeTypesFor as a8, ownershipFilter as a9, storedFields as aa, type Policy as b, type IssueCode as c, PROBLEM_CODES as d, type ProblemBody as e, type
|
|
705
|
+
export { clientResource as $, type RecordOf as A, type BelongsToField as B, type CreateInput as C, DEFAULT_FILE_MAX_BYTES as D, type EnumField as E, type Field as F, type ResourceConfig as G, type HasManyField as H, ISSUE_CODES as I, type JsonField as J, ResourceDefinitionError as K, STRING_FORMATS as L, type MultiSelectField as M, NUMBER_FORMATS as N, type StringField as O, type ProblemCode as P, type StringFormat as Q, type Resource as R, type StoredField as S, TEXT_FORMATS as T, type UpdateInput as U, type TagsField as V, type TagsOptions as W, type TextField as X, type TextFormat as Y, allowedActions as Z, can as _, type ProblemIssue as a, columnName as a0, conditionHolds as a1, defaultFieldLabel as a2, definePolicy as a3, defineResource as a4, describeCondition as a5, field as a6, fileMaxBytes as a7, mimeTypesFor as a8, ownershipFilter as a9, storedFields as aa, type Policy as b, type IssueCode as c, PROBLEM_CODES as d, type ProblemBody as e, type PolicyAction as f, type BooleanField as g, type ClientResource as h, type DateField as i, type DateTimeField as j, FILE_CATEGORIES as k, type FieldCondition as l, type FieldKind as m, type FieldValue as n, type FileCategory as o, problemResponse as p, type FileField as q, type FloatField as r, type IntField as s, type JsonOptions as t, type NumberFormat as u, type PolicyConfig as v, wantsJson as w, PolicyError as x, type PolicyOwnership as y, RESERVED_FIELD_NAMES as z };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
|
2
2
|
import { BaseSQLiteDatabase, SQLiteTable, SQLiteColumn } from 'drizzle-orm/sqlite-core';
|
|
3
|
-
import { P as ProblemCode, a as ProblemIssue, R as Resource, F as Field, S as StoredField, b as Policy } from './policy-
|
|
4
|
-
export { I as ISSUE_CODES, c as IssueCode, d as PROBLEM_CODES, e as ProblemBody, p as problemResponse, w as wantsJson } from './policy-
|
|
3
|
+
import { P as ProblemCode, a as ProblemIssue, R as Resource, F as Field, S as StoredField, b as Policy } from './policy-eVpUpYxV.js';
|
|
4
|
+
export { I as ISSUE_CODES, c as IssueCode, d as PROBLEM_CODES, e as ProblemBody, p as problemResponse, w as wantsJson } from './policy-eVpUpYxV.js';
|
|
5
5
|
import './rate-limit-ClbdZioJ.js';
|
|
6
6
|
|
|
7
7
|
/**
|
package/dist/server.js
CHANGED