@pyric/ui 0.1.0-alpha.16 → 0.1.0-alpha.18
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/rules/components/format.d.ts +0 -10
- package/dist/rules/components/format.d.ts.map +1 -1
- package/dist/rules/components/format.js +63 -17
- package/dist/rules/components/format.js.map +1 -1
- package/dist/storage/storageApi.d.ts +1 -1
- package/dist/storage/storageApi.d.ts.map +1 -1
- package/dist/storage/storageApi.js +2 -1
- package/dist/storage/storageApi.js.map +1 -1
- package/package.json +6 -6
- package/src/rules/components/format.ts +74 -15
- package/src/storage/storageApi.ts +3 -2
|
@@ -22,16 +22,6 @@ export interface RuleLine {
|
|
|
22
22
|
/** A short note for skipped lines, e.g. "not checked, this is an update". */
|
|
23
23
|
note?: string;
|
|
24
24
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Split the rules source into numbered lines and mark each `allow` line
|
|
27
|
-
* with a verdict per the spec:
|
|
28
|
-
* - the deciding rule's line → `deny`
|
|
29
|
-
* - an allow line whose operations don't include the method → `skip`
|
|
30
|
-
* - any other allow line → `allow`
|
|
31
|
-
*
|
|
32
|
-
* Verdicts are matched to source lines via `RuleEvaluation.line` (1-indexed
|
|
33
|
-
* `allow` keyword). Lines without a matching evaluation entry get no verdict.
|
|
34
|
-
*/
|
|
35
25
|
export declare function markRuleLines(rulesSource: string, evaluation: RuleEvaluation[], method: FirestoreMethod): RuleLine[];
|
|
36
26
|
/** Render a trace value the way the mock shows it: JSON-ish, quoted
|
|
37
27
|
* strings, `false`/`true`/`null` bare. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/rules/components/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGhG;kEACkE;AAClE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,EAAE,CASlE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,cAAc,GAAG,SAAS,CAM3F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,cAAc,EAAE,EAC5B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,GACX,MAAM,CAuBR;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/rules/components/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGhG;kEACkE;AAClE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,EAAE,CASlE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,cAAc,GAAG,SAAS,CAM3F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,cAAc,EAAE,EAC5B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,GACX,MAAM,CAuBR;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkED,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,cAAc,EAAE,EAC5B,MAAM,EAAE,eAAe,GACtB,QAAQ,EAAE,CA2CZ;AAED;2CAC2C;AAC3C,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAYlD;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAW3E;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,sEAAsE;IACtE,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB"}
|
|
@@ -60,43 +60,89 @@ export function denialReason(evaluation, method, path) {
|
|
|
60
60
|
* Verdicts are matched to source lines via `RuleEvaluation.line` (1-indexed
|
|
61
61
|
* `allow` keyword). Lines without a matching evaluation entry get no verdict.
|
|
62
62
|
*/
|
|
63
|
+
function parsePyricSourceMapEntries(sourceText) {
|
|
64
|
+
const marker = '// @pyric-source-map:';
|
|
65
|
+
const markerIndex = sourceText.indexOf(marker);
|
|
66
|
+
const hasMarker = markerIndex !== -1;
|
|
67
|
+
if (!hasMarker) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const jsonStart = markerIndex + marker.length;
|
|
71
|
+
const rawJson = sourceText.slice(jsonStart).trim();
|
|
72
|
+
try {
|
|
73
|
+
const parsed = JSON.parse(rawJson);
|
|
74
|
+
const isArrayPayload = Array.isArray(parsed);
|
|
75
|
+
if (isArrayPayload) {
|
|
76
|
+
return parsed;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function stripPyricSourceMap(source) {
|
|
85
|
+
const marker = '// @pyric-source-map:';
|
|
86
|
+
const markerIndex = source.indexOf(marker);
|
|
87
|
+
const hasMarker = markerIndex !== -1;
|
|
88
|
+
if (!hasMarker) {
|
|
89
|
+
return source;
|
|
90
|
+
}
|
|
91
|
+
return source.slice(0, markerIndex).trimEnd();
|
|
92
|
+
}
|
|
93
|
+
function mapAuthoredLineToGenerated(sourceMapEntries, authoredLine) {
|
|
94
|
+
const isMapMissing = sourceMapEntries === null;
|
|
95
|
+
if (isMapMissing) {
|
|
96
|
+
return authoredLine;
|
|
97
|
+
}
|
|
98
|
+
const matchingEntry = sourceMapEntries.find((entry) => entry.authoredLine === authoredLine);
|
|
99
|
+
const hasMatchingEntry = matchingEntry !== undefined;
|
|
100
|
+
if (hasMatchingEntry) {
|
|
101
|
+
return matchingEntry.generatedLine;
|
|
102
|
+
}
|
|
103
|
+
return authoredLine;
|
|
104
|
+
}
|
|
63
105
|
export function markRuleLines(rulesSource, evaluation, method) {
|
|
64
106
|
const deciding = decidingEvaluation(evaluation);
|
|
65
107
|
const ops = methodOperations(method);
|
|
66
|
-
|
|
108
|
+
const sourceMapEntries = parsePyricSourceMapEntries(rulesSource);
|
|
67
109
|
const byLine = new Map();
|
|
68
|
-
const noteByLine = new Map();
|
|
69
110
|
for (const e of evaluation) {
|
|
70
|
-
|
|
111
|
+
const hasLineNumber = e.line != null;
|
|
112
|
+
if (!hasLineNumber)
|
|
71
113
|
continue;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
byLine.set(
|
|
114
|
+
const targetLine = mapAuthoredLineToGenerated(sourceMapEntries, e.line);
|
|
115
|
+
const isDecidingEvaluation = e === deciding;
|
|
116
|
+
if (isDecidingEvaluation) {
|
|
117
|
+
byLine.set(targetLine, 'deny');
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
byLine.set(targetLine, 'allow');
|
|
121
|
+
}
|
|
76
122
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const rawLines = rulesSource.split('\n');
|
|
123
|
+
const cleanSource = stripPyricSourceMap(rulesSource);
|
|
124
|
+
const rawLines = cleanSource.split('\n');
|
|
80
125
|
const allowRe = /^\s*allow\s+([a-z,\s]+?)\s*:/;
|
|
81
126
|
return rawLines.map((text, i) => {
|
|
82
127
|
const number = i + 1;
|
|
83
128
|
const line = { number, text };
|
|
84
129
|
const fromEval = byLine.get(number);
|
|
85
|
-
|
|
130
|
+
const hasEvaluationVerdict = fromEval !== undefined;
|
|
131
|
+
if (hasEvaluationVerdict) {
|
|
86
132
|
line.verdict = fromEval;
|
|
87
133
|
return line;
|
|
88
134
|
}
|
|
89
135
|
const m = allowRe.exec(text);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
136
|
+
const isAllowLine = m !== null;
|
|
137
|
+
if (isAllowLine) {
|
|
138
|
+
const declared = m[1].split(',').map((s) => s.trim()).filter(Boolean);
|
|
139
|
+
const matches = declared.some((op) => ops.includes(op));
|
|
140
|
+
const isOperationMatched = matches;
|
|
141
|
+
if (!isOperationMatched) {
|
|
94
142
|
line.verdict = 'skip';
|
|
95
143
|
line.note = `not checked, this is a ${method}`;
|
|
96
144
|
}
|
|
97
145
|
else {
|
|
98
|
-
// Declared for this method but not in the evaluation trace
|
|
99
|
-
// (e.g. a different match block). Treat as a normal allow line.
|
|
100
146
|
line.verdict = 'allow';
|
|
101
147
|
}
|
|
102
148
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/rules/components/format.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAErE;kEACkE;AAClE,MAAM,UAAU,gBAAgB,CAAC,MAAuB;IACtD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACnC,KAAK,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrC,KAAK,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC1C,KAAK,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC1C,KAAK,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC1C,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAA4B;IAC7D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,qEAAqE;IACrE,8DAA8D;IAC9D,2CAA2C;IAC3C,OAAO,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,UAA4B,EAC5B,MAAuB,EACvB,IAAY;IAEZ,MAAM,QAAQ,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,4BAA4B,MAAM,IAAI,IAAI,yCAAyC,CAAC;IAC7F,CAAC;IACD,IAAI,QAAQ,CAAC,OAAO,KAAK,aAAa,EAAE,CAAC;QACvC,OAAO,CACL,uCAAuC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO;YAC3E,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,qEAAqE,CACtE,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,CACL,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,8BAA8B;YAClE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,6BAA6B,CAC9B,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa;QACjC,CAAC,CAAC,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,kBAAkB,QAAQ,CAAC,aAAa,4BAA4B;QAC1G,CAAC,CAAC,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,sCAAsC,CAAC;IAC/E,OAAO,GAAG,IAAI,8BAA8B,CAAC;AAC/C,CAAC;AAUD;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,WAAmB,EACnB,UAA4B,EAC5B,MAAuB;IAEvB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACrC,
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/rules/components/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ import { type ReactNode } from 'react';
|
|
|
19
19
|
* rules internals and no-ops on a handle without them (worker handles), which is
|
|
20
20
|
* the correct degrade (the worker enforces read rules on `listAll` server-side).
|
|
21
21
|
*/
|
|
22
|
-
export type StorageApi = Pick<typeof import('pyric/storage'), 'ref' | 'listAll' | 'getMetadata' | 'getBlob' | 'uploadBytes' | 'deleteObject'>;
|
|
22
|
+
export type StorageApi = Pick<typeof import('pyric/storage'), 'ref' | 'listAll' | 'getMetadata' | 'getBlob' | 'uploadBytes' | 'uploadBytesResumable' | 'deleteObject'>;
|
|
23
23
|
/** Read the active Storage API bundle (defaults to in-process `pyric/storage`). */
|
|
24
24
|
export declare function useStorageApi(): StorageApi;
|
|
25
25
|
/** Provide a Storage API bundle to the subtree (Studio's worker client). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageApi.d.ts","sourceRoot":"","sources":["../../src/storage/storageApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,UAAU,GAAG,IAAI,CAC3B,cAAc,eAAe,CAAC,EAC9B,KAAK,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,GAAG,aAAa,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"storageApi.d.ts","sourceRoot":"","sources":["../../src/storage/storageApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,UAAU,GAAG,IAAI,CAC3B,cAAc,eAAe,CAAC,EAC9B,KAAK,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,GAAG,aAAa,GAAG,sBAAsB,GAAG,cAAc,CACxG,CAAC;AAcF,mFAAmF;AACnF,wBAAgB,aAAa,IAAI,UAAU,CAE1C;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;CACrB,uFAEA"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createContext, createElement, useContext } from 'react';
|
|
2
|
-
import { ref, listAll, getMetadata, getBlob, uploadBytes, deleteObject } from 'pyric/storage';
|
|
2
|
+
import { ref, listAll, getMetadata, getBlob, uploadBytes, uploadBytesResumable, deleteObject } from 'pyric/storage';
|
|
3
3
|
const inProcessStorageApi = {
|
|
4
4
|
ref,
|
|
5
5
|
listAll,
|
|
6
6
|
getMetadata,
|
|
7
7
|
getBlob,
|
|
8
8
|
uploadBytes,
|
|
9
|
+
uploadBytesResumable,
|
|
9
10
|
deleteObject,
|
|
10
11
|
};
|
|
11
12
|
const StorageApiContext = createContext(inProcessStorageApi);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageApi.js","sourceRoot":"","sources":["../../src/storage/storageApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAkB,MAAM,OAAO,CAAC;AACjF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"storageApi.js","sourceRoot":"","sources":["../../src/storage/storageApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAkB,MAAM,OAAO,CAAC;AACjF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA2BpH,MAAM,mBAAmB,GAAe;IACtC,GAAG;IACH,OAAO;IACP,WAAW;IACX,OAAO;IACP,WAAW;IACX,oBAAoB;IACpB,YAAY;CACb,CAAC;AAEF,MAAM,iBAAiB,GAAG,aAAa,CAAa,mBAAmB,CAAC,CAAC;AAEzE,mFAAmF;AACnF,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACvC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,kBAAkB,CAAC,EACjC,KAAK,EACL,QAAQ,GAIT;IACC,OAAO,aAAa,CAAC,iBAAiB,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,CAAC,CAAC;AACxE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyric/ui",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.18",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"homepage": "https://pyric.dev",
|
|
6
6
|
"repository": {
|
|
@@ -90,10 +90,10 @@
|
|
|
90
90
|
},
|
|
91
91
|
"peerDependencies": {
|
|
92
92
|
"@inbrowser/agent": "0.4.2",
|
|
93
|
-
"react": ">=
|
|
94
|
-
"react-dom": ">=
|
|
93
|
+
"react": ">=18",
|
|
94
|
+
"react-dom": ">=18",
|
|
95
95
|
"firebase": ">=12",
|
|
96
|
-
"pyric": "^0.1.0-alpha.
|
|
96
|
+
"pyric": "^0.1.0-alpha.18"
|
|
97
97
|
},
|
|
98
98
|
"peerDependenciesMeta": {
|
|
99
99
|
"@inbrowser/agent": {
|
|
@@ -109,8 +109,8 @@
|
|
|
109
109
|
"fake-indexeddb": "^6.0.0",
|
|
110
110
|
"firebase": "^12.12.0",
|
|
111
111
|
"jsdom": "^29.1.1",
|
|
112
|
-
"pyric": "^0.1.0-alpha.
|
|
113
|
-
"pyric-admin": "^0.1.0-alpha.
|
|
112
|
+
"pyric": "^0.1.0-alpha.18",
|
|
113
|
+
"pyric-admin": "^0.1.0-alpha.18",
|
|
114
114
|
"react": "^19.0.0",
|
|
115
115
|
"react-dom": "^19.0.0",
|
|
116
116
|
"react-test-renderer": "^19.2.6",
|
|
@@ -80,6 +80,60 @@ export interface RuleLine {
|
|
|
80
80
|
* Verdicts are matched to source lines via `RuleEvaluation.line` (1-indexed
|
|
81
81
|
* `allow` keyword). Lines without a matching evaluation entry get no verdict.
|
|
82
82
|
*/
|
|
83
|
+
function parsePyricSourceMapEntries(sourceText: string): Array<{
|
|
84
|
+
generatedLine: number;
|
|
85
|
+
authoredLine: number;
|
|
86
|
+
authoredCol: number;
|
|
87
|
+
authoredFile: string;
|
|
88
|
+
}> | null {
|
|
89
|
+
const marker = '// @pyric-source-map:';
|
|
90
|
+
const markerIndex = sourceText.indexOf(marker);
|
|
91
|
+
const hasMarker = markerIndex !== -1;
|
|
92
|
+
if (!hasMarker) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const jsonStart = markerIndex + marker.length;
|
|
96
|
+
const rawJson = sourceText.slice(jsonStart).trim();
|
|
97
|
+
try {
|
|
98
|
+
const parsed = JSON.parse(rawJson);
|
|
99
|
+
const isArrayPayload = Array.isArray(parsed);
|
|
100
|
+
if (isArrayPayload) {
|
|
101
|
+
return parsed;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
} catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function stripPyricSourceMap(source: string): string {
|
|
110
|
+
const marker = '// @pyric-source-map:';
|
|
111
|
+
const markerIndex = source.indexOf(marker);
|
|
112
|
+
const hasMarker = markerIndex !== -1;
|
|
113
|
+
if (!hasMarker) {
|
|
114
|
+
return source;
|
|
115
|
+
}
|
|
116
|
+
return source.slice(0, markerIndex).trimEnd();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function mapAuthoredLineToGenerated(
|
|
120
|
+
sourceMapEntries: Array<{ generatedLine: number; authoredLine: number }> | null,
|
|
121
|
+
authoredLine: number,
|
|
122
|
+
): number {
|
|
123
|
+
const isMapMissing = sourceMapEntries === null;
|
|
124
|
+
if (isMapMissing) {
|
|
125
|
+
return authoredLine;
|
|
126
|
+
}
|
|
127
|
+
const matchingEntry = sourceMapEntries.find(
|
|
128
|
+
(entry) => entry.authoredLine === authoredLine,
|
|
129
|
+
);
|
|
130
|
+
const hasMatchingEntry = matchingEntry !== undefined;
|
|
131
|
+
if (hasMatchingEntry) {
|
|
132
|
+
return matchingEntry.generatedLine;
|
|
133
|
+
}
|
|
134
|
+
return authoredLine;
|
|
135
|
+
}
|
|
136
|
+
|
|
83
137
|
export function markRuleLines(
|
|
84
138
|
rulesSource: string,
|
|
85
139
|
evaluation: RuleEvaluation[],
|
|
@@ -87,36 +141,41 @@ export function markRuleLines(
|
|
|
87
141
|
): RuleLine[] {
|
|
88
142
|
const deciding = decidingEvaluation(evaluation);
|
|
89
143
|
const ops = methodOperations(method);
|
|
90
|
-
|
|
144
|
+
const sourceMapEntries = parsePyricSourceMapEntries(rulesSource);
|
|
91
145
|
const byLine = new Map<number, LineVerdict>();
|
|
92
|
-
const noteByLine = new Map<number, string>();
|
|
93
146
|
for (const e of evaluation) {
|
|
94
|
-
|
|
95
|
-
if (
|
|
96
|
-
|
|
147
|
+
const hasLineNumber = e.line != null;
|
|
148
|
+
if (!hasLineNumber) continue;
|
|
149
|
+
const targetLine = mapAuthoredLineToGenerated(sourceMapEntries, e.line!);
|
|
150
|
+
const isDecidingEvaluation = e === deciding;
|
|
151
|
+
if (isDecidingEvaluation) {
|
|
152
|
+
byLine.set(targetLine, 'deny');
|
|
153
|
+
} else {
|
|
154
|
+
byLine.set(targetLine, 'allow');
|
|
155
|
+
}
|
|
97
156
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const rawLines = rulesSource.split('\n');
|
|
157
|
+
const cleanSource = stripPyricSourceMap(rulesSource);
|
|
158
|
+
const rawLines = cleanSource.split('\n');
|
|
101
159
|
const allowRe = /^\s*allow\s+([a-z,\s]+?)\s*:/;
|
|
102
160
|
return rawLines.map((text, i) => {
|
|
103
161
|
const number = i + 1;
|
|
104
162
|
const line: RuleLine = { number, text };
|
|
105
163
|
const fromEval = byLine.get(number);
|
|
106
|
-
|
|
164
|
+
const hasEvaluationVerdict = fromEval !== undefined;
|
|
165
|
+
if (hasEvaluationVerdict) {
|
|
107
166
|
line.verdict = fromEval;
|
|
108
167
|
return line;
|
|
109
168
|
}
|
|
110
169
|
const m = allowRe.exec(text);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
170
|
+
const isAllowLine = m !== null;
|
|
171
|
+
if (isAllowLine) {
|
|
172
|
+
const declared = m[1].split(',').map((s) => s.trim()).filter(Boolean);
|
|
173
|
+
const matches = declared.some((op) => ops.includes(op));
|
|
174
|
+
const isOperationMatched = matches;
|
|
175
|
+
if (!isOperationMatched) {
|
|
115
176
|
line.verdict = 'skip';
|
|
116
177
|
line.note = `not checked, this is a ${method}`;
|
|
117
178
|
} else {
|
|
118
|
-
// Declared for this method but not in the evaluation trace
|
|
119
|
-
// (e.g. a different match block). Treat as a normal allow line.
|
|
120
179
|
line.verdict = 'allow';
|
|
121
180
|
}
|
|
122
181
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, createElement, useContext, type ReactNode } from 'react';
|
|
2
|
-
import { ref, listAll, getMetadata, getBlob, uploadBytes, deleteObject } from 'pyric/storage';
|
|
2
|
+
import { ref, listAll, getMetadata, getBlob, uploadBytes, uploadBytesResumable, deleteObject } from 'pyric/storage';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The modular Storage fns the browse/inspect hooks call, as an INJECTABLE
|
|
@@ -23,7 +23,7 @@ import { ref, listAll, getMetadata, getBlob, uploadBytes, deleteObject } from 'p
|
|
|
23
23
|
*/
|
|
24
24
|
export type StorageApi = Pick<
|
|
25
25
|
typeof import('pyric/storage'),
|
|
26
|
-
'ref' | 'listAll' | 'getMetadata' | 'getBlob' | 'uploadBytes' | 'deleteObject'
|
|
26
|
+
'ref' | 'listAll' | 'getMetadata' | 'getBlob' | 'uploadBytes' | 'uploadBytesResumable' | 'deleteObject'
|
|
27
27
|
>;
|
|
28
28
|
|
|
29
29
|
const inProcessStorageApi: StorageApi = {
|
|
@@ -32,6 +32,7 @@ const inProcessStorageApi: StorageApi = {
|
|
|
32
32
|
getMetadata,
|
|
33
33
|
getBlob,
|
|
34
34
|
uploadBytes,
|
|
35
|
+
uploadBytesResumable,
|
|
35
36
|
deleteObject,
|
|
36
37
|
};
|
|
37
38
|
|