@absolutejs/sync-pack-utils 0.1.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/README.md +124 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.js +79 -0
- package/dist/index.js.map +10 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# @absolutejs/sync-pack-utils
|
|
2
|
+
|
|
3
|
+
Shared helpers for [`@absolutejs/sync`](https://github.com/absolutejs/sync)
|
|
4
|
+
packs. Each helper closes one repeated pattern that showed up across the six
|
|
5
|
+
official packs (presence, comments, digest, notifications, favorites,
|
|
6
|
+
counters). The goal: make new packs — first- or third-party — cheaper to
|
|
7
|
+
write and consistent with what's already shipped.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add @absolutejs/sync-pack-utils
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## API
|
|
14
|
+
|
|
15
|
+
### Actor resolution
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import {
|
|
19
|
+
defaultGetActorId,
|
|
20
|
+
resolveActor,
|
|
21
|
+
} from '@absolutejs/sync-pack-utils';
|
|
22
|
+
|
|
23
|
+
// (ctx) => ctx.userId — the conventional default.
|
|
24
|
+
const getActorId = config.getActorId ?? defaultGetActorId<MyCtx>();
|
|
25
|
+
|
|
26
|
+
// Inside a mutation handler: throws UnauthorizedError if no actor id.
|
|
27
|
+
// The context string ends up in the error message so logs name the op.
|
|
28
|
+
const actorId = resolveActor(getActorId, ctx, 'mypack:create');
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Permission builders
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import {
|
|
35
|
+
requireRowOwner,
|
|
36
|
+
requireOwnerOrModerator,
|
|
37
|
+
} from '@absolutejs/sync-pack-utils';
|
|
38
|
+
|
|
39
|
+
permissions: {
|
|
40
|
+
[table]: {
|
|
41
|
+
read: ...,
|
|
42
|
+
// Owner-only writes — uses row.actorId by default; override the
|
|
43
|
+
// field name for packs that use authorId, userId, etc.
|
|
44
|
+
insert: requireRowOwner(getActorId, 'actorId'),
|
|
45
|
+
update: requireRowOwner(getActorId, 'actorId'),
|
|
46
|
+
// Owner OR moderator delete. Falls back to store.getById when
|
|
47
|
+
// actions.delete supplied only the row key (the common case).
|
|
48
|
+
delete: requireOwnerOrModerator({
|
|
49
|
+
actorIdField: 'actorId',
|
|
50
|
+
canModerate, // optional
|
|
51
|
+
getActorId,
|
|
52
|
+
store, // { getById }
|
|
53
|
+
}),
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`requireRowOwner` and `requireOwnerOrModerator` are higher-order — call
|
|
59
|
+
them once at pack-build time to receive the per-row predicate the engine
|
|
60
|
+
expects. Both reject when `getActorId(ctx)` is `undefined` (anonymous
|
|
61
|
+
callers can't own a row).
|
|
62
|
+
|
|
63
|
+
### In-memory store
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import {
|
|
67
|
+
createInMemoryStore,
|
|
68
|
+
type InMemoryStore,
|
|
69
|
+
} from '@absolutejs/sync-pack-utils';
|
|
70
|
+
|
|
71
|
+
type FavoriteRow = { id: string; actorId: string; /* ... */ };
|
|
72
|
+
|
|
73
|
+
const store: InMemoryStore<FavoriteRow> =
|
|
74
|
+
config.store ?? createInMemoryStore<FavoriteRow>();
|
|
75
|
+
|
|
76
|
+
engine.registerPack(defineSyncPack({
|
|
77
|
+
// ...
|
|
78
|
+
readers: { favorites: store.reader },
|
|
79
|
+
writers: { favorites: store.writer },
|
|
80
|
+
// store.getById is available for permission + mutation handler use.
|
|
81
|
+
}));
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`createInMemoryStore<Row>()` returns:
|
|
85
|
+
|
|
86
|
+
- `reader: TableReader<CollectionContext>` — `all()` returns `[...rows.values()]`
|
|
87
|
+
- `writer: TableWriter<Row>` — upsert-by-id; `delete` removes by `row.id`
|
|
88
|
+
- `getById(id)` — point lookup
|
|
89
|
+
- `rows: Map<string, Row>` — direct access (treat as read-only)
|
|
90
|
+
|
|
91
|
+
Every official pack uses this as its default backing store and exposes a
|
|
92
|
+
`store?: ...` config field so consumers can swap in a Postgres / Drizzle /
|
|
93
|
+
Redis implementation when they need persistence.
|
|
94
|
+
|
|
95
|
+
## What's intentionally not here
|
|
96
|
+
|
|
97
|
+
- **`prefixed(prefix, ...)`**: just use template literals.
|
|
98
|
+
``${prefix}<my-collection>`` is fine.
|
|
99
|
+
- **`defineActorPack(...)`**: a Convex-style abstraction that wraps
|
|
100
|
+
`defineSyncPack` with permission defaults. Decided against — it'd hide
|
|
101
|
+
the engine surface, which is the thing pack authors learn first.
|
|
102
|
+
- **Validators / Zod adapters**: out of scope; sync's `field` helper +
|
|
103
|
+
schema is the validation layer.
|
|
104
|
+
|
|
105
|
+
## Pairing with `@absolutejs/sync/testing`
|
|
106
|
+
|
|
107
|
+
Pack tests typically pair with `@absolutejs/sync/testing` (added in sync
|
|
108
|
+
1.9.2):
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { expectRejection } from '@absolutejs/sync/testing';
|
|
112
|
+
import { resolveActor } from '@absolutejs/sync-pack-utils';
|
|
113
|
+
|
|
114
|
+
const error = await expectRejection(() => {
|
|
115
|
+
resolveActor(getActorId, {}, 'mypack:do');
|
|
116
|
+
return Promise.resolve();
|
|
117
|
+
});
|
|
118
|
+
expect(error).toBeInstanceOf(UnauthorizedError);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Versioning
|
|
122
|
+
|
|
123
|
+
This package stays 0.x indefinitely while the ecosystem settles. When the
|
|
124
|
+
six official packs are stable, the helpers will follow.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@absolutejs/sync-pack-utils` — shared helpers extracted from the six
|
|
3
|
+
* official `@absolutejs/sync` packs.
|
|
4
|
+
*
|
|
5
|
+
* Each helper closes one repeated pattern. The goal is to make new packs
|
|
6
|
+
* (first- and third-party) cheaper to write and stop drift from the
|
|
7
|
+
* standard shapes already shipped by presence / comments / digest /
|
|
8
|
+
* notifications / favorites / counters.
|
|
9
|
+
*/
|
|
10
|
+
import { type CollectionContext, type TableReader, type TableWriter } from '@absolutejs/sync/engine';
|
|
11
|
+
/**
|
|
12
|
+
* The conventional default — `(ctx) => ctx.userId`. Use as the fallback when
|
|
13
|
+
* a pack's config doesn't supply its own `getActorId`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const getActorId = config.getActorId ?? defaultGetActorId<MyCtx>();
|
|
17
|
+
*/
|
|
18
|
+
export declare const defaultGetActorId: <Ctx = CollectionContext>() => ((ctx: Ctx) => string | undefined);
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the caller's actor id from a ctx, or throw {@link UnauthorizedError}
|
|
21
|
+
* with a descriptive message. Use inside mutation handlers that require an
|
|
22
|
+
* actor; the message embeds your `context` string so error reports name the
|
|
23
|
+
* pack and operation.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const actorId = resolveActor(getActorId, ctx, 'comments:create');
|
|
27
|
+
*/
|
|
28
|
+
export declare const resolveActor: <Ctx = CollectionContext>(getActorId: (ctx: Ctx) => string | undefined, ctx: unknown, context: string) => string;
|
|
29
|
+
/**
|
|
30
|
+
* Permission validator that requires `row[actorIdField] === getActorId(ctx)`.
|
|
31
|
+
* Use for `insert` and `update` on rows the actor owns; the handler stamps
|
|
32
|
+
* the actor on the row, so this is the canonical row-ownership check.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* permissions: {
|
|
36
|
+
* notifications: {
|
|
37
|
+
* insert: requireRowOwner(getActorId, 'actorId'),
|
|
38
|
+
* update: requireRowOwner(getActorId, 'actorId'),
|
|
39
|
+
* },
|
|
40
|
+
* },
|
|
41
|
+
*/
|
|
42
|
+
export declare const requireRowOwner: <Ctx = CollectionContext>(getActorId: (ctx: Ctx) => string | undefined, actorIdField?: string) => (ctx: unknown, row: unknown) => boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Permission validator for delete (or any op) that accepts the row OR
|
|
45
|
+
* just its id. Falls back to `store.getById(row.id)` when the row's actor
|
|
46
|
+
* field isn't on the supplied subject — sync's engine passes only the
|
|
47
|
+
* key to `actions.delete({ id })`, so this pattern is needed for every
|
|
48
|
+
* owner-gated delete.
|
|
49
|
+
*
|
|
50
|
+
* Returns true when the row's owner matches the caller OR `canModerate(ctx)`
|
|
51
|
+
* is `true`.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* permissions: {
|
|
55
|
+
* notifications: {
|
|
56
|
+
* delete: requireOwnerOrModerator({
|
|
57
|
+
* getActorId,
|
|
58
|
+
* canModerate,
|
|
59
|
+
* store, // { getById }
|
|
60
|
+
* actorIdField: 'actorId',
|
|
61
|
+
* }),
|
|
62
|
+
* },
|
|
63
|
+
* },
|
|
64
|
+
*/
|
|
65
|
+
export declare const requireOwnerOrModerator: <Ctx = CollectionContext>(options: {
|
|
66
|
+
getActorId: (ctx: Ctx) => string | undefined;
|
|
67
|
+
canModerate?: (ctx: Ctx) => boolean;
|
|
68
|
+
store: {
|
|
69
|
+
getById: (id: string) => unknown;
|
|
70
|
+
};
|
|
71
|
+
actorIdField?: string;
|
|
72
|
+
}) => (ctx: unknown, row: unknown) => boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Standard in-memory store for a pack table. Every row needs an `id: string`
|
|
75
|
+
* (the table's primary key); the writer is upsert-by-id. Used by every
|
|
76
|
+
* official pack as the default backing store.
|
|
77
|
+
*/
|
|
78
|
+
export type InMemoryStore<Row extends {
|
|
79
|
+
id: string;
|
|
80
|
+
}> = {
|
|
81
|
+
reader: TableReader<CollectionContext>;
|
|
82
|
+
writer: TableWriter<Row, CollectionContext, unknown>;
|
|
83
|
+
/** Lookup by id — convenient for permission and mutation handlers. */
|
|
84
|
+
getById: (id: string) => Row | undefined;
|
|
85
|
+
/** Direct read of the underlying Map for advanced use; treat as read-only. */
|
|
86
|
+
rows: Map<string, Row>;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Build a fresh, isolated in-memory store. Each call gets its own Map, so
|
|
90
|
+
* two pack instances on the same engine don't share state.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* const store = config.store ?? createInMemoryStore<NotificationRow>();
|
|
94
|
+
*/
|
|
95
|
+
export declare const createInMemoryStore: <Row extends {
|
|
96
|
+
id: string;
|
|
97
|
+
}>() => InMemoryStore<Row>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/index.ts
|
|
3
|
+
import {
|
|
4
|
+
UnauthorizedError
|
|
5
|
+
} from "@absolutejs/sync/engine";
|
|
6
|
+
var defaultGetActorId = () => (ctx) => ctx.userId;
|
|
7
|
+
var resolveActor = (getActorId, ctx, context) => {
|
|
8
|
+
const actorId = getActorId(ctx);
|
|
9
|
+
if (actorId === undefined || actorId === "") {
|
|
10
|
+
throw new UnauthorizedError(`${context} (no actor id)`);
|
|
11
|
+
}
|
|
12
|
+
return actorId;
|
|
13
|
+
};
|
|
14
|
+
var requireRowOwner = (getActorId, actorIdField = "actorId") => (ctx, row) => {
|
|
15
|
+
const callerId = getActorId(ctx);
|
|
16
|
+
if (callerId === undefined)
|
|
17
|
+
return false;
|
|
18
|
+
const rowActor = row[actorIdField];
|
|
19
|
+
return rowActor === callerId;
|
|
20
|
+
};
|
|
21
|
+
var requireOwnerOrModerator = (options) => (ctx, row) => {
|
|
22
|
+
const {
|
|
23
|
+
getActorId,
|
|
24
|
+
canModerate,
|
|
25
|
+
store,
|
|
26
|
+
actorIdField = "actorId"
|
|
27
|
+
} = options;
|
|
28
|
+
const callerId = getActorId(ctx);
|
|
29
|
+
if (callerId === undefined)
|
|
30
|
+
return false;
|
|
31
|
+
const supplied = row;
|
|
32
|
+
const ownerId = supplied[actorIdField] !== undefined ? supplied[actorIdField] : (() => {
|
|
33
|
+
const id = supplied.id;
|
|
34
|
+
if (typeof id !== "string")
|
|
35
|
+
return;
|
|
36
|
+
const stored = store.getById(id);
|
|
37
|
+
return stored?.[actorIdField];
|
|
38
|
+
})();
|
|
39
|
+
if (ownerId === undefined)
|
|
40
|
+
return false;
|
|
41
|
+
if (ownerId === callerId)
|
|
42
|
+
return true;
|
|
43
|
+
return canModerate !== undefined ? canModerate(ctx) : false;
|
|
44
|
+
};
|
|
45
|
+
var createInMemoryStore = () => {
|
|
46
|
+
const rows = new Map;
|
|
47
|
+
return {
|
|
48
|
+
getById: (id) => rows.get(id),
|
|
49
|
+
reader: {
|
|
50
|
+
all: () => [...rows.values()]
|
|
51
|
+
},
|
|
52
|
+
rows,
|
|
53
|
+
writer: {
|
|
54
|
+
delete: (row) => {
|
|
55
|
+
rows.delete(row.id);
|
|
56
|
+
},
|
|
57
|
+
insert: (data) => {
|
|
58
|
+
rows.set(data.id, data);
|
|
59
|
+
return data;
|
|
60
|
+
},
|
|
61
|
+
update: (data) => {
|
|
62
|
+
const prior = rows.get(data.id);
|
|
63
|
+
const merged = { ...prior ?? {}, ...data };
|
|
64
|
+
rows.set(data.id, merged);
|
|
65
|
+
return merged;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export {
|
|
71
|
+
resolveActor,
|
|
72
|
+
requireRowOwner,
|
|
73
|
+
requireOwnerOrModerator,
|
|
74
|
+
defaultGetActorId,
|
|
75
|
+
createInMemoryStore
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
//# debugId=EA54D19BA095911A64756E2164756E21
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * `@absolutejs/sync-pack-utils` — shared helpers extracted from the six\n * official `@absolutejs/sync` packs.\n *\n * Each helper closes one repeated pattern. The goal is to make new packs\n * (first- and third-party) cheaper to write and stop drift from the\n * standard shapes already shipped by presence / comments / digest /\n * notifications / favorites / counters.\n */\n\nimport {\n\tUnauthorizedError,\n\ttype CollectionContext,\n\ttype TableReader,\n\ttype TableWriter\n} from '@absolutejs/sync/engine';\n\n// ─── Actor resolution ────────────────────────────────────────────────────────\n\n/**\n * The conventional default — `(ctx) => ctx.userId`. Use as the fallback when\n * a pack's config doesn't supply its own `getActorId`.\n *\n * @example\n * const getActorId = config.getActorId ?? defaultGetActorId<MyCtx>();\n */\nexport const defaultGetActorId = <\n\tCtx = CollectionContext\n>(): ((ctx: Ctx) => string | undefined) =>\n\t(ctx) => (ctx as { userId?: string }).userId;\n\n/**\n * Resolve the caller's actor id from a ctx, or throw {@link UnauthorizedError}\n * with a descriptive message. Use inside mutation handlers that require an\n * actor; the message embeds your `context` string so error reports name the\n * pack and operation.\n *\n * @example\n * const actorId = resolveActor(getActorId, ctx, 'comments:create');\n */\nexport const resolveActor = <Ctx = CollectionContext>(\n\tgetActorId: (ctx: Ctx) => string | undefined,\n\tctx: unknown,\n\tcontext: string\n): string => {\n\tconst actorId = getActorId(ctx as Ctx);\n\tif (actorId === undefined || actorId === '') {\n\t\tthrow new UnauthorizedError(`${context} (no actor id)`);\n\t}\n\treturn actorId;\n};\n\n// ─── Permission builders ─────────────────────────────────────────────────────\n\n/**\n * Permission validator that requires `row[actorIdField] === getActorId(ctx)`.\n * Use for `insert` and `update` on rows the actor owns; the handler stamps\n * the actor on the row, so this is the canonical row-ownership check.\n *\n * @example\n * permissions: {\n * notifications: {\n * insert: requireRowOwner(getActorId, 'actorId'),\n * update: requireRowOwner(getActorId, 'actorId'),\n * },\n * },\n */\nexport const requireRowOwner =\n\t<Ctx = CollectionContext>(\n\t\tgetActorId: (ctx: Ctx) => string | undefined,\n\t\tactorIdField: string = 'actorId'\n\t) =>\n\t(ctx: unknown, row: unknown): boolean => {\n\t\tconst callerId = getActorId(ctx as Ctx);\n\t\tif (callerId === undefined) return false;\n\t\tconst rowActor = (row as Record<string, unknown>)[actorIdField];\n\t\treturn rowActor === callerId;\n\t};\n\n/**\n * Permission validator for delete (or any op) that accepts the row OR\n * just its id. Falls back to `store.getById(row.id)` when the row's actor\n * field isn't on the supplied subject — sync's engine passes only the\n * key to `actions.delete({ id })`, so this pattern is needed for every\n * owner-gated delete.\n *\n * Returns true when the row's owner matches the caller OR `canModerate(ctx)`\n * is `true`.\n *\n * @example\n * permissions: {\n * notifications: {\n * delete: requireOwnerOrModerator({\n * getActorId,\n * canModerate,\n * store, // { getById }\n * actorIdField: 'actorId',\n * }),\n * },\n * },\n */\nexport const requireOwnerOrModerator =\n\t<Ctx = CollectionContext>(options: {\n\t\tgetActorId: (ctx: Ctx) => string | undefined;\n\t\tcanModerate?: (ctx: Ctx) => boolean;\n\t\tstore: { getById: (id: string) => unknown };\n\t\tactorIdField?: string;\n\t}) =>\n\t(ctx: unknown, row: unknown): boolean => {\n\t\tconst {\n\t\t\tgetActorId,\n\t\t\tcanModerate,\n\t\t\tstore,\n\t\t\tactorIdField = 'actorId'\n\t\t} = options;\n\t\tconst callerId = getActorId(ctx as Ctx);\n\t\tif (callerId === undefined) return false;\n\t\tconst supplied = row as Record<string, unknown>;\n\t\tconst ownerId =\n\t\t\tsupplied[actorIdField] !== undefined\n\t\t\t\t? supplied[actorIdField]\n\t\t\t\t: (() => {\n\t\t\t\t\t\tconst id = supplied.id;\n\t\t\t\t\t\tif (typeof id !== 'string') return undefined;\n\t\t\t\t\t\tconst stored = store.getById(id) as\n\t\t\t\t\t\t\t| Record<string, unknown>\n\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\treturn stored?.[actorIdField];\n\t\t\t\t\t})();\n\t\tif (ownerId === undefined) return false;\n\t\tif (ownerId === callerId) return true;\n\t\treturn canModerate !== undefined ? canModerate(ctx as Ctx) : false;\n\t};\n\n// ─── In-memory store ────────────────────────────────────────────────────────\n\n/**\n * Standard in-memory store for a pack table. Every row needs an `id: string`\n * (the table's primary key); the writer is upsert-by-id. Used by every\n * official pack as the default backing store.\n */\nexport type InMemoryStore<Row extends { id: string }> = {\n\treader: TableReader<CollectionContext>;\n\twriter: TableWriter<Row, CollectionContext, unknown>;\n\t/** Lookup by id — convenient for permission and mutation handlers. */\n\tgetById: (id: string) => Row | undefined;\n\t/** Direct read of the underlying Map for advanced use; treat as read-only. */\n\trows: Map<string, Row>;\n};\n\n/**\n * Build a fresh, isolated in-memory store. Each call gets its own Map, so\n * two pack instances on the same engine don't share state.\n *\n * @example\n * const store = config.store ?? createInMemoryStore<NotificationRow>();\n */\nexport const createInMemoryStore = <\n\tRow extends { id: string }\n>(): InMemoryStore<Row> => {\n\tconst rows = new Map<string, Row>();\n\treturn {\n\t\tgetById: (id) => rows.get(id),\n\t\treader: {\n\t\t\tall: () => [...rows.values()]\n\t\t},\n\t\trows,\n\t\twriter: {\n\t\t\tdelete: (row) => {\n\t\t\t\trows.delete((row as { id: string }).id);\n\t\t\t},\n\t\t\tinsert: (data) => {\n\t\t\t\trows.set(data.id, data);\n\t\t\t\treturn data;\n\t\t\t},\n\t\t\tupdate: (data) => {\n\t\t\t\tconst prior = rows.get(data.id);\n\t\t\t\tconst merged = { ...(prior ?? {}), ...data } as Row;\n\t\t\t\trows.set(data.id, merged);\n\t\t\t\treturn merged;\n\t\t\t}\n\t\t}\n\t};\n};\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;AAUA;AAAA;AAAA;AAgBO,IAAM,oBAAoB,MAGhC,CAAC,QAAS,IAA4B;AAWhC,IAAM,eAAe,CAC3B,YACA,KACA,YACY;AAAA,EACZ,MAAM,UAAU,WAAW,GAAU;AAAA,EACrC,IAAI,YAAY,aAAa,YAAY,IAAI;AAAA,IAC5C,MAAM,IAAI,kBAAkB,GAAG,uBAAuB;AAAA,EACvD;AAAA,EACA,OAAO;AAAA;AAkBD,IAAM,kBACZ,CACC,YACA,eAAuB,cAExB,CAAC,KAAc,QAA0B;AAAA,EACxC,MAAM,WAAW,WAAW,GAAU;AAAA,EACtC,IAAI,aAAa;AAAA,IAAW,OAAO;AAAA,EACnC,MAAM,WAAY,IAAgC;AAAA,EAClD,OAAO,aAAa;AAAA;AAyBf,IAAM,0BACZ,CAA0B,YAM1B,CAAC,KAAc,QAA0B;AAAA,EACxC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,MACZ;AAAA,EACJ,MAAM,WAAW,WAAW,GAAU;AAAA,EACtC,IAAI,aAAa;AAAA,IAAW,OAAO;AAAA,EACnC,MAAM,WAAW;AAAA,EACjB,MAAM,UACL,SAAS,kBAAkB,YACxB,SAAS,iBACR,MAAM;AAAA,IACP,MAAM,KAAK,SAAS;AAAA,IACpB,IAAI,OAAO,OAAO;AAAA,MAAU;AAAA,IAC5B,MAAM,SAAS,MAAM,QAAQ,EAAE;AAAA,IAG/B,OAAO,SAAS;AAAA,KACd;AAAA,EACN,IAAI,YAAY;AAAA,IAAW,OAAO;AAAA,EAClC,IAAI,YAAY;AAAA,IAAU,OAAO;AAAA,EACjC,OAAO,gBAAgB,YAAY,YAAY,GAAU,IAAI;AAAA;AA0BxD,IAAM,sBAAsB,MAER;AAAA,EAC1B,MAAM,OAAO,IAAI;AAAA,EACjB,OAAO;AAAA,IACN,SAAS,CAAC,OAAO,KAAK,IAAI,EAAE;AAAA,IAC5B,QAAQ;AAAA,MACP,KAAK,MAAM,CAAC,GAAG,KAAK,OAAO,CAAC;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,MACP,QAAQ,CAAC,QAAQ;AAAA,QAChB,KAAK,OAAQ,IAAuB,EAAE;AAAA;AAAA,MAEvC,QAAQ,CAAC,SAAS;AAAA,QACjB,KAAK,IAAI,KAAK,IAAI,IAAI;AAAA,QACtB,OAAO;AAAA;AAAA,MAER,QAAQ,CAAC,SAAS;AAAA,QACjB,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;AAAA,QAC9B,MAAM,SAAS,KAAM,SAAS,CAAC,MAAO,KAAK;AAAA,QAC3C,KAAK,IAAI,KAAK,IAAI,MAAM;AAAA,QACxB,OAAO;AAAA;AAAA,IAET;AAAA,EACD;AAAA;",
|
|
8
|
+
"debugId": "EA54D19BA095911A64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@absolutejs/sync-pack-utils",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared helpers for @absolutejs/sync packs — resolveActor, requireRowOwner/Moderator, createInMemoryStore, and other patterns extracted from the official packs",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/absolutejs/sync-packs.git",
|
|
8
|
+
"directory": "utils"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"module": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"license": "CC BY-NC 4.0",
|
|
15
|
+
"author": "Alex Kahn",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"absolutejs",
|
|
21
|
+
"sync",
|
|
22
|
+
"sync-pack",
|
|
23
|
+
"utils",
|
|
24
|
+
"helpers"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "rm -rf dist && bun build src/index.ts --outdir dist --sourcemap --target=bun --external @absolutejs/sync && tsc --project tsconfig.build.json",
|
|
28
|
+
"test": "bun test",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"format": "prettier --write \"./**/*.{ts,json,md}\"",
|
|
31
|
+
"release": "bun run format && bun run typecheck && bun run test && bun run build && bun publish"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@absolutejs/sync": ">= 1.9.2"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@absolutejs/sync": "^1.9.2",
|
|
38
|
+
"@types/bun": "1.3.14",
|
|
39
|
+
"prettier": "3.5.3",
|
|
40
|
+
"typescript": "5.8.3"
|
|
41
|
+
},
|
|
42
|
+
"exports": {
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./dist/index.d.ts",
|
|
45
|
+
"import": "./dist/index.js",
|
|
46
|
+
"default": "./dist/index.js"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"files": ["dist", "README.md"]
|
|
50
|
+
}
|